texlive[68037] Master: penlightplus

commits+karl at tug.org commits+karl at tug.org
Wed Aug 23 23:18:46 CEST 2023


Revision: 68037
          http://tug.org/svn/texlive?view=revision&revision=68037
Author:   karl
Date:     2023-08-23 23:18:46 +0200 (Wed, 23 Aug 2023)
Log Message:
-----------
penlightplus

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/luatex/penlightplus/
    trunk/Master/texmf-dist/doc/luatex/penlightplus/README.md
    trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf
    trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.tex
    trunk/Master/texmf-dist/tex/luatex/penlightplus/
    trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
    trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
    trunk/Master/tlpkg/tlpsrc/penlightplus.tlpsrc

Added: trunk/Master/texmf-dist/doc/luatex/penlightplus/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/penlightplus/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/luatex/penlightplus/README.md	2023-08-23 21:18:46 UTC (rev 68037)
@@ -0,0 +1,28 @@
+# penlightplus
+
+Additions to the Penlight Lua Libraries.
+
+
+# License
+
+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
+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.


Property changes on: trunk/Master/texmf-dist/doc/luatex/penlightplus/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf	2023-08-23 21:11:53 UTC (rev 68036)
+++ trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf	2023-08-23 21:18:46 UTC (rev 68037)

