From 6e793bc48a31b373735ca2daacaf4b606e498047 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 13 Jan 2023 22:02:26 +0000 Subject: luakeys (13jan23) git-svn-id: svn://tug.org/texlive/trunk@65533 c570f23f-e606-0410-a88d-b1316a301751 --- .../doc/luatex/luakeys/documentation.tex | 123 +++------ Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf | Bin 427721 -> 425955 bytes .../tex/luatex/luakeys/luakeys-debug.sty | 2 +- Master/texmf-dist/tex/luatex/luakeys/luakeys.lua | 303 ++++++++++++++++----- Master/texmf-dist/tex/luatex/luakeys/luakeys.sty | 2 +- 5 files changed, 267 insertions(+), 163 deletions(-) (limited to 'Master') diff --git a/Master/texmf-dist/doc/luatex/luakeys/documentation.tex b/Master/texmf-dist/doc/luatex/luakeys/documentation.tex index 42da7c1acc3..2e57cbae190 100644 --- a/Master/texmf-dist/doc/luatex/luakeys/documentation.tex +++ b/Master/texmf-dist/doc/luatex/luakeys/documentation.tex @@ -64,7 +64,7 @@ The default value of the option “\texttt{#1}” is: \href{https://github.com/Josef-Friedrich/luakeys} {github.com/Josef-Friedrich/luakeys}% } -\date{v0.12.0 from 2023/01/05} +\date{v0.13.0 from 2023/01/13} \maketitle @@ -273,11 +273,14 @@ and loads the Lua module \texttt{luakeys.lua} into the global variable Luakeys exports only one function that must be called to access the public API. % -% Das Lua-Modul exportiert diese Funktionen und Tabellen: -The Lua module exports this functions and tables: +% Diese Exportfunktion gibt eine Tabelle zurück, die die öffentlichen +% Funktionen und weiteren Tabellen enthält: +This export function returns a table containing the public functions and +additional tables: \InputLua[firstline=3,lastline=16]{export.lua} +\noindent % Das Projekt verwendet einige wenige Abkürzungen für Variablennamen, % die hoffentlich für externe Leser eindeutig und bekannt sind. The project uses a few abbreviations for variable names that are @@ -316,6 +319,19 @@ The raw result of the Lpeg grammar parser. \\ \end{tabular} \end{center} +\noindent +% Es wird empfohlen, beim Entwickeln im Texteditor luakeys zusammen mit +% dem Lua-Language-Server zu verwenden. +It is recommended to use luakeys together with the +\href{https://github.com/sumneko/lua-language-server}{github.com/sumneko/lua-language-server} +when developing in a text editor. +% +% Luakeys unterstützt nämlich das vom Server angeboten Annotationsformat +luakeys supports the annotation format offered by the server. +% Sie sollten dann Warnungen erhalten, wenn Sie die mittlerweile +% ziemlich große API von luakeys falsch verwenden. +You should then get warnings if you misuse luakeys’ now rather large API. + %% % %% @@ -1524,7 +1540,7 @@ therefore accepts any data type. % In der Tabelle \lua{utils} sind einige Hilfsfunktionen gebündelt. The \lua{utils} table bundles some auxiliary functions. -\InputLua[firstline=3,lastline=34]{utils/all.lua} +\InputLua[firstline=3,lastline=37]{utils/all.lua} %% % @@ -1621,6 +1637,18 @@ installed. \InputLua[firstline=4,lastline=10]{version.lua} +%% +% +%% + +\subsection{Table “error_messages”} + +\InputLua[firstline=4,lastline=17]{error-messages.lua} + +\begin{description} +\directlua{luakeys.print_error_messages()} +\end{description} + %----------------------------------------------------------------------- % %----------------------------------------------------------------------- @@ -2069,93 +2097,6 @@ An example of how to use the command in \LaTeX: \inputminted[linenos=true]{latex}{luakeys-debug.sty} -\changes{v0.1.0}{2021/01/18}{Inital release} -\changes{v0.2.0}{2021/09/19}{ -* Allow all recognized data types as keys. -* Allow TeX macros in the values. -* New public Lua functions: save(identifier, result), get(identifier). -} -\changes{v0.3.0}{2021/11/05}{ -* Add a LuaLaTeX wrapper “luakeys.sty”. -* Add a plain LuaTeX wrapper “luakeys.tex”. -* Rename the previous documentation file “luakeys.tex” to luakeys-doc.tex”. -} -\changes{v0.4.0}{2021/12/31}{ -* Parser: Add support for nested tables (for example {{'a', 'b'}}). -* Parser: Allow only strings and numbers as keys. -* Parser: Remove support from Lua numbers with exponents (for example '5e+20'). -* Switch the Lua testing framework to busted. -} -\changes{v0.5.0}{2022/04/04}{ -* Add possibility to change options globally. -* New option: standalone_as_true. -* Add a recursive converter callback / hook to process the parse tree. -* New option: case_insensitive_keys. -} -\changes{v0.6.0}{2022/06/09}{ -* New feature: keys now can be defined using the function - “define(defs, opts)” or “define(kv_string, { defs = { key = { ... } } })” -* Rename the global options table from “default_options” to “opts”. -* New option “format_keys”. -* Remove option “case_insensitive_keys”. Use - “format_keys = \{ lower \}” to achieve the same effect. -* The default value of the option “convert_dimension” is now false. -* The option “standalone_as_true” is renamed to “naked_as_value”. - The boolean value of the option must be changed to the opposite to. - produce the previous effect. -* The function “print()” is now called “debug()”. -} -\changes{v0.7.0}{2022/07/06}{ -* The project now uses semantic versioning. -* New definition attribute “pick” to pick standalone values and assign - them to a key. -* New function “utils.scan_oarg()” to search for an optional argument, - that means scan for tokens that are enclosed in square brackets. -* Extend and improve the documentation. -} -\changes{v0.8.0}{2022/11/17}{ -* Add 6 new options to change the delimiters: “assignment_operator”, - “group_begin”, “group_end”, “list_separator”, “quotation_begin”, - “quotation_end”. -* Extend the documentation about the option “format_keys”. -} -\changes{v0.9.0}{2022/11/21}{ -* The definition attibute “pick” accepts a new data type: “any”. -* The attribute value “true” for the attribute “pick” is deprecated. -* The attribute “pick” accepts now multiple data types specified in - a table. -* Add a new function called “any(value)” in the “is” table that accepts - any data type. -} -\changes{v0.10.0}{2022/12/16}{ -* Add support for an invert flat that flips the value of naked keys. -* Add new options to specify which strings are recognized as Boolean - values. -} -\changes{v0.11.0}{2022/12/23}{ -* Add a new function called “get_private_instance()” to load a private - version of the luakeys module. -} -\changes{v0.12.0}{2023/01/05}{ -Added -* Macros \cmd{\LuakeysGetPackageOptions}, \cmd{\LuakeysGetClassOptions}. -* Option “accumulated_result”. -* Data type “list” to the attribute “data_type”. -* Attribute “description”. -* Tables “utils.log” and “utils.ansi_color”. -* Table “errors_message” to set custom messages. -* Short form syntax for the definition attribute “opposite_keys”. -Changed -* Breaking change! luakeys exports now a function instead of a table. - Use “require('luakeys')()” or “luakeys.new()” instead of - “require('luakeys')”. -* Breaking change! “luakeys.parse()”, “luakeys.define()”, “luakeys.save()” - and “luakeys.get()” can’t be used anymore from the global variable luakeys. -* New name for the function “new()” instead of “get_private_instance()". -} - -\pagebreak -\PrintChanges \pagebreak \PrintIndex \end{document} diff --git a/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf b/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf index 5d53f1a31a7..7e7a25c6204 100644 Binary files a/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf and b/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf differ diff --git a/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty b/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty index aa82ed78be7..ef77fff6320 100644 --- a/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty +++ b/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty @@ -17,6 +17,6 @@ % luakeys-debug.sty and luakeys-debug.tex. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{luakeys-debug}[2023/01/05 v0.12.0 Debug package for luakeys.] +\ProvidesPackage{luakeys-debug}[2023/01/13 v0.13.0 Debug package for luakeys.] \input luakeys-debug.tex diff --git a/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua b/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua index c3da56e7166..ede652cf64f 100644 --- a/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua +++ b/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua @@ -17,7 +17,6 @@ ---luakeys-debug.sty and luakeys-debug.tex. ----A key-value parser written with Lpeg. --- ----@module luakeys local lpeg = require('lpeg') if not tex then @@ -34,6 +33,7 @@ if not tex then } end +--- local utils = (function() --- ---Merge two tables into the first specified table. @@ -88,10 +88,10 @@ local utils = (function() --- ---Remove an element from a table. --- - ---@param source table - ---@param value any + ---@param source table # The source table. + ---@param value any # The value to be removed from the table. --- - ---@return any|nil + ---@return any|nil # If the value was found, then this value, otherwise nil. local function remove_from_table(source, value) for index, v in pairs(source) do if value == v then @@ -102,7 +102,9 @@ local utils = (function() end --- - ---@param source table + ---Return the keys of a table as a sorted list (array like table). + --- + ---@param source table # The source table. --- ---@return table # An array table with the sorted key names. local function get_table_keys(source) @@ -148,47 +150,32 @@ local utils = (function() end --- - ---Scan for an optional argument. + ---Print a formatted string. --- - ---@param initial_delimiter? string # The character that marks the beginning of an optional argument (by default `[`). - ---@param end_delimiter? string # The character that marks the end of an optional argument (by default `]`). + ---* `%d` or `%i`: Signed decimal integer + ---* `%u`: Unsigned decimal integer + ---* `%o`: Unsigned octal + ---* `%x`: Unsigned hexadecimal integer + ---* `%X`: Unsigned hexadecimal integer (uppercase) + ---* `%f`: Decimal floating point, lowercase + ---* `%e`: Scientific notation (mantissa/exponent), lowercase + ---* `%E`: Scientific notation (mantissa/exponent), uppercase + ---* `%g`: Use the shortest representation: %e or %f + ---* `%G`: Use the shortest representation: %E or %F + ---* `%a`: Hexadecimal floating point, lowercase + ---* `%A`: Hexadecimal floating point, uppercase + ---* `%c`: Character + ---* `%s`: String of characters + ---* `%p`: Pointer address b8000000 + ---* `%%`: A `%` followed by another `%` character will write a single `%` to the stream. + ---* `%q`: formats `booleans`, `nil`, `numbers`, and `strings` in a way that the result is a valid constant in Lua source code. --- - ---@return string|nil # The string that was enclosed by the delimiters. The delimiters themselves are not returned. - local function scan_oarg(initial_delimiter, - end_delimiter) - if initial_delimiter == nil then - initial_delimiter = '[' - end - - if end_delimiter == nil then - end_delimiter = ']' - end - - local function convert_token(t) - if t.index ~= nil then - return utf8.char(t.index) - else - return '\\' .. t.csname - end - end - - local function get_next_char() - local t = token.get_next() - return convert_token(t), t - end - - local char, t = get_next_char() - if char == initial_delimiter then - local oarg = {} - char = get_next_char() - while char ~= end_delimiter do - table.insert(oarg, char) - char = get_next_char() - end - return table.concat(oarg, '') - else - token.put_next(t) - end + ---http://www.lua.org/source/5.3/lstrlib.c.html#str_format + --- + ---@param format string # A string in the `printf` format + ---@param ... any # A sequence of additional arguments, each containing a value to be used to replace a format specifier in the format string. + local function tex_printf(format, ...) + tex.print(string.format(format, ...)) end --- @@ -278,6 +265,54 @@ local utils = (function() throw_error_message(message, help) end + --- + ---Scan for an optional argument. + --- + ---@param initial_delimiter? string # The character that marks the beginning of an optional argument (by default `[`). + ---@param end_delimiter? string # The character that marks the end of an optional argument (by default `]`). + --- + ---@return string|nil # The string that was enclosed by the delimiters. The delimiters themselves are not returned. + local function scan_oarg(initial_delimiter, + end_delimiter) + if initial_delimiter == nil then + initial_delimiter = '[' + end + + if end_delimiter == nil then + end_delimiter = ']' + end + + --- + ---@param t Token + --- + ---@return string + local function convert_token(t) + if t.index ~= nil then + return utf8.char(t.index) + else + return '\\' .. t.csname + end + end + + local function get_next_char() + local t = token.get_next() + return convert_token(t), t + end + + local char, t = get_next_char() + if char == initial_delimiter then + local oarg = {} + char = get_next_char() + while char ~= end_delimiter do + table.insert(oarg, char) + char = get_next_char() + end + return table.concat(oarg, '') + else + token.put_next(t) + end + end + local function visit_tree(tree, callback_func) if type(tree) ~= 'table' then throw_error_message( @@ -504,19 +539,29 @@ local utils = (function() ---Log levels: --- ---* 0: silent - ---* 1: error - ---* 2: warn - ---* 3: info - ---* 4: verbose - ---* 5: debug + ---* 1: error (red) + ---* 2: warn (yellow) + ---* 3: info (green) + ---* 4: verbose (blue) + ---* 5: debug (magenta) --- local log = (function() ---@private local opts = { level = 0 } + local function colorize_not(s) + return s + end + + local colorize = colorize_not + ---@private local function print_message(message, ...) - print(string.format(message, ...)) + local args = {...} + for index, value in ipairs(args) do + args[index] = colorize(value) + end + print(string.format(message, table.unpack(args))) end --- @@ -548,7 +593,12 @@ local utils = (function() end opts.level = level end + end + --- + ---@return integer + local function get_log_level() + return opts.level end --- @@ -560,7 +610,9 @@ local utils = (function() ---@param ... any local function error(message, ...) if opts.level >= 1 then + colorize = ansi_color.red print_message(message, ...) + colorize = colorize_not end end @@ -573,7 +625,9 @@ local utils = (function() ---@param ... any local function warn(message, ...) if opts.level >= 2 then + colorize = ansi_color.yellow print_message(message, ...) + colorize = colorize_not end end @@ -586,7 +640,9 @@ local utils = (function() ---@param ... any local function info(message, ...) if opts.level >= 3 then + colorize = ansi_color.green print_message(message, ...) + colorize = colorize_not end end @@ -599,7 +655,9 @@ local utils = (function() ---@param ... any local function verbose(message, ...) if opts.level >= 4 then + colorize = ansi_color.blue print_message(message, ...) + colorize = colorize_not end end @@ -612,12 +670,15 @@ local utils = (function() ---@param ... any local function debug(message, ...) if opts.level >= 5 then + colorize = ansi_color.magenta print_message(message, ...) + colorize = colorize_not end end return { - set_log_level = set_log_level, + set = set_log_level, + get = get_log_level, error = error, warn = warn, info = info, @@ -634,11 +695,12 @@ local utils = (function() get_table_size = get_table_size, get_array_size = get_array_size, visit_tree = visit_tree, - scan_oarg = scan_oarg, + tex_printf = tex_printf, throw_error_message = throw_error_message, throw_error_code = throw_error_code, - log = log, + scan_oarg = scan_oarg, ansi_color = ansi_color, + log = log, } end)() @@ -648,7 +710,7 @@ end)() local visualizers = (function() --- - ---The function `render(tbl)` reverses the function + ---Reverse the function ---`parse(kv_string)`. It takes a Lua table and converts this table ---into a key-value string. The resulting string usually has a ---different order as the input table. In Lua only tables with @@ -783,6 +845,64 @@ local visualizers = (function() return { render = render, stringify = stringify, debug = debug } end)() +---@class OptionCollection +---@field accumulated_result? table +---@field assignment_operator? string # default `=` +---@field convert_dimensions? boolean # default `false` +---@field debug? boolean # default `false` +---@field default? boolean # default `true` +---@field defaults? table +---@field defs? DefinitionCollection +---@field false_aliases? table default `{ 'false', 'FALSE', 'False' }`, +---@field format_keys? boolean # default `false`, +---@field group_begin? string default `{`, +---@field group_end? string default `}`, +---@field hooks? HookCollection +---@field invert_flag? string default `!` +---@field list_separator? string default `,` +---@field naked_as_value? boolean # default `false` +---@field no_error? boolean # default `false` +---@field quotation_begin? string `"` +---@field quotation_end? string `"` +---@field true_aliases? table `{ 'true', 'TRUE', 'True' }` +---@field unpack? boolean # default `true` + +---@alias KeysHook fun(key: string, value: any, depth: integer, current: table, result: table): string, any +---@alias ResultHook fun(result: table): nil + +---@class HookCollection +---@field kv_string? fun(kv_string: string): string +---@field keys_before_opts? KeysHook +---@field result_before_opts? ResultHook +---@field keys_before_def? KeysHook +---@field result_before_def? ResultHook +---@field keys? KeysHook +---@field result? ResultHook + +---@alias ProcessFunction fun(value: any, input: table, result: table, unknown: table): any + +---@alias PickDataType 'string'|'number'|'dimension'|'integer'|'boolean'|'any' + +---@class Definition +---@field alias? string|table +---@field always_present? boolean +---@field choices? table +---@field data_type? 'boolean'|'dimension'|'integer'|'number'|'string'|'list' +---@field default? any +---@field description? string +---@field exclusive_group? string +---@field l3_tl_set? string +---@field macro? string +---@field match? string +---@field name? string +---@field opposite_keys? table +---@field pick? PickDataType|PickDataType[]|false +---@field process? ProcessFunction +---@field required? boolean +---@field sub_keys? table + +---@alias DefinitionCollection table + local namespace = { opts = { accumulated_result = false, @@ -883,10 +1003,13 @@ local namespace = { } --- ----@return table # The public interface of the module. +---Main entry point of the module. +--- +---The return value is intentional not documented so the Lua language server can figure out the types. local function main() ---The default options. + ---@type OptionCollection local default_opts = utils.clone_table(namespace.opts) local error_messages = utils.clone_table(namespace.error_messages) @@ -901,9 +1024,9 @@ local function main() --- ---Normalize the parse options. --- - ---@param opts? table # Options in a raw format. The table may be empty or some keys are not set. + ---@param opts? OptionCollection|unknown # Options in a raw format. The table may be empty or some keys are not set. --- - ---@return table + ---@return OptionCollection local function normalize_opts(opts) if type(opts) ~= 'table' then opts = {} @@ -1461,10 +1584,10 @@ local function main() throw_error('E010') end - ---@param value string - local function remove_values(value) + ---@param v string + local function remove_values(v) local count = 0 - while utils.remove_from_table(input, value) do + while utils.remove_from_table(input, v) do count = count + 1 end return count @@ -1485,7 +1608,9 @@ local function main() throw_error('E020', { ['true'] = true_key, ['false'] = false_key }) end - + if true_count == 0 and false_count == 0 then + return + end return true_count == 1 or false_count == 0 end end, @@ -1681,17 +1806,28 @@ local function main() ---Parse a LaTeX/TeX style key-value string into a Lua table. --- ---@param kv_string string # A string in the TeX/LaTeX style key-value format as described above. - ---@param opts? table # A table containing options. + ---@param opts? OptionCollection # A table containing options. --- ---@return table result # The final result of all individual parsing and normalization steps. ---@return table unknown # A table with unknown, undefinied key-value pairs. ---@return table raw # The unprocessed, raw result of the LPeg parser. local function parse(kv_string, opts) + opts = normalize_opts(opts) + + local function log_result(caption, result) + utils.log + .debug('%s: \n%s', caption, visualizers.stringify(result)) + end + if kv_string == nil then return {}, {}, {} end - opts = normalize_opts(opts) + if opts.debug then + utils.log.set('debug') + end + + utils.log.debug('kv_string: “%s”', kv_string) if type(opts.hooks.kv_string) == 'function' then kv_string = opts.hooks.kv_string(kv_string) @@ -1700,6 +1836,8 @@ local function main() local result = generate_parser('list', opts):match(kv_string) local raw = utils.clone_table(result) + log_result('result after Lpeg Parsing', result) + local function apply_hook(name) if type(opts.hooks[name]) == 'function' then if name:match('^keys') then @@ -1727,6 +1865,8 @@ local function main() apply_hooks('before_opts') + log_result('after hooks before_opts', result) + --- ---Normalize the result table of the LPeg parser. This normalization ---tasks are performed on the raw input table coming directly from @@ -1803,6 +1943,8 @@ local function main() end result = apply_opts(result, opts) + log_result('after apply opts', result) + ---All unknown keys are stored in this table local unknown = nil if type(opts.defs) == 'table' then @@ -1811,15 +1953,15 @@ local function main() {}, {}, utils.clone_table(result)) end + log_result('after apply_definitions', result) + apply_hooks() if opts.defaults ~= nil and type(opts.defaults) == 'table' then utils.merge_tables(result, opts.defaults, false) end - if opts.debug then - visualizers.debug(result) - end + log_result('End result', result) if opts.accumulated_result ~= nil and type(opts.accumulated_result) == 'table' then @@ -1841,11 +1983,14 @@ local function main() return { new = main, - version = { 0, 12, 0 }, + version = { 0, 13, 0 }, ---@see parse parse = parse, + --- + ---@param defs DefinitionCollection + ---@param opts? OptionCollection define = function(defs, opts) return function(kv_string, inner_opts) local options @@ -1883,24 +2028,25 @@ local function main() debug = visualizers.debug, --- - ---The function `save(identifier, result): void` saves a result (a + ---Save a result (a ---table from a previous run of `parse`) under an identifier. ---Therefore, it is not necessary to pollute the global namespace to ---store results for the later usage. --- ---@param identifier string # The identifier under which the result is saved. --- - ---@param result table # A result to be stored and that was created by the key-value parser. + ---@param result table|any # A result to be stored and that was created by the key-value parser. save = function(identifier, result) result_store[identifier] = result end, + --- ---The function `get(identifier): table` retrieves a saved result ---from the result store. --- ---@param identifier string # The identifier under which the result was saved. --- - ---@return table + ---@return table|any get = function(identifier) ---if result_store[identifier] == nil then --- throw_error('No stored result was found for the identifier \'' .. identifier .. '\'') @@ -1931,6 +2077,23 @@ local function main() tex.print(tostring(namespace[from][name])) end, + print_error_messages = function() + local msgs = namespace.error_messages + local keys = utils.get_table_keys(namespace.error_messages) + for _, key in ipairs(keys) do + local msg = msgs[key] + ---@type string + local msg_text + if type(msg) == 'table' then + msg_text = msg[1] + else + msg_text = msg + end + utils.tex_printf('\\item[\\texttt{%s}]: \\texttt{%s}', key, + msg_text) + end + end, + --- ---@param exported_table table depublish_functions = function(exported_table) diff --git a/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty b/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty index 4b5432faa3b..6feef78b2a2 100644 --- a/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty +++ b/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty @@ -17,7 +17,7 @@ % luakeys-debug.sty and luakeys-debug.tex. \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{luakeys}[2023/01/05 v0.12.0 Parsing key-value options using Lua.] +\ProvidesPackage{luakeys}[2023/01/13 v0.13.0 Parsing key-value options using Lua.] \directlua{ if luakeys == nil then luakeys = require('luakeys')() -- cgit v1.2.3