local deprecator = function ()
SU.deprecated("SILE.settings.*", "SILE.settings:*", "0.13.0", "0.15.0")
end
local settings = pl.class()
function settings:_init ()
self.state = {}
self.declarations = {}
self.stateQueue = {}
self.defaults = {}
self.hooks = {}
self:declare({
parameter = "document.parindent",
type = "glue",
default = SILE.types.node.glue("1bs"),
help = "Glue at start of paragraph",
})
self:declare({
parameter = "document.baselineskip",
type = "vglue",
default = SILE.types.node.vglue("1.2em plus 1pt"),
help = "Leading",
})
self:declare({
parameter = "document.lineskip",
type = "vglue",
default = SILE.types.node.vglue("1pt"),
help = "Leading",
})
self:declare({
parameter = "document.parskip",
type = "vglue",
default = SILE.types.node.vglue("0pt plus 1pt"),
help = "Leading",
})
self:declare({
parameter = "document.spaceskip",
type = "length or nil",
default = nil,
help = "The length of a space (if nil, then measured from the font)",
})
self:declare({
parameter = "document.rskip",
type = "glue or nil",
default = nil,
help = "Skip to be added to right side of line",
})
self:declare({
parameter = "document.lskip",
type = "glue or nil",
default = nil,
help = "Skip to be added to left side of line",
})
self:declare({
parameter = "document.zenkakuchar",
default = "あ",
type = "string",
help = "The character measured to determine the length of a zenkaku width (全角幅)",
})
SILE.registerCommand(
"set",
function (options, content)
local makedefault = SU.boolean(options.makedefault, false)
local reset = SU.boolean(options.reset, false)
local value = options.value
if content and (type(content) == "function" or content[1]) then
if makedefault then
SU.warn(
"Are you sure meant to set default settings *and* pass content to ostensibly apply them to temporarily?"
)
end
self:temporarily(function ()
if options.parameter then
local parameter = SU.required(options, "parameter", "\\set command")
self:set(parameter, value, makedefault, reset)
end
SILE.process(content)
end)
else
local parameter = SU.required(options, "parameter", "\\set command")
self:set(parameter, value, makedefault, reset)
end
end,
"Set a SILE parameter <parameter> to value <value> (restoring the value afterwards if <content> is provided)",
nil,
true
)
end
function settings:pushState ()
if not self then
return deprecator()
end
table.insert(self.stateQueue, self.state)
self.state = pl.tablex.copy(self.state)
end
function settings:popState ()
if not self then
return deprecator()
end
local previous = self.state
self.state = table.remove(self.stateQueue)
for parameter, oldvalue in pairs(previous) do
if self.hooks[parameter] then
local newvalue = self.state[parameter]
if oldvalue ~= newvalue then
self:runHooks(parameter, newvalue)
end
end
end
end
function settings:declare (spec)
if not spec then
return deprecator()
end
if spec.name then
SU.deprecated(
"'name' argument of SILE.settings:declare",
"'parameter' argument of SILE.settings:declare",
"0.10.10",
"0.11.0"
)
end
if self.declarations[spec.parameter] then
SU.debug("settings", "Attempt to re-declare setting:", spec.parameter)
return
end
self.declarations[spec.parameter] = spec
self.hooks[spec.parameter] = {}
if spec.hook then
self:registerHook(spec.parameter, spec.hook)
end
self:set(spec.parameter, spec.default, true)
end
function settings:reset ()
if not self then
return deprecator()
end
for k, _ in pairs(self.state) do
self:set(k, self.defaults[k])
end
end
function settings:toplevelState ()
if not self then
return deprecator()
end
if #self.stateQueue ~= 0 then
for parameter, _ in pairs(self.state) do
self.state[parameter] = self.stateQueue[1][parameter] or self.defaults[parameter]
end
end
end
function settings:get (parameter)
if parameter == "current.parindent" then
return SILE.typesetter and SILE.typesetter.state.parindent
end
if not parameter then
return deprecator()
end
if not self.declarations[parameter] then
SU.error("Undefined setting '" .. parameter .. "'")
end
if type(self.state[parameter]) ~= "nil" then
return self.state[parameter]
else
return self.defaults[parameter]
end
end
function settings:set (parameter, value, makedefault, reset)
if parameter == "current.parindent" then
if SILE.typesetter and not SILE.typesetter.state.hmodeOnly then
SILE.typesetter.state.parindent = SU.cast("glue or nil", value)
end
return
end
if type(self) ~= "table" then
return deprecator()
end
if not self.declarations[parameter] then
SU.error("Undefined setting '" .. parameter .. "'")
end
if reset then
if makedefault then
SU.error("Can't set a new default and revert to and old default setting at the same time")
end
value = self.defaults[parameter]
else
value = SU.cast(self.declarations[parameter].type, value)
end
self.state[parameter] = value
if makedefault then
self.defaults[parameter] = value
end
self:runHooks(parameter, value)
end
function settings:registerHook (parameter, func)
table.insert(self.hooks[parameter], func)
end
function settings:runHooks (parameter, value)
if self.hooks[parameter] then
for _, func in ipairs(self.hooks[parameter]) do
SU.debug("classhooks", "Running setting hook for", parameter)
func(value)
end
end
end
function settings:temporarily (func)
if not func then
return deprecator()
end
self:pushState()
func()
self:popState()
end
function settings:wrap ()
if not self then
return deprecator()
end
local clSettings = pl.tablex.copy(self.state)
return function (content)
table.insert(self.stateQueue, self.state)
self.state = clSettings
SILE.process(content)
self:popState()
end
end
return settings