Property changes on: trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.tex	2023-08-23 21:18:46 UTC (rev 68037)
@@ -0,0 +1,227 @@
+% Kale Ewasiuk (kalekje at gmail.com)
+% 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
+% 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.
+
+
+\documentclass[11pt,parskip=half]{scrartcl}
+\setlength{\parindent}{0ex}
+\newcommand{\llcmd}[1]{\leavevmode\llap{\texttt{\detokenize{#1}}}}
+\newcommand{\cmd}[1]{\texttt{\detokenize{#1}}}
+\newcommand{\qcmd}[1]{``\cmd{#1}''}
+\usepackage{url}
+\usepackage{xcolor}
+\usepackage{showexpl}
+\lstset{explpreset={justification=\raggedright,pos=r,wide=true}}
+\setlength\ResultBoxRule{0mm}
+\lstset{
+	language=[LaTeX]TeX,
+	basicstyle=\ttfamily\small,
+	commentstyle=\ttfamily\small\color{gray},
+	frame=none,
+	numbers=left,
+	numberstyle=\ttfamily\small\color{gray},
+	prebreak=\raisebox{0ex}[0ex][0ex]{\color{gray}\ensuremath{\hookleftarrow}},
+	extendedchars=true,
+	breaklines=true,
+	tabsize=4,
+}
+\addtokomafont{title}{\raggedright}
+\addtokomafont{author}{\raggedright}
+\addtokomafont{date}{\raggedright}
+\author{Kale Ewasiuk (\url{kalekje at gmail.com})}
+\usepackage[yyyymmdd]{datetime}\renewcommand{\dateseparator}{--}
+\date{\today}
+
+
+\RequirePackage{penlightplus}
+
+\title{penlightplus}
+\subtitle{Additions to the Penlight Lua Libraries}
+
+\begin{document}
+%
+
+\maketitle
+
+This package first loads the \cmd{[import]penlight} package.\\
+The \texttt{pl} option may be passed to this package to create an alias for \cmd{penlight}.\\
+\texttt{globals} option may be used to make several of the functions global (as discussed below).
+
+\subsection*{texlua usage}
+If you want to use penlightplus.lua  with the \texttt{texlua} interpreter
+(no document is made, but useful for testing your Lua code),
+you can access it by setting \cmd{__SKIP_TEX__ = true} before loading. For example:
+ \begin{verbatim}
+package.path = package.path .. ';'..'path/to/texmf/tex/latex/penlightplus/?.lua'
+package.path = package.path .. ';'..'path/to/texmf/tex/latex/penlight/?.lua'
+penlight = require'penlight'
+
+__SKIP_TEX__ = true  --only required if you want to use
+                     --penlightplus without a LaTeX run
+__PL_GLOBALS__ = true -- optional, include global definitions
+require'penlightplus'
+\end{verbatim}
+
+
+
+
+
+
+\subsection*{}
+
+The following global variables are defined:
+
+\llcmd{__SKIP_TEX__} If using the \cmd{penlightplus} package with \cmd{texlua} (good for troubleshooting), set this global before loading \cmd{penlight}\\
+The gloals flags below are taken care of in the package options:\\
+\llcmd{__PL_}\cmd{GLOBALS__} If using package with \cmd{texlua} and you don't want to set some globals (described in next sections), set this global before to \cmd{true} loading \cmd{penlight}\\
+\cmd{__PL_NO_HYPERREF__} a flag used to change the behaviour of a function, depending on if you don't use the hyperref package\\
+
+\subsubsection*{penlight additions}
+
+Some functionality is added to penlight/lua.
+
+\llcmd{pl.hasval(x)} Python-like boolean testing\\
+\llcmd{COMP'xyz'()} Python-like comprehensions:\\\url{https://lunarmodules.github.io/Penlight/libraries/pl.comprehension.html}\\
+\llcmd{math.mod(n,d)}, \cmd{math.mod2(n)} math modulous\\
+\llcmd{string.}\cmd{totable(s)} string a table of characters\\
+\llcmd{string.}\cmd{delspace(s)} clear spaces from string\\
+\llcmd{pl.}\cmd{char(n)} return letter corresponding to 1=a, 2=b, etc.\\
+\llcmd{pl.}\cmd{Char(n)} return letter corresponding to 1=A, 2=B, etc.\\
+
+\llcmd{pl.utils.}\cmd{filterfiles}\cmd{(dir,filt,rec)} Get files from dir and apply glob-like filters. Set rec to \cmd{true} to include sub directories\\
+
+
+\subsubsection*{A \cmd{pl.tex.} module is added}
+\llcmd{add_bkt}\cmd{_cnt(n), }\cmd{close_bkt_cnt(n), reset_bkt_cnt} functions to keep track of adding curly brackets as strings. \cmd{add} will return \cmd{n} (default 1) \{'s and increment a counter. \cmd{close} will return \cmd{n} \}'s (default will close all brackets) and decrement.\\
+\llcmd{_NumBkts} internal integer for tracking the number of brackets\\
+\llcmd{opencmd(cs)} prints \cmd{\cs}\{ and adds to the bracket counters.\\
+\\
+\llcmd{_xNoValue,}\cmd{_xTrue,_xFalse}: \cmd{xparse} equivalents for commands\\
+\\
+\llcmd{prt(x),prtn(x)} print without or with a newline at end. Tries to help with special characters or numbers printing.\\
+\llcmd{prtl(l),prtt(t)} print a literal string, or table\\
+\llcmd{wrt(x), wrtn(x)} write to log\\
+\llcmd{help_wrt}\cmd{(s1, s2)} pretty-print something to console. S2 is a flag to help you find.\\
+\llcmd{prt_array2d(tt)} pretty print a 2d array\\
+\\
+\llcmd{pkgwarn}\cmd{(pkg, msg1, msg2)} throw a package warning\\
+\llcmd{pkgerror}\cmd{(pkg, msg1, msg2, stop)} throw a package error. If stop is true, immediately ceases compile.\\
+\\
+\llcmd{defcmd}\cmd{(cs, val)} like \cmd{\gdef}\\
+\llcmd{newcmd}\cmd{(cs, val)} like \cmd{\newcommand}\\
+\llcmd{renewcmd}\cmd{(cs, val)} like \cmd{\renewcommand}\\
+\llcmd{prvcmd}\cmd{(cs, val)} like \cmd{\providecommand}\\
+\llcmd{deccmd}\cmd{(cs, dft, overwrite)} declare a command. If \cmd{dft} (default) is \cmd{nil}, \cmd{cs} is set
+to a package warning saying \cmd{'cs' was declared and used in document, but never set}. If \cmd{overwrite}
+is true, it will overwrite an existing command (using \cmd{defcmd}), otherwise, it will throw error like \cmd{newcmd}.\\
+\llcmd{get_ref_info(l)}accesses the \cmd{\r at label} and returns a table\\
+
+
+
+\subsubsection*{global extras}
+If \cmd{extrasglobals} is used and NOT \cmd{extras}, many additional globals are set for shortcuts\\
+All \cmd{pl.tex} modules are made global.\\
+\cmd{pl.hasval}, \cmd{pl.COMP}, \cmd{pl.utils.kpairs}, \cmd{pl.utils.npairs} become globals with the function name.\\
+
+
+
+\subsection*{Macro helpers}
+\cmd{\MakeluastringCommands[def]{spec}} will let \cmd{\plluastring(A|B|C..)} be \cmd{\luastring(N|O|T|F)}
+based on the letters that \cmd{spec} is set to (or \cmd{def} if nothing is provided)
+This is useful if you want to write a command with flexibility on argument expansion.
+The user can specify \cmd{n}, \cmd{o}, \cmd{t}, and \cmd{f} (case insensitve) if they want
+no, once, twice, or full expansion.
+
+%   BELOW IS FOR TROUBLESHOOTING ABOVE
+%\def\NOTexp{\ONEexp}
+%\def\ONEexp{\TWOexp}
+%\def\TWOexp{\TREexp}
+%\def\TREexp{Fully expanded}
+%
+%\NewDocumentCommand{\luastringExpTest}{m m}{
+%  \MakeluastringCommands{#1}
+%  \luadirect{texio.write_nl('VVVVVVVVVVVVVVVVVVVVVVVVVVVVV')}
+%  \luadirect{texio.write_nl(\plluastringA{#2}..' | Not')}
+%  \luadirect{texio.write_nl(\plluastringB{#2}..' | Once')}
+%  \luadirect{texio.write_nl(\plluastringC{#2}..' | Twice')}
+%  \luadirect{texio.write_nl(\plluastringD{#2}..' | Full')}
+%  \luadirect{texio.write_nl('VVVVVVVVVVVVVVVVVVVVVVVVVVVVV')}
+%}
+%
+%\luastringExpTest{ n o t f }{\NOTexp}
+
+
+
+
+\subsection*{Split stuff}
+Splitting text (or a cmd) into oxford comma format via:
+\cmd{\splitToComma[expansion level]{text}{text to split on}}:
+
+\begin{LTXexample}
+
+-\splitToComma{  j doe  }{\and}-\\
+-\splitToComma{  j doe \and s else  }{\and}-\\
+-\splitToComma{  j doe \and s else \and a per }{\and}-\\
+-\splitToComma{  j doe \and s else \and a per \and f guy}{\and}-
+
+\def\authors{j doe \and s else \and a per \and f guy}
+\splitToComma[o]{\authors}{\and}
+\end{LTXexample}
+
+The expansion level is up to two characters, \cmd{n|o|t|f}, to control teh expasion of each argument.
+
+\begin{LTXexample}
+spliToItems:
+\begin{itemize}
+  \splitToItems{kale\and john}{\and}
+  \splitToItems{kale -john -someone else}{-}
+\end{itemize}
+\end{LTXexample}
+
+
+
+
+
+
+%  \tblfrkv{tbl_def}{kale=cool,paul=gay,craig=fun}
+%  \tblfrkv{tbl}{kale,paul=gay} %[naked_as_value=true]
+%
+%  \tblget{tbl}{kale}%
+%  \tblget{tbl}{paul}%
+%  \tblget{tbl}{craig}%
+%
+%  \tblupd{tbl_def}{tbl}%
+%
+%  \tblfrkvII{tbl}{kale=cool,paul=gay,craig=fun}{kale=weak,paul=sad}
+%  \tblget{tbl}{craig}%
+%  \tblget{tbl}{paul}%
+%  \tblget{tbl}{kale}%
+%
+%  \NewDocumentCommand{\THINg}{ O{} m}{%
+%    \tblfrkvII{setti}{color=red,size=small}{#1} % make settings and update based on [arg=]
+%    {\color{\tblget{setti}{color}}\tblget{setti}{size} #2}
+%  }
+%
+%  \THINg[color=blue,size=tiny]{Kale}
+  
+\end{document}
\ No newline at end of file


Property changes on: trunk/Master/texmf-dist/doc/luatex/penlightplus/penlightplus.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua	2023-08-23 21:18:46 UTC (rev 68037)
@@ -0,0 +1,927 @@
+--% Kale Ewasiuk (kalekje at gmail.com)
+--% 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
+--% 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_PLUS__ = true
+__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_GLOBALS__ = __PL_GLOBALS__ or false
+__PL_NO_HYPERREF__ = __PL_NO_HYPERREF__ or false
+
+
+penlight.luakeys = require'luakeys'()
+
+
+penlight.COMP = require'pl.comprehension'.new() -- for comprehensions
+
+-- http://lua-users.org/wiki/SplitJoin -- todo read me!!
+
+penlight.tex = {} -- adding a sub-module for tex related stuff
+
+local bind = bind or penlight.func.bind
+
+
+function penlight.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
+penlight.tex._xTrue = '\\BooleanTrue '
+penlight.tex._xFalse = '\\BooleanFalse '
+penlight.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
+                penlight.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 penlight.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 penlight.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
+
+    penlight.tex.wrt = texio.write
+    penlight.tex.wrtn = texio.write_nl
+else
+    penlight.tex.prt = io.write
+    penlight.tex.prtn = print     --print with new line
+    penlight.tex.wrt = io.write
+    penlight.tex.wrtn = io.write_nl
+end
+
+function penlight.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
+        penlight.tex.prtn(line)
+    end
+end
+
+-- todo option to specify between character? one for first table, on for recursives?
+function penlight.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
+                penlight.tex.prtn(t)
+            else
+                penlight.tex.prt(t, d1)
+            end
+         else
+            penlight.tex.prtn(d2)
+            penlight.tex.prtt(t,d1,d2)
+        end
+    end
+end
+
+function penlight.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(penlight.pretty.write(s1))
+    else
+        wrt2(tostring(s1))
+    end
+    wrt2('\n^^^^^\n')
+end
+penlight.help_wrt = penlight.tex.help_wrt
+
+function penlight.tex.prt_array2d(t)
+    for _, r in ipairs(t) do
+        local s = ''
+        for _, v in ipairs(r) do
+            s = s.. tostring(v)..', '
+        end
+        penlight.tex.prt(s)
+        penlight.tex.prt('\n')
+    end
+end
+
+-- -- -- -- --
+
+function penlight.tex.pkgwarn(pkg, msg1, msg2)
+    pkg = pkg or ''
+    msg1 = msg1 or ''
+    msg2 = msg2 or ''
+    tex.sprint('\\PackageWarning{'..pkg..'}{'..msg1..'}{'..msg2..'}')
+end
+
+function penlight.tex.pkgerror(pkg, msg1, msg2, stop)
+    pkg = pkg or ''
+    msg1 = msg1 or ''
+    msg2 = msg2 or ''
+    stop = penlight.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 penlight.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 penlight.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 penlight.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 penlight.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
+        penlight.tex.defcmd(cs, val)
+    end
+end
+
+function penlight.tex.newcmd(cs, val) -- provide command via lua
+   if token.is_defined(cs) then
+       penlight.tex.pkgerror('penlight: newcmd',cs..' already defined')
+    else
+        penlight.tex.defcmd(cs, val)
+    end
+end
+
+function penlight.tex.renewcmd(cs, val) -- provide command via lua
+   if token.is_defined(cs) then
+        penlight.tex.defcmd(cs, val)
+    else
+        penlight.tex.pkgerror('penlight: renewcmd',cs..' not defined')
+    end
+end
+
+function penlight.tex.deccmd(cs, def, overwrite) -- declare a definition, placeholder throws an error if it used but not set!
+    overwrite = penlight.hasval(overwrite)
+    local decfun
+    if overwrite then decfun = penlight.tex.defcmd else decfun = penlight.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
+penlight.tex._NumBkts = 0
+--prt(opencmd('textbf')..opencmd('texttt')..'bold typwriter'..close_bkt_cnt())
+
+function penlight.tex.opencmd(cmd)
+    return '\\'..cmd..add_bkt_cnt()
+end
+
+function penlight.tex.reset_bkt_cnt(n)
+     n = n or 0
+    _NumBkts = n
+end
+
+function penlight.tex.add_bkt_cnt(n)
+    -- add open bracket n times, returns brackets
+     n = n or 1
+    _NumBkts = _NumBkts + n
+    return ('{'):rep(n)
+end
+
+function penlight.tex.close_bkt_cnt(n)
+    n = n or _NumBkts
+    local s = ('}'):rep(n)
+    _NumBkts = _NumBkts - n
+    return s
+end
+
+
+
+function penlight.tex.aliasluastring(s, d)
+    s = s:delspace():upper():tolist()
+    d = d:delspace():upper():tolist()
+    for i, S in penlight.seq.enum(d:slice_assign(1,#s,s)) do
+        if (S == 'E') or (S == 'F') then S = '' end  -- E or F is fully expanded
+        penlight.tex.prtn('\\let\\plluastring'..penlight.Char(i)..'\\luastring'..S)
+    end
+end
+
+
+
+
+
+function penlight.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 = penlight.tablex.new(n, 0)  -- make all 0s
+        r = '-not found-'
+    else
+        t = {r:match(("(%b{})"):rep(n))}
+        t = penlight.tablex.map(string.trimfl, t)
+    end
+    t[#t+1] = r -- add the og return of label
+    --penlight.help_wrt(t, 'ref info')
+    return t
+end
+
+-- todo add regex pattern for cref info
+--function penlight.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 penlight.char(num)
+  return string.char(string.byte("a")+num-1)
+end
+
+function penlight.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 penlight.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 penlight.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 penlight.operator.strgt(a,b) return tostring(a) > tostring(b) end
+function penlight.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 penlight.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 penlight.tablex.map_slice(func, T, j1, j2)
+    if type(j1) == 'string' then
+        return penlight.array2d.map_slice(func, {T}, ','..j1)[1]
+    else
+        return penlight.array2d.map_slice(func, {T}, 1, j1, 1, j2)[1]
+    end
+end
+
+penlight.array2d.map_slice1 = penlight.tablex.map_slice
+
+
+-- todo option for multiple filters with AND logic, like the filter files??
+function penlight.tablex.filterstr(t, exp, case)
+    -- case = case sensitive
+    case = penlight.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 penlight.tablex.filter(t, bind(string.containsany,_1,exp))
+    else
+        return penlight.tablex.filter(t, bind(string.containsanycase,_1,exp))
+    end
+end
+
+
+function penlight.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 = penlight.dir.getallfiles(dir)
+    else files = penlight.dir.getfiles(dir)
+    end
+    for i=nstart,args.n do
+        files = penlight.tablex.filter(files, penlight.func.compose(bind(string.containsanycase,_1, args[i]), penlight.path.basename))
+    end
+    return  files
+end
+
+
+
+
+-- -- -- -- -- -- -- --  functions below extend the array2d module
+
+
+function penlight.array2d.map_slice(func, M, i1, j1, i2, j2) -- map a function to a slice of a Matrix
+    func = penlight.utils.function_arg(1, func)
+    for i,j in penlight.array2d.iter(M, true, i1, j1, i2, j2) do
+        M[i][j] = func(M[i][j])
+    end
+   return M
+end
+
+penlight.array2d.map_slice2 = penlight.array2d.map_slice
+
+function penlight.array2d.map_cols(func, M, j1, j2) -- map function to columns of matrix
+    if type(j1) == 'string' then
+        return penlight.array2d.map_slice(func, M, ','..j1)
+    else
+        j2 = j2 or -1
+        return penlight.array2d.map_slice(func, M, 1, j1, -1, j2)
+    end
+end
+
+penlight.array2d.map_columns = penlight.array2d.map_cols
+
+function penlight.array2d.map_rows(func, M, i1, i2) -- map function to rows of matrix
+    if type(i1) == 'string' then
+        return penlight.array2d.map_slice(func, M, i1)
+    else
+        i2 = i2 or -1
+        return penlight.array2d.map_slice(func, M, i1, 1, i2, -1)
+    end
+end
+
+
+-- -- -- -- -- -- -- --
+
+function penlight.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 penlight.seq.sort(M, comp_2ele_func(op, ele)) do
+            M_new[#M_new+1] = row
+        end
+        return M_new
+end
+
+function penlight.array2d.like(M1, v)
+    v = v or 0
+    r, c = penlight.array2d.size(M1)
+    return penlight.array2d.new(r,c,v)
+end
+
+function penlight.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 penlight.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 penlight.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 penlight.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 = penlight.clone_function(penlight.array2d.parse_range)
+
+function penlight.array2d.parse_range(s) -- edit parse range to do numpy string if no letter passed
+    penlight.utils.assert_arg(1,s,'string')
+    if not s:find'%a' then
+        return penlight.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
+penlight.tex.recordedbuf = ""
+function penlight.tex.readbuf(buf)
+    i,j = string.find(buf, '\\end{%w+}')
+     if i==nil then -- if not ending an environment
+        penlight.tex.recordedbuf = penlight.tex.recordedbuf .. buf .. "\n"
+        return ""
+    else
+        return nil
+    end
+end
+
+function penlight.tex.startrecording()
+    penlight.tex.recordedbuf = ""
+    luatexbase.add_to_callback('process_input_buffer', penlight.tex.readbuf, 'readbuf')
+end
+
+function penlight.tex.stoprecording()
+    luatexbase.remove_from_callback('process_input_buffer', 'readbuf')
+    penlight.tex.recordedbuf = penlight.tex.recordedbuf:gsub("\\end{%w+}\n","")
+end
+
+
+
+__PDFmetadata__ = {}
+penlight.tex.add_xspace_intext = true
+
+
+function penlight.tex.updatePDFtable(k, v, o) -- key val overwrite
+    k = k:upfirst()
+    if penlight.hasval(o) or (__PDFmetadata__[k] == nil) then
+        __PDFmetadata__[k] = v
+    end
+end
+
+penlight.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
+  penlight.utils.writefile(tex.jobname..'.xmpdata', str)
+end
+
+
+
+function penlight.tex.clear_cmds_str(s)
+    return s:gsub('%s+', ' '):gsub('\\\\',' '):gsub('\\%a+',''):gsub('{',' '):gsub('}',' '):gsub('%s+',' '):strip()
+end
+
+function penlight.tex.makePDFvarstr(s)
+    s = s:gsub('%s*\\sep%s+','\0'):gsub('%s*\\and%s+','\0')  -- turn \and into \sep
+    s = penlight.tex.clear_cmds_str(s)
+    s = s:gsub('\0','\\sep ')
+    --penlight.tex.help_wrt(s,'PDF var string')
+    return s
+end
+
+function penlight.tex.makeInTextstr(s)
+    local s, c_and = s:gsub('%s*\\and%s+','\0')
+    s = penlight.tex.clear_cmds_str(s)
+    if penlight.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
+    --penlight.tex.help_wrt(s,'in text var string')
+    return s
+end
+
+--todo decide on above or below
+
+function penlight.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 penlight.tex.split2comma(s, d)
+    local t = penlight.List(s:split(d)):map(string.strip)
+    penlight.tex.prt(penlight.tex.list2comma(t))
+end
+
+function penlight.tex.split2items(s, d)
+    local t = penlight.List(s:split(d)):map(string.strip)
+    for n, v in ipairs(t) do
+        penlight.tex.prtn('\\item '..v)
+    end
+end
+
+
+
+if penlight.hasval(__PL_GLOBALS__) then
+    -- iterators
+    kpairs = penlight.utils.kpairs
+    npairs = penlight.utils.npairs
+    --enum = utils.enum
+
+    for k,v in pairs(penlight.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
+
+    penlight.tablex.concat = table.concat
+    penlight.tablex.insert = table.insert
+    penlight.tablex.maxn = table.maxn
+    penlight.tablex.remove = table.remove
+    penlight.tablex.sort = table.sort
+
+    hasval = penlight.hasval
+    COMP = penlight.COMP
+
+    -- shortcuts
+-- http://stevedonovan.github.io/Penlight/api/libraries/penlight.utils.html
+    penlight.writefile = penlight.utils.writefile
+    penlight.readfile = penlight.utils.readfile
+    penlight.readlines = penlight.utils.readfile
+    penlight.filterfiles = penlight.utils.filterfiles
+
+    penlight.a2 = penlight.array2d
+    penlight.tbl = penlight.tablex
+
+
+    for k,v in pairs(penlight.tex) do  -- make tex functions global
+        _G[k] = v
+    end
+
+end
+
+
+
+
+
+    --_xTrue = penlight.tex._xTrue
+    --_xFalse = penlight.tex._xFalse
+    --_xNoValue = penlight.tex._xNoValue
+    --
+    --prt = penlight.tex.prt
+    --prtn = penlight.tex.prtn
+    --wrt = penlight.tex.wrt
+    --wrtn = penlight.tex.wrtn
+    --
+    --prtl = penlight.tex.prtl
+    --prtt = penlight.tex.prtt
+    --
+    --help_wrt = penlight.tex.help_wrt
+    --prt_array2d = penlight.tex.prt_array2d
+    --
+    --pkgwarn = penlight.tex.pkgwarn
+    --pkgerror = penlight.tex.pkgerror
+    --
+    --defcmd = penlight.tex.defcmd
+    --prvcmd = penlight.tex.prvcmd
+    --newcmd = penlight.tex.newcmd
+    --renewcmd = penlight.tex.renewcmd
+    --deccmd = penlight.tex.deccmd
+    --
+    --_NumBkts = penlight.tex._NumBkts
+    --opencmd = penlight.tex.opencmd
+    --reset_bkt_cnt = penlight.tex.reset_bkt_cnt
+    --add_bkt_cnt = penlight.tex.add_bkt_cnt
+    --close_bkt_cnt = penlight.tex.close_bkt_cnt
+
+
+-- graveyard
+
+
+-- luakeys parses individual keys as ipairs, this changes the list to a pure map
+--function penlight.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 = penlight.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 penlight.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 penlight.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 penlight.seq.range(i1,i2) do
+    --    for j in penlight.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 = penlight.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
+


Property changes on: trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty	2023-08-23 21:18:46 UTC (rev 68037)
@@ -0,0 +1,119 @@
+% Kale Ewasiuk (kalekje at gmail.com)
+% 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
+% 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.
+
+\ProvidesPackage{penlightplus}[2023-07-22]
+
+\RequirePackage{luacode}
+\RequirePackage{luakeys}
+\RequirePackage[import]{penlight}
+
+\DeclareOption{globals}{\luadirect{__PL_GLOBALS__ = true}}
+\DeclareOption{pl}{\directlua{pl = penlight}}
+\ProcessOptions*\relax
+
+\luadirect{require'penlightplus'}
+
+
+
+
+\global\newcommand{\writePDFmetadata}{\luadirect{penlight.tex.writePDFmetadata()}}
+
+\NewDocumentCommand{\writePDFmetadatakv}{ s m }{
+\IfBooleanTF{#1}{% if *, overwrite everything
+  \luadirect{
+    __PDFmetadata__ = penlight.luakeys.parse(\luastring{#2})
+      penlight.tex.writePDFmetadata()
+  }}{
+    \luadirect{
+    __PDFmetadata__ = __PDFmetadata__ or {}
+    penlight.tablex.update(__PDFmetadata__, penlight.luakeys.parse(\luastring{#2}))
+    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{penlight.tex.aliasluastring(\luastring{#2},\luastring{#1})}%
+}
+
+\NewDocumentCommand{\splitToComma}{ O{nn} m m }{%
+  \MakeluastringCommands[nn]{#1}%
+  \luadirect{penlight.tex.split2comma(\plluastringA{#2},\plluastringB{#3})}%
+}
+
+\NewDocumentCommand{\splitToItems}{ O{NN} m m }{%
+  \MakeluastringCommands[nn]{#1}%
+  \luadirect{penlight.tex.split2items(\plluastringA{#2},\plluastringB{#3})}%
+}
+
+
+%
+%
+%\NewDocumentCommand{\tblnew}{m}{\luadirect{
+%  _G[\luastring{#1}] = {}
+%}}
+%
+%\NewDocumentCommand{\tblfrkv}{m m O{} }{\luadirect{
+%  _G[\luastring{#1}] = penlight.luakeys.parse(\luastring{#2}, penlight.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{
+%  penlight.tablex.update(_G[\luastring{#1}], _G[\luastring{#2}])
+%}}
+%
+%\NewDocumentCommand{\tblupdkv}{ m m }{\luadirect{
+%  penlight.tablex.update(_G[\luastring{#1}], penlight.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}] = penlight.tablex.update(penlight.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]
+%  penlight.tablex[\luastring[#1]](_G[\luastring{}], _G[\luastring{}])
+%}}
+
+


Property changes on: trunk/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2023-08-23 21:11:53 UTC (rev 68036)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2023-08-23 21:18:46 UTC (rev 68037)
@@ -638,7 +638,7 @@
     pdfpagediff pdfpages pdfpc pdfpc-movie pdfprivacy pdfreview
     pdfscreen pdfslide pdfsync
     pdftex-quiet pdftexcmds pdftricks pdftricks2 pdfx pdfxup
-    pecha pedigree-perl penlight perception perfectcut perltex
+    pecha pedigree-perl penlight penlightplus perception perfectcut perltex
     permute persian-bib
     petiteannonce petri-nets pfarrei pfdicons
     pgf pgf-blur pgf-interference pgf-periodictable pgf-pie

Modified: trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2023-08-23 21:11:53 UTC (rev 68036)
+++ trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2023-08-23 21:18:46 UTC (rev 68037)
@@ -89,6 +89,7 @@
 depend pdfarticle
 depend pdfextra
 depend penlight
+depend penlightplus
 depend piton
 depend placeat
 depend plantuml

Added: trunk/Master/tlpkg/tlpsrc/penlightplus.tlpsrc
===================================================================


More information about the tex-live-commits mailing list.