summaryrefslogtreecommitdiff
path: root/support/lyluatex/lyluatex-options.lua
diff options
context:
space:
mode:
Diffstat (limited to 'support/lyluatex/lyluatex-options.lua')
-rw-r--r--support/lyluatex/lyluatex-options.lua266
1 files changed, 0 insertions, 266 deletions
diff --git a/support/lyluatex/lyluatex-options.lua b/support/lyluatex/lyluatex-options.lua
deleted file mode 100644
index 62ec72a3c3..0000000000
--- a/support/lyluatex/lyluatex-options.lua
+++ /dev/null
@@ -1,266 +0,0 @@
--- luacheck: ignore ly warn info log self luatexbase internalversion font fonts tex token kpse status
-local err, warn, info, log = luatexbase.provides_module({
- name = "lyluatex-options",
- version = '1.0f', --LYLUATEX_VERSION
- date = "2019/05/27", --LYLUATEX_DATE
- description = "Module lyluatex-options.",
- author = "The Gregorio Project − (see Contributors.md)",
- copyright = "2015-2019 - jperon and others",
- license = "MIT",
-})
-
---[[
- This module provides functionality to handle package options and make them
- configurable in a fine-grained fashion as
- - package options
- - local options (for individual instances of commands/environments)
- - changed “from here on” within a document.
-
--- ]]
-
-local lib = require(kpse.find_file("lyluatex-lib.lua") or "lyluatex-lib.lua")
-local optlib = {} -- namespace for the returned table
-local Opts = {options = {}} -- Options class
-Opts.__index = function (self, k) return self.options[k] or rawget(Opts, k) end
-setmetatable(Opts, Opts)
-
-
-function Opts:new(opt_prefix, declarations)
---[[
- Declare package options along with their default and
- accepted values. To *some* extent also provide type checking.
- - opt_prefix: the prefix/name by which the lyluatex-options module is
- referenced in the parent LaTeX document (preamble or package).
- This is required to write the code calling optlib.set_option into
- the option declaration.
- - declarations: a definition table stored in the calling module (see below)
- Each entry in the 'declarations' table represents one package option, with each
- value being an array (table with integer indexes instead of keys). For
- details please refer to the manual.
---]]
- local o = setmetatable(
- {
- declarations = declarations,
- options = {}
- },
- self
- )
- local exopt = ''
- for k, v in pairs(declarations) do
- o.options[k] = v[1] or ''
- tex.sprint(string.format([[
-\DeclareOptionX{%s}{\directlua{
- %s:set_option('%s', '\luatexluaescapestring{#1}')
-}}%%
-]],
- k, opt_prefix, k
- ))
- exopt = exopt..k..'='..(v[1] or '')..','
- end
- tex.sprint([[\ExecuteOptionsX{]]..exopt..[[}%%]], [[\ProcessOptionsX]])
- return o
-end
-
-function Opts:check_local_options(opts, ignore_declarations)
---[[
- Parse the given options (options passed to a command/environment),
- sanitize them against the global package options and return a table
- with the local options that should then supersede the global options.
- If ignore_declaration is given any non-false value the sanitization
- step is skipped (i.e. local options are only parsed and duplicates
- rejected).
---]]
- local options = {}
- local next_opt = opts:gmatch('([^,]+)') -- iterator over options
- for opt in next_opt do
- local k, v = opt:match('([^=]+)=?(.*)')
- if k then
- if v and v:sub(1, 1) == '{' then -- handle keys with {multiple, values}
- while select(2, v:gsub('{', '')) ~= select(2, v:gsub('}', '')) do v = v..','..next_opt() end
- v = v:sub(2, -2) -- remove { }
- end
- if not ignore_declarations then
- k, v = self:sanitize_option(k:gsub('^%s', ''), v:gsub('^%s', ''))
- end
- if k then
- if options[k] then err('Option %s is set two times for the same score.', k)
- else options[k] = v
- end
- end
- end
- end
- return options
-end
-
-function Opts:is_neg(k)
---[[
- Type check for a 'negative' option. This is an existing option
- name prefixed with 'no' (e.g. 'noalign')
---]]
- local _, i = k:find('^no')
- return i and lib.contains_key(self.declarations, k:sub(i + 1))
-end
-
-function Opts:sanitize_option(k, v)
---[[
- Check and (if necessary) adjust the value of a given option.
- Reject undefined options
- Check 'negative' options
- Handle boolean options (empty strings or 'false'), set them to real booleans
---]]
- local declarations = self.declarations
- if k == '' or k == 'noarg' then return end
- if not lib.contains_key(declarations, k) then err('Unknown option: '..k) end
- -- aliases
- if declarations[k] and declarations[k][2] == optlib.is_alias then
- if declarations[k][1] == v then return
- else k = declarations[k] end
- end
- -- boolean
- if v == 'false' then v = false end
- -- negation (for example, noindent is the negation of indent)
- if self:is_neg(k) then
- if v ~= nil and v ~= 'default' then
- k = k:gsub('^no(.*)', '%1')
- v = not v
- else return
- end
- end
- return k, v
-end
-
-function Opts:set_option(k, v)
---[[
- Set an option for the given prefix to be in effect from this point on.
- Raises an error if the option is not declared or does not meet the
- declared expectations. (TODO: The latter has to be integrated by extracting
- optlib.validate_option from optlib.validate_options and call it in
- sanitize_option).
---]]
- k, v = self:sanitize_option(k, v)
- if k then
- self.options[k] = v
- self:validate_option(k)
- end
-end
-
-function Opts:validate_option(key, options_obj)
---[[
- Validate an (already sanitized) option against its expected values.
- With options_obj a local options table can be provided,
- otherwise the global options stored in OPTIONS are checked.
---]]
- local package_opts = self.declarations
- local options = options_obj or self.options
- local unexpected
- if options[key] == 'default' then
- -- Replace 'default' with an actual value
- options[key] = package_opts[key][1]
- unexpected = options[key] == nil
- end
- if not lib.contains(package_opts[key], options[key]) and package_opts[key][2] then
- -- option value is not in the array of accepted values
- if type(package_opts[key][2]) == 'function' then package_opts[key][2](key, options[key])
- else unexpected = true
- end
- end
- if unexpected then
- err([[
- Unexpected value "%s" for option %s:
- authorized values are "%s"
- ]],
- options[key], key, table.concat(package_opts[key], ', ')
- )
- end
-end
-
-function Opts:validate_options(options_obj)
---[[
- Validate the given set of options against the option declaration
- table for the given prefix.
- With options_obj a local options table can be provided,
- otherwise the global options stored in OPTIONS are checked.
---]]
- for k, _ in lib.orderedpairs(self.declarations) do
- self:validate_option(k, options_obj)
- end
-end
-
-
-function optlib.is_alias()
---[[
- This function doesn't do anything, but if an option is defined
- as an alias, its second parameter will be this function, so the
- test declarations[k][2] == optlib.is_alias in Opts:sanitize_options
- will return true.
---]]
-end
-
-
-function optlib.is_dim(k, v)
---[[
- Type checking for options that accept a LaTeX dimension.
- This can be
- - a number (integer or float)
- - a number with unit
- - a (multiplied) TeX length
- (see error message in code for examples)
---]]
- if v == '' or v == false or tonumber(v) then return true end
- local n, sl, u = v:match('^%d*%.?%d*'), v:match('\\'), v:match('%a+')
- -- a value of number - backslash - length is a dimension
- -- invalid input will be prevented in by the LaTeX parser already
- if n and sl and u then return true end
- if n and lib.contains(lib.TEX_UNITS, u) then return true end
- err([[
-Unexpected value "%s" for dimension %s:
-should be either a number (for example "12"),
-a number with unit, without space ("12pt"),
-or a (multiplied) TeX length (".8\linewidth")
-]],
- v, k
- )
-end
-
-
-function optlib.is_neg(k, _)
---[[
- Type check for a 'negative' option. At this stage,
- we only check that it begins with 'no'.
---]]
- return k:find('^no')
-end
-
-
-function optlib.is_num(_, v)
---[[
- Type check for number options
---]]
- return v == '' or tonumber(v)
-end
-
-
-function optlib.is_str(_, v)
---[[
- Type check for string options
---]]
- return type(v) == 'string'
-end
-
-
-function optlib.merge_options(base_opt, super_opt)
---[[
- Merge two tables.
- Create a new table as a copy of base_opt, then merge with
- super_opt. Entries in super_opt supersede (i.e. overwrite)
- colliding entries in base_opt.
---]]
- local result = {}
- for k, v in pairs(base_opt) do result[k] = v end
- for k, v in pairs(super_opt) do result[k] = v end
- return result
-end
-
-
-optlib.Opts = Opts
-return optlib