diff options
author | Karl Berry <karl@freefriends.org> | 2023-07-23 20:46:55 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-07-23 20:46:55 +0000 |
commit | b4e682468cdb7557fd2abc99087fbd593459e86c (patch) | |
tree | 6cf4772607aed54779939ffe617e4aae1f16f8e6 /Master/texmf-dist/tex/luatex | |
parent | f877d675254b93251f32484b55e086b9bda798cf (diff) |
penlight (23jul23)
git-svn-id: svn://tug.org/texlive/trunk@67716 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r-- | Master/texmf-dist/tex/luatex/penlight/penlight.sty | 127 | ||||
-rw-r--r-- | Master/texmf-dist/tex/luatex/penlight/penlightextras.lua | 936 |
2 files changed, 9 insertions, 1054 deletions
diff --git a/Master/texmf-dist/tex/luatex/penlight/penlight.sty b/Master/texmf-dist/tex/luatex/penlight/penlight.sty index 4f5900e3b83..7a7c94b6a77 100644 --- a/Master/texmf-dist/tex/luatex/penlight/penlight.sty +++ b/Master/texmf-dist/tex/luatex/penlight/penlight.sty @@ -1,6 +1,6 @@ % Kale Ewasiuk (kalekje@gmail.com) -% 2023-07-18 -% Copyright (C) 2021-2022 Kale Ewasiuk +% 2023-07-22 +% Copyright (C) 2021-2023 Kale Ewasiuk % % Permission is hereby granted, free of charge, to any person obtaining a copy % of this software and associated documentation files (the "Software"), to deal @@ -22,124 +22,15 @@ % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE % OR OTHER DEALINGS IN THE SOFTWARE. -\ProvidesPackage{penlight}[2023-07-18] +\ProvidesPackage{penlight}[2023-07-22] -\RequirePackage{luacode} +\directlua{penlight = require'penlight'} -\IfFileExists{luakeys.lua}{}{\PackageError{penlight}{This package requires that luakeys be installed}{}} +\DeclareOption{pl}{\directlua{pl = penlight}} - -\DeclareOption{pl}{\luadirect{ - pl = require'penlight' - __PENLIGHT__ = 'pl' -}} -\DeclareOption{penlight}{\luadirect{ - penlight = require'penlight' - __PENLIGHT__ = 'penlight' -}} - - -\DeclareOption{stringx}{\luadirect{_G[__PENLIGHT__].stringx.import()}} -\DeclareOption{format}{\luadirect{_G[__PENLIGHT__].stringx.format_operator()}} -\DeclareOption{func}{\luadirect{_G[__PENLIGHT__].utils.import(__PENLIGHT__..'.func')}} -\DeclareOption{extras}{\luadirect{require'penlightextras'} - \gdef\penlight@loadextras{} -} -\DeclareOption{extrasglobals}{\luadirect{ - __PL_GLOBALS__ = true - require'penlightextras' - } - \gdef\penlight@loadextras{} -} +\DeclareOption{stringx}{\directlua{penlight.stringx.import()}} +\DeclareOption{format}{\directlua{penlight.stringx.format_operator()}} +\DeclareOption{func}{\directlua{penlight.utils.import(penlight.func)}} +\DeclareOption{import}{\ExecuteOptions{stringx,format,func}} \ProcessOptions*\relax - -\luadirect{ -if __PENLIGHT__ == nil then - tex.sprint('\\PackageError{penlight}{"penlight" or "pl" option must be passed to penlight as the first option}{}') -end -} - -\ifdefined\penlight@loadextras - -\global\newcommand{\writePDFmetadata}{\luadirect{_G[__PENLIGHT__].tex.writePDFmetadata()}} - -\NewDocumentCommand{\writePDFmetadatakv}{ s m }{ -\IfBooleanTF{#1}{% if *, overwrite everything - \luadirect{ - __PDFmetadata__ = luakeys.parse(\luastring{#2}) - _G[__PENLIGHT__].tex.writePDFmetadata() - }}{ - \luadirect{ - __PDFmetadata__ = __PDFmetadata__ or {} - _G[__PENLIGHT__].tablex.update(__PDFmetadata__, luakeys.parse(\luastring{#2})) - _G[__PENLIGHT__].tex.writePDFmetadata() - }} -} - - -\gdef\luastringT#1{\luastring{\unexpanded\expandafter\expandafter\expandafter{#1}}} % expand luastring twice -\global\let\luastringF\luastring % fully expanded luastring - -% allow control over expansion of arguments to a latex function -\NewDocumentCommand{\MakeluastringCommands}{O{} m }{% #1 the desired commands #2 defaults - \luadirect{_G[__PENLIGHT__].tex.aliasluastring(\luastring{#2},\luastring{#1})}% -} - -\NewDocumentCommand{\splitToComma}{ O{nn} m m }{% - \MakeluastringCommands[nn]{#1}% - \luadirect{_G[__PENLIGHT__].tex.split2comma(\plluastringA{#2},\plluastringB{#3})}% -} - -\NewDocumentCommand{\splitToItems}{ O{NN} m m }{% - \MakeluastringCommands[nn]{#1}% - \luadirect{_G[__PENLIGHT__].tex.split2items(\plluastringA{#2},\plluastringB{#3})}% -} - - -% -% -%\NewDocumentCommand{\tblnew}{m}{\luadirect{ -% _G[\luastring{#1}] = {} -%}} -% -%\NewDocumentCommand{\tblfrkv}{m m O{} }{\luadirect{ -% _G[\luastring{#1}] = luakeys.parse(\luastring{#2}, luakeys.parse(\luastring{#3})) -%}} -% -%\NewDocumentCommand{\tblset}{m m m}{\luadirect{ -% _G[\luastring{#1}][\luastring{#2}] = \luastring{#3} -%}} -% -%\NewDocumentCommand{\tblget}{m m}{\luadirect{ -% tex.sprint(tostring(_G[\luastring{#1}][\luastring{#2}])) -%}} -% -%\NewDocumentCommand{\tblidx}{m m}{\luadirect{ -% tex.sprint(tostring(_G[\luastring{#1}][#2])) -%}} -% -% -%\NewDocumentCommand{\tblupd}{ m m}{\luadirect{ -% _G[__PENLIGHT__].tablex.update(_G[\luastring{#1}], _G[\luastring{#2}]) -%}} -% -%\NewDocumentCommand{\tblupdkv}{ m m }{\luadirect{ -% _G[__PENLIGHT__].tablex.update(_G[\luastring{#1}], luakeys.parse(\luastring{#2})) -%}} -% -%% todo need a get table function. If blank is passed, the last table referenced is used. -%\NewDocumentCommand{\tblfrkvII}{ m m m }{\luadirect{ -% _G[\luastring{#1}] = _G[__PENLIGHT__].tablex.update(luakeys.parse(\luastring{#2}), luakeys.parse(\luastring{#3})) -%}} - - -%\NewDocumentCommand{\tbldo}{m m O{} }{\luadirect{ -% % tex.sprint(tostring(_G[\luastring{#1}][#2])) -% % todo allow one to use pl tablex function here, -% % {tbl}{update}[arg1][arg2] -% _G[__PENLIGHT__].tablex[\luastring[#1]](_G[\luastring{}], _G[\luastring{}]) -%}} - - -\else\fi
\ No newline at end of file diff --git a/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua b/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua deleted file mode 100644 index 5f5f76aefbf..00000000000 --- a/Master/texmf-dist/tex/luatex/penlight/penlightextras.lua +++ /dev/null @@ -1,936 +0,0 @@ ---% Kale Ewasiuk (kalekje@gmail.com) ---% 2023-07-18 ---% Copyright (C) 2021-2022 Kale Ewasiuk ---% ---% Permission is hereby granted, free of charge, to any person obtaining a copy ---% of this software and associated documentation files (the "Software"), to deal ---% in the Software without restriction, including without limitation the rights ---% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ---% copies of the Software, and to permit persons to whom the Software is ---% furnished to do so, subject to the following conditions: ---% ---% The above copyright notice and this permission notice shall be included in ---% all copies or substantial portions of the Software. ---% ---% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ---% ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED ---% TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A ---% PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT ---% SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ---% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ---% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ---% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE ---% OR OTHER DEALINGS IN THE SOFTWARE. - -__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) -__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 --- __PENLIGHT__ = 'penlight' or 'pl' - --- requires penlight -local pl = _G['penlight'] or _G['pl'] -- penlight for this namespace is pl - -if not __PL_SKIP_LUAKEYS__ then - luakeys = require'luakeys'() -end - - --- some bonus string operations, % text operator, and functional programming -pl.stringx.import() -pl.stringx.format_operator() -pl.utils.import'pl.func' -- allow placeholder expressions _1 +1 etc. - -pl.COMP = require'pl.comprehension'.new() -- for comprehensions - --- http://lua-users.org/wiki/SplitJoin -- todo read me!! - -pl.tex = {} -- adding a sub-module for tex related stuff - -local bind = bind or pl.func.bind - - -function pl.hasval(x) -- if something has value - if (type(x) == 'function') or (type(x) == 'CFunction') or (type(x) == 'userdata') then - return true - elseif (x == nil) or (x == false) or (x == 0) or (x == '') or (x == {}) then - return false - elseif (type(x) ~= 'boolean') and (type(x) ~= 'number') and (type(x) ~= 'string') then -- something else? maybe ths not needed - if #x == 0 then -- one more check, probably no needed though, I was trying to cover other classes but they all tables - return false - else - return true - end - end - return true -end - - --- Some simple and helpful LaTeX functions -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - --- xparse defaults -pl.tex._xTrue = '\\BooleanTrue ' -pl.tex._xFalse = '\\BooleanFalse ' -pl.tex._xNoValue = '-NoValue-' - ---Generic LuaLaTeX utilities for print commands or environments - -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 - pl.tex.pkgwarn('penlight', 'printing string with special (eg. newline) char, possible unexpected behaviour on string: '..s) - end - end - end - - -- NOTE: usage is a bit different than default. If number is first arg, you CANT change catcode. - -- We don't need that under normal use, use tex.print or tex.sprint if you need - function pl.tex.prt(s, ...) -- print something, no new line after - check_special_chars(s) - if type(s) == 'number' then s = tostring(s) end - tex.sprint(s, ...) --can print lists as well, but will NOT put new line between them or anything printed - end - - function pl.tex.prtn(s, ...) -- print with new line after, can print lists or nums. C-function not in Lua, apparantly - s = s or '' - check_special_chars(s) - if type(s) == 'number' then s = tostring(s) end - tex.print(s, ...) - end - - pl.tex.wrt = texio.write - pl.tex.wrtn = texio.write_nl -else - pl.tex.prt = io.write - pl.tex.prtn = print --print with new line - pl.tex.wrt = io.write - pl.tex.wrtn = io.write_nl -end - -function pl.tex.prtl(str) -- prints a literal/lines string in latex, adds new line between them - for line in str:gmatch"[^\n]*" do -- gets all characters up to a new line - pl.tex.prtn(line) - end -end - --- todo option to specify between character? one for first table, on for recursives? -function pl.tex.prtt(tab, d1, d2) -- prints a table with new line between each item - d1 = d1 or '' - d2 = d2 or '\\leavevmode\\\\' - for _, t in pairs(tab) do -- - if type(t) ~= 'table' then - if d1 == '' then - pl.tex.prtn(t) - else - pl.tex.prt(t, d1) - end - else - pl.tex.prtn(d2) - pl.tex.prtt(t,d1,d2) - end - end -end - -function pl.tex.help_wrt(s1, s2) -- helpful printing, makes it easy to debug, s1 is object, s2 is note - local wrt2 = wrt or texio.write_nl or print - s2 = s2 or '' - wrt2('\nvvvvv '..s2..'\n') - if type(s1) == 'table' then - wrt2(pl.pretty.write(s1)) - else - wrt2(tostring(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 - local s = '' - for _, v in ipairs(r) do - s = s.. tostring(v)..', ' - end - pl.tex.prt(s) - pl.tex.prt('\n') - end -end - --- -- -- -- -- - -function pl.tex.pkgwarn(pkg, msg1, msg2) - pkg = pkg or '' - msg1 = msg1 or '' - msg2 = msg2 or '' - tex.sprint('\\PackageWarning{'..pkg..'}{'..msg1..'}{'..msg2..'}') -end - -function pl.tex.pkgerror(pkg, msg1, msg2, stop) - pkg = pkg or '' - msg1 = msg1 or '' - msg2 = msg2 or '' - stop = pl.hasval(stop) - tex.sprint('\\PackageError{'..pkg..'}{'..msg1..'}{'..msg2..'}') - if stop then tex.sprint('\\stop') end -- stop on the spot (say that 10 times) -end - - ---definition helpers -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - -function pl.tex.defmacro(cs, val) -- , will not work if val contains undefined tokens (so pre-define them if using..) - val = val or '' -- however this works for arbitrary command names (\@hello-123 etc allowed) - token.set_macro(cs, val, 'global') -end - - -function pl.tex.defcmd(cs, val) -- fixes above issue, but only chars allowed in cs (and no @) - val = val or '' - tex.sprint('\\gdef\\'..cs..'{'..val..'}') -end - -function pl.tex.defcmdAT(cs, val) -- allows @ in cs, - --however should only be used in preamble. I avoid \makeatother because I've ran into issues with cls and sty files using it. - val = val or '' - tex.sprint('\\makeatletter\\gdef\\'..cs..'{'..val..'}') -end - - - -function pl.tex.prvcmd(cs, val) -- provide command via lua - if token.is_defined(cs) then - -- do nothing if token is defined already --pkgwarn('penlight', 'Definition '..cs..' is being overwritten') - else - pl.tex.defcmd(cs, val) - end -end - -function pl.tex.newcmd(cs, val) -- provide command via lua - if token.is_defined(cs) then - pl.tex.pkgerror('penlight: newcmd',cs..' already defined') - else - pl.tex.defcmd(cs, val) - end -end - -function pl.tex.renewcmd(cs, val) -- provide command via lua - if token.is_defined(cs) then - pl.tex.defcmd(cs, val) - else - pl.tex.pkgerror('penlight: renewcmd',cs..' not defined') - end -end - -function pl.tex.deccmd(cs, def, overwrite) -- declare a definition, placeholder throws an error if it used but not set! - overwrite = pl.hasval(overwrite) - local decfun - if overwrite then decfun = pl.tex.defcmd else decfun = pl.tex.newcmd end - if def == nil then - decfun(cs, pkgerror('penlight', cs..' was declared and used in document, but never set')) - else - decfun(cs, def) - end -end - - --- --- -- todo add and improve this, options for args? ---local function defcmd_nest(cs) -- for option if you'd like your commands under a parent ex. \csparent{var} --- tex.print('\\gdef\\'..cs..'#1{\\csname '..var..'--#1--\\endcsname}') ---end --- --- ---local function defcmd(cs, val, nargs) --- if (nargs == nil) or (args == 0) then --- token.set_macro(cs, tostring(val), 'global') --- else --- local args = '#1' --- tex.print('\\gdef\\'..cs..args..'{'..val..'}') --- -- todo https://tex.stackexchange.com/questions/57551/create-a-capitalized-macro-token-using-csname --- -- \expandafter\gdef\csname Two\endcsname#1#2{1:#1, two:#2} --todo do it like this --- end ---end - --- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - - --- when nesting commands, this makes it helpful to not worry about brackets -pl.tex._NumBkts = 0 ---prt(opencmd('textbf')..opencmd('texttt')..'bold typwriter'..close_bkt_cnt()) - -function pl.tex.opencmd(cmd) - return '\\'..cmd..add_bkt_cnt() -end - -function pl.tex.reset_bkt_cnt(n) - n = n or 0 - _NumBkts = n -end - -function pl.tex.add_bkt_cnt(n) - -- add open bracket n times, returns brackets - n = n or 1 - _NumBkts = _NumBkts + n - return ('{'):rep(n) -end - -function pl.tex.close_bkt_cnt(n) - n = n or _NumBkts - local s = ('}'):rep(n) - _NumBkts = _NumBkts - n - return s -end - - - -function pl.tex.aliasluastring(s, d) - s = s:delspace():upper():tolist() - d = d:delspace():upper():tolist() - for i, S in pl.seq.enum(d:slice_assign(1,#s,s)) do - if (S == 'E') or (S == 'F') then S = '' end -- E or F is fully expanded - pl.tex.prtn('\\let\\plluastring'..pl.Char(i)..'\\luastring'..S) - end -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 - 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 - 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 - - --- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - - - - - - --- -- -- -- math stuff -function math.mod(a, b) -- math modulo, return remainder only - return a - (math.floor(a/b)*b) -end - -function math.mod2(a) -- math modulo 2 - return math.mod(a,2) -end - - - --- -- -- -- string stuff -local lpeg = require"lpeg" -local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V - -local number = P{"number", - number = (V"int" * V"frac"^-1 * V"exp"^-1) / tonumber, - int = V"sign"^-1 * (R"19" * V"digits" + V"digit"), - digits = V"digit" * V"digits" + V"digit", - digit = R"09", - sign = S"+-", - frac = P"." * V"digits", - exp = S"eE" * V"sign"^-1 * V"digits", - } - - - - -function pl.char(num) - return string.char(string.byte("a")+num-1) -end - -function pl.Char(num) - return string.char(string.byte("A")+num-1) -end - - -local str_mt = getmetatable("") -- register functions with str - -function str_mt.__index.gnum(s) - return number:match(s) -end - -function str_mt.__index.gextract(s, pat) --extract a pattern from string, returns both - local s_extr = '' - local s_rem = s - for e in s:gmatch(pat) do - s_extr = s_extr..e - s_rem = s_rem:gsub(e,'') - end - return s_extr, s_rem -end - -function str_mt.__index.gfirst(s, t) -- get the first pattern found from a table of pattern - for _, pat in pairs(t) do - if string.find(s, pat) then - return pat - end - end -end - -function str_mt.__index.appif(S, W, B, O) --append W ord to S tring if B oolean true, otherwise O ther - --append Word to String - if B then --if b is true - S = S .. W - else --consider Other word - O = O or '' - S = S .. O - end - return S -end - - - function str_mt.__index.containsany(s, exp) - if type(exp) ~= 'table' then exp = {exp} end - for _, e in ipairs(exp) do - if s:find(e) then return true end - end - return false -end - -function str_mt.__index.containsanycase(s, exp) - if type(exp) ~= 'table' then exp = {exp} end - for _, e in ipairs(exp) do - if s:lower():find(e:lower()) then return true end - end - return false -end - -function str_mt.__index.totable(str) - local t = {} - for i = 1, #str do - t[i] = str:sub(i, i) - end - return t -end - -function str_mt.__index.tolist(str) - return pl.List(str) -end - - -function str_mt.__index.upfirst(str) - return str:gsub('%a', function(x) return x:upper() end, 1) -end - -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 - -function pl.clone_function(fn) - local dumped = string.dump(fn) - local cloned = loadstring(dumped) - local i = 1 - while true do - local name = debug.getupvalue(fn, i) - if not name then - break - end - debug.upvaluejoin(cloned, i, fn, i) - i = i + 1 - end - return cloned -end - - - - --- -- -- -- -- -- -- -- -- -- -- -- functions below extend the operator module - -function pl.operator.strgt(a,b) return tostring(a) > tostring(b) end -function pl.operator.strlt(a,b) return tostring(a) < tostring(b) end - - - --- -- -- -- functions below are helpers for arrays and 2d - -local function compare_elements(a, b, op, ele) - op = op or pl.oper.gt - ele = ele or 1 - return op(a[ele], b[ele]) -end - -local function comp_2ele_func(op, ele) -- make a 2 element comparison function, - --sort with function on element nnum - return bind(compare_elements, _1, _2, op, ele) -end - - - - - --- table stuff below - - -function pl.tablex.map_slice(func, T, j1, j2) - if type(j1) == 'string' then - return pl.array2d.map_slice(func, {T}, ','..j1)[1] - else - return pl.array2d.map_slice(func, {T}, 1, j1, 1, j2)[1] - end -end - -pl.array2d.map_slice1 = pl.tablex.map_slice - - --- todo option for multiple filters with AND logic, like the filter files?? -function pl.tablex.filterstr(t, exp, case) - -- case = case sensitive - case = pl.hasval(case) - -- apply lua patterns to a table to filter iter - -- str or table of str's can be passed, OR logic is used if table is passed - if case then - return pl.tablex.filter(t, bind(string.containsany,_1,exp)) - else - return pl.tablex.filter(t, bind(string.containsanycase,_1,exp)) - end -end - - -function pl.utils.filterfiles(...) - -- f1 is a series of filtering patterns, or condition - -- f2 is a series of filtering patters, or condition - -- (f1_a or f2_...) and (f2 .. ) must match - local args = table.pack(...) - -- todo -- check where boolean is for recursive or not, set starting argument - -- this could allow one to omit dir - -- todo if no boolean at all, assume dir = '.' and r = false - -- if boolean given, assume dir = '.' - local nstart = 3 - local r = args[2] - local dir = args[1] - if type(args[1]) == 'boolean' then - dir = '.' - r = args[1] - nstart = 2 - elseif type(args[2]) ~= 'boolean' then - dir = '.' - r = false - nstart = 1 - end - - local files - if r then files = pl.dir.getallfiles(dir) - else files = pl.dir.getfiles(dir) - end - for i=nstart,args.n do - files = pl.tablex.filter(files, pl.func.compose(bind(string.containsanycase,_1, args[i]), pl.path.basename)) - end - return files -end - - - - --- -- -- -- -- -- -- -- functions below extend the array2d module - - -function pl.array2d.map_slice(func, M, i1, j1, i2, j2) -- map a function to a slice of a Matrix - func = pl.utils.function_arg(1, func) - for i,j in pl.array2d.iter(M, true, i1, j1, i2, j2) do - M[i][j] = func(M[i][j]) - end - return M -end - -pl.array2d.map_slice2 = pl.array2d.map_slice - -function pl.array2d.map_cols(func, M, j1, j2) -- map function to columns of matrix - if type(j1) == 'string' then - return pl.array2d.map_slice(func, M, ','..j1) - else - j2 = j2 or -1 - return pl.array2d.map_slice(func, M, 1, j1, -1, j2) - end -end - -pl.array2d.map_columns = pl.array2d.map_cols - -function pl.array2d.map_rows(func, M, i1, i2) -- map function to rows of matrix - if type(i1) == 'string' then - return pl.array2d.map_slice(func, M, i1) - else - i2 = i2 or -1 - return pl.array2d.map_slice(func, M, i1, 1, i2, -1) - end -end - - --- -- -- -- -- -- -- -- - -function pl.array2d.sortOP(M, op, ele) -- sort a 2d array based on operator criteria, ele is column, ie sort on which element - M_new = {} - for row in pl.seq.sort(M, comp_2ele_func(op, ele)) do - M_new[#M_new+1] = row - end - return M_new -end - -function pl.array2d.like(M1, v) - v = v or 0 - r, c = pl.array2d.size(M1) - return pl.array2d.new(r,c,v) -end - -function pl.array2d.from_table(t) -- turns a labelled table to a 2d, label-free array - t_new = {} - for k, v in pairs(t) do - if type(v) == 'table' then - t_new_row = {k} - for _, v_ in ipairs(v) do - t_new_row[#t_new_row+1] = v_ - end - t_new[#t_new+1] = t_new_row - else - t_new[#t_new+1] = {k, v} - end - end - return t_new -end - -function pl.array2d.toTeX(M, EL) --puts & between columns, can choose to end line with \\ if EL is true (end-line) - EL = EL or false - if EL then EL = '\\\\' else EL = '' end - return pl.array2d.reduce2(_1..EL.._2, _1..'&'.._2, M)..EL -end - - -local function parse_numpy1d(i1, i2, iS) - i1 = tonumber(i1) - i2 = tonumber(i2) - if iS == ':' then - if i1 == nil then i1 = 1 end - if i2 == nil then i2 = -1 end - else - if i1 == nil then - i1 = 1 - i2 = -1 - else - i2 = i1 - end - end - return i1, i2 -end - -function pl.array2d.parse_numpy2d_str(s) - s = s:gsub('%s+', '') - _, _, i1, iS, i2, j1, jS, j2 = string.find(s, "(%-?%d*)(:?)(%-?%d*),?(%-?%d*)(:?)(%-?%d*)") - i1, i2 = parse_numpy1d(i1, i2, iS) - j1, j2 = parse_numpy1d(j1, j2, jS) - return i1, j1, i2, j2 -end - - -local _parse_range = pl.clone_function(pl.array2d.parse_range) - -function pl.array2d.parse_range(s) -- edit parse range to do numpy string if no letter passed - pl.utils.assert_arg(1,s,'string') - if not s:find'%a' then - return pl.array2d.parse_numpy2d_str(s) - end - return _parse_range(s) -end - - - - - - --- https://tex.stackexchange.com/questions/38150/in-lualatex-how-do-i-pass-the-content-of-an-environment-to-lua-verbatim -pl.tex.recordedbuf = "" -function pl.tex.readbuf(buf) - i,j = string.find(buf, '\\end{%w+}') - if i==nil then -- if not ending an environment - pl.tex.recordedbuf = pl.tex.recordedbuf .. buf .. "\n" - return "" - else - return nil - end -end - -function pl.tex.startrecording() - pl.tex.recordedbuf = "" - luatexbase.add_to_callback('process_input_buffer', pl.tex.readbuf, 'readbuf') -end - -function pl.tex.stoprecording() - luatexbase.remove_from_callback('process_input_buffer', 'readbuf') - pl.tex.recordedbuf = pl.tex.recordedbuf:gsub("\\end{%w+}\n","") -end - - - -__PDFmetadata__ = {} -pl.tex.add_xspace_intext = true - - -function pl.tex.updatePDFtable(k, v, o) -- key val overwrite - k = k:upfirst() - if pl.hasval(o) or (__PDFmetadata__[k] == nil) then - __PDFmetadata__[k] = v - end -end - -pl.tex.writePDFmetadata = function(t) -- write PDF metadata to xmpdata file - t = t or __PDFmetadata__ - local str = '' - for k, v in pairs(t) do - k = k:upfirst() - str = str..'\\'..k..'{'..v..'}'..'\n' - end - pl.utils.writefile(tex.jobname..'.xmpdata', str) -end - - - -function pl.tex.clear_cmds_str(s) - return s:gsub('%s+', ' '):gsub('\\\\',' '):gsub('\\%a+',''):gsub('{',' '):gsub('}',' '):gsub('%s+',' '):strip() -end - -function pl.tex.makePDFvarstr(s) - s = s:gsub('%s*\\sep%s+','\0'):gsub('%s*\\and%s+','\0') -- turn \and into \sep - s = pl.tex.clear_cmds_str(s) - s = s:gsub('\0','\\sep ') - --pl.tex.help_wrt(s,'PDF var string') - return s -end - -function pl.tex.makeInTextstr(s) - local s, c_and = s:gsub('%s*\\and%s+','\0') - s = pl.tex.clear_cmds_str(s) - if pl.tex.add_xspace_intext then - s = s..'\\xspace' - end - if c_and == 1 then - s = s:gsub('\0',' and ') - elseif c_and > 1 then - s = s:gsub('\0',', ', c_and - 1) - s = s:gsub('\0',', and ') - end - --pl.tex.help_wrt(s,'in text var string') - return s -end - ---todo decide on above or below - -function pl.tex.list2comma(t) - local s = '' - if #t == 1 then - s = t[1] - elseif #t == 2 then - s = t:join(' and ') - elseif #t >= 3 then - s = t:slice(1,#t-1):join(', ')..', and '..t[#t] - end - return s -end - -function pl.tex.split2comma(s, d) - local t = pl.List(s:split(d)):map(string.strip) - pl.tex.prt(pl.tex.list2comma(t)) -end - -function pl.tex.split2items(s, d) - local t = pl.List(s:split(d)):map(string.strip) - for n, v in ipairs(t) do - pl.tex.prtn('\\item '..v) - end -end - - - -if pl.hasval(__PL_GLOBALS__) then - __PL_EXTRAS__ = 2 - -- iterators - kpairs = pl.utils.kpairs - npairs = pl.utils.npairs - --enum = utils.enum - - for k,v in pairs(pl.tablex) do -- extend the table table to contain tablex functions - if k == 'sort' then - table.sortk = v - elseif k == 'move' then - table.xmove = v - else - _G['table'][k] = v - 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 - - -- shortcuts --- http://stevedonovan.github.io/Penlight/api/libraries/pl.utils.html - pl.writefile = pl.utils.writefile - pl.readfile = pl.utils.readfile - pl.readlines = pl.utils.readfile - pl.filterfiles = pl.utils.filterfiles - - pl.a2 = pl.array2d - pl.tbl = pl.tablex - - - for k,v in pairs(pl.tex) do -- make tex functions global - _G[k] = v - end - -end - - - - - - --_xTrue = pl.tex._xTrue - --_xFalse = pl.tex._xFalse - --_xNoValue = pl.tex._xNoValue - -- - --prt = pl.tex.prt - --prtn = pl.tex.prtn - --wrt = pl.tex.wrt - --wrtn = pl.tex.wrtn - -- - --prtl = pl.tex.prtl - --prtt = pl.tex.prtt - -- - --help_wrt = pl.tex.help_wrt - --prt_array2d = pl.tex.prt_array2d - -- - --pkgwarn = pl.tex.pkgwarn - --pkgerror = pl.tex.pkgerror - -- - --defcmd = pl.tex.defcmd - --prvcmd = pl.tex.prvcmd - --newcmd = pl.tex.newcmd - --renewcmd = pl.tex.renewcmd - --deccmd = pl.tex.deccmd - -- - --_NumBkts = pl.tex._NumBkts - --opencmd = pl.tex.opencmd - --reset_bkt_cnt = pl.tex.reset_bkt_cnt - --add_bkt_cnt = pl.tex.add_bkt_cnt - --close_bkt_cnt = pl.tex.close_bkt_cnt - - --- graveyard - - --- luakeys parses individual keys as ipairs, this changes the list to a pure map ---function pl.luakeystomap(t) --- local t_new = {} --- for k, v in pairs(t) do --- if type(k) == 'number' then --- t_new[v] = true --- else --- t_new[k] = v --- end --- end --- return t_new ---end ---if luakeys then -- if luakeys is already loaded --- function luakeys.parseN(s, ...) --- local t = luakeys.parse(s,...) --- t = pl.luakeystomap(t) --- return t --- end ---end --- might not be needed - - - --local func = check_func(func) ---local function check_func(func) -- check if a function is a PE, if so, make it a function --- if type(func) ~= 'function' then --- return I(func) --- end --- return func ---end - --- -- -- -- -- -- -- --- -- -- -- functions below extend the array2d module - - ---function pl.array2d.map_slice1(func, L, i1, i2) -- map a function to a slice of an array, can use PlcExpr --- i2 = i2 or i1 --- local len = #L --- i1 = check_index(i1, len) --- i2 = check_index(i2, len) --- func = check_func(func) --- for i in pl.seq.range(i1,i2) do --- L[i] = func(L[i]) --- end --- return L ---end - - -- used this below when iter was not working.. - --i1, j1, i2, j2 = check_slice(M, i1, j1, i2, j2) - --for i in pl.seq.range(i1,i2) do - -- for j in pl.seq.range(j1,j2) do - --end - -- penlight may have fixed this ---local function check_index(ij, rc) -- converts array index to positive value if negative --- if type(ij) ~= 'number' then --- return 1 --- else --- if ij < 0 then --- ij = rc + ij + 1 --- elseif ij > rc then --- ij = rc --- elseif ij == 0 then --- ij = 1 --- end --- return ij --- end ---end ---local function check_slice(M, i1, j1, i2, j2) -- ensure a slice is valid; i.e. all positive numbers --- r, c = pl.array2d.size(M) --- i1 = check_index(i1 or 1, r) --- i2 = check_index(i2 or r, r) --- j1 = check_index(j1 or 1, c) --- j2 = check_index(j2 or c, c) --- return i1, j1, i2, j2 ---end - |