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 --- .../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 +- 3 files changed, 235 insertions(+), 72 deletions(-) (limited to 'Master/texmf-dist/tex/luatex') 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