diff options
author | Karl Berry <karl@freefriends.org> | 2022-10-22 20:19:58 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2022-10-22 20:19:58 +0000 |
commit | d9c4e32efd56d621a7c2ba80175502b38ff8d8ca (patch) | |
tree | d22109b3ce7b8cd5ff90c5e9ce7fbc7d0e2afc5c /Master/texmf-dist/tex/luatex/penlight | |
parent | 50b1788490c90e5386d61dc589433c842926cc50 (diff) |
penlight (22oct22)
git-svn-id: svn://tug.org/texlive/trunk@64781 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/penlight')
-rw-r--r-- | Master/texmf-dist/tex/luatex/penlight/penlight.lua | 202 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/penlight/penlight.sty | 18 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/penlight/penlightextras.lua | 55 |
3 files changed, 217 insertions, 58 deletions
diff --git a/Master/texmf-dist/tex/luatex/penlight/penlight.lua b/Master/texmf-dist/tex/luatex/penlight/penlight.lua index 4b2436be1b3..6ffcaf49b70 100644 --- a/Master/texmf-dist/tex/luatex/penlight/penlight.lua +++ b/Master/texmf-dist/tex/luatex/penlight/penlight.lua @@ -133,10 +133,11 @@ function _M.parse(text_or_filename, is_file, use_basic) end if is_file then - local text_or_filename, err = utils.readfile(text_or_filename) - if not text_or_filename then + local text, err = utils.readfile(text_or_filename) + if not text then return nil, err end + text_or_filename = text end local doc, err = parser(text_or_filename) @@ -1219,12 +1220,24 @@ end -- -- Note: the path is prefixed, so it is searched first when requiring modules. -- @string base optional base directory (absolute, or relative path). +-- @bool nofollow always use the invocation's directory, even if the invoked file is a symlink -- @treturn string the current script's path with a trailing slash -function app.require_here (base) - local p = path.dirname(app.script_name()) +function app.require_here (base, nofollow) + local p = app.script_name() if not path.isabs(p) then p = path.join(path.currentdir(),p) end + if not nofollow then + local t = path.link_attrib(p) + if t and t.mode == 'link' then + t = t.target + if not path.isabs(t) then + t = path.join(path.dirname(p), t) + end + p = t + end + end + p = path.normpath(path.dirname(p)) if p:sub(-1,-1) ~= path.sep then p = p..path.sep end @@ -2583,9 +2596,9 @@ end -- This functions mimics the `warn` function added in Lua 5.4. -- @function warn -- @param ... any arguments -if not warn then -- luacheck: ignore +if not rawget(_G, "warn") then local enabled = false - local function warn(arg1, ...) -- luacheck: ignore + local function warn(arg1, ...) if type(arg1) == "string" and arg1:sub(1, 1) == "@" then -- control message if arg1 == "@on" then @@ -2957,7 +2970,7 @@ end local config = {} ---- like io.lines(), but allows for lines to be continued with '\'. +--- like `io.lines`, but allows for lines to be continued with '`\`'. -- @param file a file-like object (anything where read() returns the next line) or a filename. -- Defaults to stardard input. -- @return an iterator over the lines, or nil @@ -5993,7 +6006,8 @@ function lapp.process_options_string(str,args) elseif check '$<{name} $' then -- is it <parameter_name>? -- so <input file...> becomes input_file ... optparm,rest = res.name:match '([^%.]+)(.*)' - optparm = optparm:gsub('%A','_') + -- follow lua legal variable names + optparm = optparm:sub(1,1):gsub('%A','_') .. optparm:sub(2):gsub('%W', '_') varargs = rest == '...' append(parmlist,optparm) end @@ -6002,6 +6016,7 @@ function lapp.process_options_string(str,args) line = res.rest res = {} local optional + local defval_str -- do we have ([optional] [<type>] [default <val>])? if match('$({def} $',line,res) or match('$({def}',line,res) then local typespec = strip(res.def) @@ -6044,6 +6059,7 @@ function lapp.process_options_string(str,args) -- optional 'default value' clause. Type is inferred as -- 'string' or 'number' if there's no explicit type if default or match('default $r{rest}',typespec,res) then + defval_str = res.rest defval,vtype = process_default(res.rest,vtype) end else -- must be a plain flag, no extra parameter required @@ -6053,6 +6069,7 @@ function lapp.process_options_string(str,args) local ps = { type = vtype, defval = defval, + defval_str = defval_str, required = defval == nil and not optional, comment = res.rest or optparm, constraint = constraint, @@ -6182,6 +6199,9 @@ function lapp.process_options_string(str,args) if not ps.used then if ps.required then lapp.error("missing required parameter: "..parm) end set_result(ps,parm,ps.defval) + if builtin_types[ps.type] == "file" then + set_result(ps, parm .. "_name", ps.defval_str) + end end end return results @@ -8279,9 +8299,6 @@ end -- @string P A file path function path.isdir(P) assert_string(1,P) - if P:match("\\$") then - P = P:sub(1,-2) - end return attrib(P,'mode') == 'directory' end @@ -9227,10 +9244,11 @@ function pretty.write (tbl,space,not_clever) end end table.sort(ordered_keys, function (a, b) - if type(a) == type(b) and type(a) == 'string' then - return a < b + if type(a) == type(b) then + return tostring(a) < tostring(b) + else + return type(a) < type(b) end - return type(a) == 'boolean' or (type(b) ~= 'boolean' and type(a) == 'table') end) local function write_entry (key, val) local tkey = type(key) @@ -12327,7 +12345,7 @@ local function keys_op(i,v) return i end --- return all the keys of a table in arbitrary order. -- @within Extraction --- @tab t A table +-- @tab t A list-like table where the values are the keys of the input table function tablex.keys(t) assert_arg_iterable(1,t) return makelist(tablex.pairmap(keys_op,t)) @@ -12337,7 +12355,7 @@ local function values_op(i,v) return v end --- return all the values of the table in arbitrary order -- @within Extraction --- @tab t A table +-- @tab t A list-like table where the values are the values of the input table function tablex.values(t) assert_arg_iterable(1,t) return makelist(tablex.pairmap(values_op,t)) @@ -13425,6 +13443,8 @@ local concat = table.concat local _unpack = table.unpack -- always injected by 'compat' local find = string.find local sub = string.sub +local next = next +local floor = math.floor local is_windows = compat.is_windows local err_mode = 'default' @@ -13433,7 +13453,7 @@ local operators local _function_factories = {} -local utils = { _VERSION = "1.12.0" } +local utils = { _VERSION = "1.13.1" } for k, v in pairs(compat) do utils[k] = v end --- Some standard patterns @@ -13635,6 +13655,47 @@ end +--- an iterator over all non-integer keys (inverse of `ipairs`). +-- It will skip any key that is an integer number, so negative indices or an +-- array with holes will not return those either (so it returns slightly less than +-- 'the inverse of `ipairs`'). +-- +-- This uses `pairs` under the hood, so any value that is iterable using `pairs` +-- will work with this function. +-- @tparam table t the table to iterate over +-- @treturn key +-- @treturn value +-- @usage +-- local t = { +-- "hello", +-- "world", +-- hello = "hallo", +-- world = "Welt", +-- } +-- +-- for k, v in utils.kpairs(t) do +-- print("German: ", v) +-- end +-- +-- -- output; +-- -- German: hallo +-- -- German: Welt +function utils.kpairs(t) + local index + return function() + local value + while true do + index, value = next(t, index) + if type(index) ~= "number" or floor(index) ~= index then + break + end + end + return index, value + end +end + + + --- Error handling -- @section Error-handling @@ -13661,17 +13722,20 @@ function utils.assert_arg (n,val,tp,verify,msg,lev) return val end ---- creates an Enum table. +--- creates an Enum or constants lookup table for improved error handling. -- This helps prevent magic strings in code by throwing errors for accessing --- non-existing values. --- --- Calling on the object does the same, but returns a soft error; `nil + err`. --- --- The values are equal to the keys. The enum object is --- read-only. --- @param ... strings that make up the enumeration. --- @return Enum object --- @usage -- accessing at runtime +-- non-existing values, and/or converting strings/identifiers to other values. +-- +-- Calling on the object does the same, but returns a soft error; `nil + err`, if +-- the call is succesful (the key exists), it will return the value. +-- +-- When calling with varargs or an array the values will be equal to the keys. +-- The enum object is read-only. +-- @tparam table|vararg ... the input for the Enum. If varargs or an array then the +-- values in the Enum will be equal to the names (must be strings), if a hash-table +-- then values remain (any type), and the keys must be strings. +-- @return Enum object (read-only table/object) +-- @usage -- Enum access at runtime -- local obj = {} -- obj.MOVEMENT = utils.enum("FORWARD", "REVERSE", "LEFT", "RIGHT") -- @@ -13683,21 +13747,81 @@ end -- -- "'REVERES' is not a valid value (expected one of: 'FORWARD', 'REVERSE', 'LEFT', 'RIGHT')" -- -- end --- @usage -- validating user-input --- local parameter = "...some user provided option..." --- local ok, err = obj.MOVEMENT(parameter) -- calling on the object --- if not ok then --- print("bad 'parameter', " .. err) +-- @usage -- standardized error codes +-- local obj = { +-- ERR = utils.enum { +-- NOT_FOUND = "the item was not found", +-- OUT_OF_BOUNDS = "the index is outside the allowed range" +-- }, +-- +-- some_method = function(self) +-- return self.ERR.OUT_OF_BOUNDS +-- end, +-- } +-- +-- local result, err = obj:some_method() +-- if not result then +-- if err == obj.ERR.NOT_FOUND then +-- -- check on error code, not magic strings +-- +-- else +-- -- return the error description, contained in the constant +-- return nil, "error: "..err -- "error: the index is outside the allowed range" +-- end +-- end +-- @usage -- validating/converting user-input +-- local color = "purple" +-- local ansi_colors = utils.enum { +-- black = 30, +-- red = 31, +-- green = 32, +-- } +-- local color_code, err = ansi_colors(color) -- calling on the object, returns the value from the enum +-- if not color_code then +-- print("bad 'color', " .. err) +-- -- "bad 'color', 'purple' is not a valid value (expected one of: 'black', 'red', 'green')" -- os.exit(1) -- end function utils.enum(...) - local lst = utils.pack(...) - utils.assert_arg(1, lst[1], "string") -- at least 1 string - + local first = select(1, ...) local enum = {} - for i, value in ipairs(lst) do - utils.assert_arg(i, value, "string") - enum[value] = value + local lst + + if type(first) ~= "table" then + -- vararg with strings + lst = utils.pack(...) + for i, value in utils.npairs(lst) do + utils.assert_arg(i, value, "string") + enum[value] = value + end + + else + -- table/array with values + utils.assert_arg(1, first, "table") + lst = {} + -- first add array part + for i, value in ipairs(first) do + if type(value) ~= "string" then + error(("expected 'string' but got '%s' at index %d"):format(type(value), i), 2) + end + lst[i] = value + enum[value] = value + end + -- add key-ed part + for key, value in utils.kpairs(first) do + if type(key) ~= "string" then + error(("expected key to be 'string' but got '%s'"):format(type(key)), 2) + end + if enum[key] then + error(("duplicate entry in array and hash part: '%s'"):format(key), 2) + end + enum[key] = value + lst[#lst+1] = key + end + end + + if not lst[1] then + error("expected at least 1 entry", 2) end local valid = "(expected one of: '" .. concat(lst, "', '") .. "')" @@ -13711,7 +13835,7 @@ function utils.enum(...) __call = function(self, key) if type(key) == "string" then local v = rawget(self, key) - if v then + if v ~= nil then return v end end diff --git a/Master/texmf-dist/tex/luatex/penlight/penlight.sty b/Master/texmf-dist/tex/luatex/penlight/penlight.sty index d796f1e1c88..5af886786e4 100644 --- a/Master/texmf-dist/tex/luatex/penlight/penlight.sty +++ b/Master/texmf-dist/tex/luatex/penlight/penlight.sty @@ -1,5 +1,5 @@ % Kale Ewasiuk (kalekje@gmail.com) -% 2022-10-15 +% 2022-10-22 % Copyright (C) 2021-2022 Kale Ewasiuk % % Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,7 +22,7 @@ % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE % OR OTHER DEALINGS IN THE SOFTWARE. -\ProvidesPackage{penlight}[2022-10-15] +\ProvidesPackage{penlight}[2022-10-22] \RequirePackage{luacode} @@ -43,8 +43,8 @@ \DeclareOption{format}{\luadirect{_G[__PENLIGHT__].stringx.format_operator()}} \DeclareOption{func}{\luadirect{_G[__PENLIGHT__].utils.import(__PENLIGHT__..'.func')}} \DeclareOption{extras}{\luadirect{require'penlightextras'}} -\DeclareOption{extrasnoglobals}{\luadirect{ - __PL_NO_GLOBALS__ = true +\DeclareOption{extrasglobals}{\luadirect{ + __PL_GLOBALS__ = true require'penlightextras' }} @@ -58,23 +58,23 @@ end -\newcommand{\writePDFmetadata}{\luadirect{writePDFmetadata()}} +\newcommand{\writePDFmetadata}{\luadirect{_G[__PENLIGHT__].tex.writePDFmetadata()}} \NewDocumentCommand{\writePDFmetadatakv}{ s m }{ \IfBooleanTF{#1}{% if *, overwrite everything \luadirect{ __PDFmetadata__ = luakeys.parse(\luastring{#2}) - writePDFmetadata() + _G[__PENLIGHT__].tex.writePDFmetadata() }}{ \luadirect{ __PDFmetadata__ = __PDFmetadata__ or {} - table.update(__PDFmetadata__, luakeys.parse(\luastring{#2})) - writePDFmetadata() + _G[__PENLIGHT__].tablex.update(__PDFmetadata__, luakeys.parse(\luastring{#2})) + _G[__PENLIGHT__].tex.writePDFmetadata() }} } -\def\luastringT#1{\luastring{\unexpanded\expandafter\expandafter\expandafter{#1}}} +\def\luastringT#1{\luastring{\unexpanded\expandafter\expandafter\expandafter{#1}}} % expand luastring twice \let\luastringF\luastring % fully expanded luastring % allow control over expansion of arguments to a latex function diff --git a/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua b/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua index 9ce0903f1c6..a6a5c1ff0aa 100644 --- a/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua +++ b/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua @@ -1,5 +1,5 @@ --% Kale Ewasiuk (kalekje@gmail.com) ---% 2022-10-15 +--% 2022-10-22 --% Copyright (C) 2021-2022 Kale Ewasiuk --% --% Permission is hereby granted, free of charge, to any person obtaining a copy @@ -22,16 +22,17 @@ --% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE --% OR OTHER DEALINGS IN THE SOFTWARE. -__SKIP_TEX__ = __SKIP_TEX__ or false --if declared true before here, it will use regular print functions +__PL_SKIP_TEX__ = __PL_SKIP_TEX__ or false --if declared true before here, it will use regular print functions -- (for troubleshooting with texlua instead of actual use in lua latex) -__SKIP_LUAKEYS__ = __SKIP_LUAKEYS__ or false -__PL_NO_GLOBALS__ = __PL_NO_GLOBALS__ or false +__PL_SKIP_LUAKEYS__ = __PL_SKIP_LUAKEYS__ or false +__PL_GLOBALS__ = __PL_GLOBALS__ or false __PL_EXTRAS__ = 1 +__PL_NO_HYPERREF__ = __PL_NO_HYPERREF__ or false -- requires penlight local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl -if not __SKIP_LUAKEYS__ then +if not __PL_SKIP_LUAKEYS__ then luakeys = require'luakeys' end @@ -74,7 +75,7 @@ pl.tex._xNoValue = '-NoValue-' --Generic LuaLaTeX utilities for print commands or environments -if not __SKIP_TEX__ then +if not __PL_SKIP_TEX__ then local function check_special_chars(s) -- todo extend to toher special chars? if type(s) == 'string' then if string.find(s, '[\n\r\t\0]') then @@ -142,6 +143,7 @@ function pl.tex.help_wrt(s1, s2) -- helpful printing, makes it easy to debug, s1 end wrt2('\n^^^^^\n') end +pl.help_wrt = pl.tex.help_wrt function pl.tex.prt_array2d(t) for _, r in ipairs(t) do @@ -292,15 +294,37 @@ end + + function pl.tex.get_ref_info(l) + local n = 5 + if __PL_NO_HYPERREF__ then + local n = 2 + end local r = token.get_macro('r@'..l) + local t = {} if r == nil then - return 0, 0 + t = pl.tablex.new(n, 0) -- make all 0s + r = '-not found-' + else + t = {r:match(("(%b{})"):rep(n))} + t = pl.tablex.map(string.trimfl, t) end - local sec, page = r:match("{([^}]*)}{([^}]*)}") - return sec, page + t[#t+1] = r -- add the og return of label + pl.help_wrt(t, 'ref info') + return t end +-- todo add regex pattern for cref info +--function pl.tex.get_ref_info_all_cref(l) +-- local r = token.get_macro('r@'..l..'@cref') +-- if r == nil then +-- return r, 0, 0 +-- end +-- local sec, page = r:match("{([^}]*)}{([^}]*)}") +-- return r, sec, page +--end + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- @@ -420,6 +444,10 @@ function str_mt.__index.delspace(str) return str:gsub('%s','') end +function str_mt.__index.trimfl(str) + return str:sub(2,-2) +end + -- -- -- -- function stuff @@ -750,7 +778,7 @@ end -if not __PL_NO_GLOBALS__ then +if _PL_GLOBALS__ then __PL_EXTRAS__ = 2 -- iterators kpairs = pl.utils.kpairs @@ -767,6 +795,13 @@ if not __PL_NO_GLOBALS__ then end end table.join = table.concat -- alias + -- todo should tablex have all table functions + + pl.tablex.concat = table.concat + pl.tablex.insert = table.insert + pl.tablex.maxn = table.maxn + pl.tablex.remove = table.remove + pl.tablex.sort = table.sort hasval = pl.hasval COMP = pl.COMP |