texlive[73266] Master: luatbls (1jan25)

commits+karl at tug.org commits+karl at tug.org
Wed Jan 1 21:55:40 CET 2025


Revision: 73266
          https://tug.org/svn/texlive?view=revision&revision=73266
Author:   karl
Date:     2025-01-01 21:55:39 +0100 (Wed, 01 Jan 2025)
Log Message:
-----------
luatbls (1jan25)

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

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

Added: trunk/Master/texmf-dist/doc/lualatex/luatbls/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luatbls/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luatbls/README.md	2025-01-01 20:55:39 UTC (rev 73266)
@@ -0,0 +1,27 @@
+# luatbls
+
+Lua tables made accessible in LaTeX
+
+# License
+
+Copyright (C) 2025 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/lualatex/luatbls/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.pdf	2025-01-01 20:55:05 UTC (rev 73265)
+++ trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.pdf	2025-01-01 20:55:39 UTC (rev 73266)

Property changes on: trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.tex
===================================================================
--- trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.tex	2025-01-01 20:55:39 UTC (rev 73266)
@@ -0,0 +1,410 @@
+% Kale Ewasiuk (kalekje at gmail.com)
+% 2025-01-01
+% Copyright (C) 2025 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}
+\usepackage[left=0.75in,right=0.75in,top=1in,bottom=1in]{geometry}
+\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[svgnames]{xcolor}
+\usepackage{showexpl}
+\lstset{explpreset={justification=\raggedright,pos=r,hsep=1cm,preset={\color{Navy}\small}}}
+\setlength\ResultBoxRule{0mm}
+\lstset{
+	language=[LaTeX]TeX,
+	basicstyle=\ttfamily\footnotesize\color{blue},
+	commentstyle=\ttfamily\footnotesize\color{gray},
+	frame=none,
+	numbers=left,
+	numberstyle=\ttfamily\footnotesize\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}
+
+\usepackage{enumitem}
+
+\RequirePackage{luatbls}
+
+\title{luatbls}
+\subtitle{Create, modify, and use Lua tables from within LaTeX}
+
+
+\begin{document}
+%
+
+\maketitle
+
+
+\subsection*{Introduction}
+
+This package provides a Lua-table interface based on the \cmd{luakeys} package:\\
+\url{https://mirror.quantum5.ca/CTAN/macros/luatex/generic/luakeys/luakeys.pdf}\\
+
+A global table called \cmd{luatbls} is created by loading this package. This table contains all user-defined tables
+as well as internal package functions and settings.
+User tables are stored directly under the module's table, so you can access a table within Lua by using:
+\cmd{luatbls['mytable']} or \cmd{luatbls.mytable}. Further, \cmd{luatbls} can be called directly to obtain a table item by \cmd{luatbls'i'},
+where \cmd{i} is a ``flexible'' indexing system discussed in the next paragraphs.
+
+If you want to change the \cmd{luakeys} global parser options, you can adjust them by:\\
+\cmd{\directlua{luatbls._luakeys.opts.OPTION = VALUE}}\\
+For debugging, set \cmd{\directlua{luatbls._debug = true}}
+
+
+In this documentation, arguments are represented as follows:\\
+\llcmd{t }: table name. If none provided, the most recent is used.\\
+\llcmd{k }: a string key.\\
+\llcmd{n }: an integer index.\\
+\llcmd{v }: a value.\\
+\llcmd{i }: the flexible indexer to get a single item.\\
+\llcmd{I }: the flexible indexer to get a single or multiple items.\\
+\llcmd{keyval }: a key-value string for the table. Standalone values are set to boolean.\\
+\llcmd{csv }: a key-value string where standalone values are parsed as array-like.
+
+There are a few ways to use the index (placeholder \cmd{i}.\\
+\cmd{t.k} where \cmd{t} is the table name and \cmd{k} is a string key (i.e. uses \cmd{luatbls.t.k}),\\
+\cmd{t/n} where \cmd{n} is an integer index (i.e. uses \cmd{t.k[n]}); note that negative indexes are allowed where -1 is the last element.
+Alternatively, \cmd{t} and the symbol can be omitted, and simply pass the element without the table name as a prefix,
+where the assumed table is the last one that was created or changed to (i.e. the most 'recent' table).
+In this case, passing a number will assume an integer index.
+
+To use a \cmd{I},
+you can explicitly select tables and groups of keys by \cmd{t|seq}, or \cmd{t.k}, or \cmd{t/n}.
+If no \cmd{|./} is provided, the recent table is used and the argument is assumed to be a sequence of keys.
+\cmd{penlightplus}'s command \cmd{penlight.seq.tbltrain()} syntax is used for \cmd{seq}uences.
+To summarize what \cmd{seq} can be, a comma-separated list of numbers or keys are used to specify which elements are iterated over.
+NumPy-like slicing is possibly with \cmd{:} to choose integer ranges.
+If \cmd{*} is provided,
+all string keys are iterated.
+If \cmd{I} is entirely blank, all elements of the recent table are used, which is equivalent to \cmd{t|*,:}.\\
+
+Note: nested tables are currently not fully supported. Some variations of commands have an \cmd{E} suffix which indicates
+that nested elements can be explicitly indexed.
+The table name must be specified, and the validity of table names and keys are not checked.
+
+The \cmd{tbl} commands fully expand the
+\cmd{t}, \cmd{k}, \cmd{n}, \cmd{i}, and \cmd{I} arguments. However a variation with an \cmd{N}-appended is usually provided
+which will not expand the \cmd{v}, \cmd{keyval}, or \cmd{csv} args.
+
+
+
+%%%
+\subsection*{Creating Tables}
+
+%\tblfrkv{kale}{kale=ewasiuk}
+%\luadirect{penlight.wrth(luatbls'kale.kale')}
+
+\cmd{\tblnew{t}} declares a new table with name \cmd{t}\\
+\cmd{\tblchg{t}} changes the 'recent' table\\
+\\
+\cmd{\tblfrkv{t}{keyval}[opts]} new table from key-vals using \cmd{luakeys} \\
+\cmd{\tblfrkvN{t}{keyval}[opts]} does not expand key-val string \cmd{luakeys} \\
+
+\cmd{\tblkvundefcheck} will throw an error if you use define a table from key-values
+and use a key that was not specified in the luakeys parse options via \cmd{opts.defaults} or \cmd{opts.defs}.\\
+\\
+ \cmd{\tblfrcsv{t}{csv}[opts]} a shorthand \cmd{\tblfrkv{t}{csv}[naked_as_value=true,opts]}, a good way to convert  a comma-separated list to an array\\
+ \cmd{\tblfrcsvN{t}{csv}[opts]} same as above, but the csv is not expanded.\\
+
+
+\subsection*{Setting, getting, and modifying}
+
+
+\cmd{\tblset{i}{v}} sets a value of the table/index \cmd{i} to \cmd{v}\\
+\cmd{\tblsetN{i}{v}} same as above, but the value is not expanded.\\
+\\
+\cmd{\tblget{i}} gets the value and \cmd{tex.sprint()}s it\\
+\cmd{\tblgetE{t.k}} An 'explicit' version of tbl get. Use this for nested tables. The tbl name must be specified.
+The validity of table names and keys are not checked.\\
+
+\begin{LTXexample}
+\tblfrkv{ex}{a,b,c,first=john,last=smith}%
+	[defaults={x=0,1=one,n=false,y=yes}]
+\tblget{ex.a}\\
+\tblset{a}{tRuE!!}
+\tblget{a}\\
+\tblget{ex.x}\\
+\tblget{.x}\\
+\tbladd{ex.newkey}{val}\tblget{newkey}\\
+\tbladd{nk}{VAL}\tblget{nk}\\
+\end{LTXexample}
+
+\begin{LTXexample}
+\tblfrcsv{EX}{x={1,2,{1,2,3}},name=me}
+\tblgetE{EX.x[1]}\\
+\tblgetE{EX.x[3][3]}\\
+\tblgetE{EX.name}\\
+\end{LTXexample}
+
+
+
+\cmd{\tbladd{i}{v}} add a new value to a table using index method\\
+\cmd{\tbladdN{i}{v}} above, but don't expand the value argument\\
+\\
+\cmd{\tblapp{t}{v}} append a \cmd{v}alue (integer-wise) to a \cmd{t}able\\
+\cmd{\tblappN{t}{v}}\\
+\\
+\cmd{\tblupd{t}{keyval}} update a \cmd{t}able with more \cmd{keyval}s\\
+\cmd{\tblupdN{t}{keyval}}\\
+\\
+\cmd{\tblcon{t}{csv}} concatenate array-style \cmd{csv} at the end of \cmd{t}\\
+\cmd{\tblconN{t}{csv}}\\
+
+
+
+\subsection*{Conditionals}
+
+\cmd{\tblif{i}{tr}[fa]} runs code \cmd{tr} if the item is true else \cmd{fa}\\
+\cmd{\tblifv{i}{tr}[fa]} runs code \cmd{tr} if the item is truth-y (using \cmd{pl.hasval}) else \cmd{fa}\\
+\cmd{\tblifeq{i}{v}{tr}[fa]} checks the equivalency of to a user-specified value. Quotes must be used to indicate strings.
+
+\begin{LTXexample}
+\tblfrcsv{x}{n=false,y=true,
+	k0="",kv=val,k2=6}
+\tblif{n}{tr}[FA]\\
+\tblif{k0}{TR}[fa]\\
+\tblifv{k0}{tr}[FA]\\
+\tblifeq{kv}{'val'}{TR}[fa]\\
+\tblifeq{k2}{6}{TR}[fa]\\
+\end{LTXexample}
+
+
+\subsection*{Iterating}
+%TODO use PIPE SYMBOLZ \dsadsa
+
+\cmd{\tblfor{I}{template}} and \cmd{\tblforN} By default, iterates over all elements (\cmd{seq = *,:}),
+but arbitrary indices/keys can be iterated over as per \cmd{penlight.seq.tbltrain} syntax.
+\cmd{<k>} and \cmd{<v>} are placeholders in the template that are replaced by the keys and vals and can be changed by:
+\cmd{\luadirect{luatbls._tblv = '<v>'}}
+
+If you want to iterate over a second-level tabel, you must use:\\
+\cmd{\tblforE} and \cmd{\tblforEN}, and explicitly provide the table and element.
+
+\begin{LTXexample}
+\tblfrcsv{x}{n1,k1=v1,n2,n3,n4,
+	     k2=v2,k3=v3,n5,n6}
+1> \tblfor{:}{<k> = <v>; }\\
+2> \tblfor{*}{<k> = <v>; }\\
+3> \tblfor{1,*,2::2}{<k> = <v>; }\\
+4> \tblfor{ x | 1,*,2::2}{<k> = <v>; }\\
+\tblfrcsv{x}{a,{a,b,c}}
+5> \tblforE{x[2]}{<k> = <v>; }
+\end{LTXexample}
+
+
+
+
+\subsection*{Definitions}
+\cmd{\tbldef{i}[cs]} pushes the value to macro \cmd{\cs}. If cs is not provided, a default cs name of \cmd{dtbl<t><k>} is used.\\
+\cmd{\tblgdef{i}[cs]} like above but global definition is used.\\
+
+\cmd{\tbldefs{I}[cspfx]} and \cmd{\tblgdefs{I}[cspfx]} defines items in table \cmd{t} (use recent if blank) with format \cmd{<cspfx><key>} where \cmd{cspfx} is a command sequence prefix.
+If \cmd{cspfx} is blank, keys will be defined as \cmd{dtbl<t><k>}.
+The default \cmd{cspfx} is changed by:\\\cmd{\luadirect{luatbls._cspfx = 'dtbl'}}\\
+Numerical keys are converted to capital letters: 1->A, 2->B.
+It is recommended that tables and keys contain letters only for predictable behaviour when using this feature.\\
+If the value of a tbl's key is a table, every element in that table is defined, and the keys of that nested table is
+appended to the cs: \cmd{dtbl<t><k1><k2>} (noting that numbers are converted to letters).\\
+
+
+\begin{LTXexample}
+\tblfrcsv{EX}{n1,kA=v1,n2,n3,n4,
+	     kB=v2,kC=v3,n5,n6}
+1>\tbldef{kA}{mycs}\mycs\tbldef{kA}{}\dtblEXkA\\
+2> \tbldef{EX/1}{}\dtblEXA
+\end{LTXexample}
+
+\begin{LTXexample}
+\tblfrcsv{EX}{x={1,2,3}}
+1>\tbldef{x}{mycs}\mycsA, \mycsB \\
+2>\tbldefs{}\dtblEXxA, \dtblEXxB
+\end{LTXexample}
+
+
+
+\cmd{\tbldefxy{i}[cspfx]} splits the value of item by space, and creates two definitions \cmd{<cspfx>x} and \cmd{<cspfx>y}.
+This might be useful for passing and using tikz coordinates, for example \cmd{xy=0 5}. An error is thrown if the values
+are non-numeric.\\
+
+\begin{LTXexample}[width=0.5\linewidth]
+\tblfrkv{EX}{coords=12 34,other}
+\tbldefxy{coords}[d]\dx, \dy \\
+\tbldefxy{coords}\dtblEXcoordsx, \dtblEXcoordsy \\
+\end{LTXexample}
+
+
+
+\subsection*{Utilities}
+
+\cmd{\tblapply{I}{func1(<v>,x,y)|:func2}[newtable]} apply a Lua function(s).\\If \cmd{newtable} is provided, a new table is created (and made the recent table)
+and the original table is preserved.\\ The \cmd{.}, \cmd{/} or \cmd{|} indexer may be used to apply a function
+to a single value or group of keys.
+Multiple functions can be applied sequentially, separated by \cmd{|}.
+
+An arbitrary global function (including additional arguments) can be used,
+but if a function is prefixed with a \cmd{:}, the class method will be called.
+The \cmd{stringx} and \cmd{tablex} methods
+from \cmd{penlight} are used depending on the value's type. See:\\
+\url{https://lunarmodules.github.io/Penlight/}
+
+Arguments can be specified with round brackets, where
+\cmd{<v>} and \cmd{<k>} are used as a placeholder for the values and keys.
+If no arguments are passed, it is assumed that the value is the only argument.
+Note that luakeys parses the args, so quotes are not needed around strings for the args.
+
+
+\begin{LTXexample}[width=0.5\linewidth]
+\tblfrcsv{ex}{{a, b, c}}
+\tblapply{}{:concat(<v>,-) | :upper}[new]
+1> \tblgetE{ex[1][1]}\\
+2> \tblget{new/1}\\
+\tblfrcsv{ex}{HelloWorld}
+\tblapply{}{string.sub(<v>,2,-5)}[new]
+3> \tblget{new/1}
+\end{LTXexample}
+
+%\begin{luacode*}
+% penlight.wrth(penlight.tablex.list2comma({'a','b','c'}),'XYZ')
+%\end{luacode*}
+
+%\tblprt*{ex}
+
+
+
+
+\cmd{\tblprt{t}} pretty-print the table in console. Using \cmd{\tblprt*{}} will terminate the LaTeX program immediately after and issue an error, which could be useful for debugging.
+
+
+
+\luadirect{luatbls._debug = true}
+
+\subsubsection*{An Example}
+%
+\begin{LTXexample}\scriptsize
+\NewDocumentCommand{\Exampletbl}{m}{
+	\tblfrcsv{ex}{#1}[defaults={sal=Hello}]
+	%\tblkvundefcheck
+	\tblapply{ex.auth}{:list2comma}
+	\tblget{sal}, \tblget{auth}! Thank you for writing such a great novel.
+	My favorite parts were:
+	\begin{description}
+		\tblforEN{ex.chaps}{\item[<k>] <v> }
+	\end{description}
+	It was also very cool to learn that
+	\tblgetE{ex.num[1]}*\tblgetE{ex.num[2]}=
+	\luadirect{tex.sprint(tostring(luatbls.ex.num[1]*luatbls.ex.num[2]))}
+}
+\Exampletbl{auth={You,Me,Dupree},
+	chaps={intro=very enticing, climax=thrilling, finale=what a twist!}
+	num={12,13}
+}
+\end{LTXexample}
+
+\tblprt{ex}
+
+
+
+
+
+
+\end{document}
+
+
+
+
+
+
+%\begin{luacode*}
+%  function prt_pyth()
+%  t = pl.tbls.pyth
+%  if not t.a then
+%    pl.tex.pkgerror('must pass a= to \\pyth')
+%  elseif not t.b then
+%    t.b = (tonumber(t.c)^2 -
+%          tonumber(t.a)^2)^0.5
+%  elseif not t.c then
+%    t.c = (tonumber(t.a)^2 +
+%          tonumber(t.b)^2)^0.5
+%  end
+%  local t = pl.tbx.fmt(t,'.'..t.d..'f') -- format table according to d decimals
+%  s = 'Right-angle sides a=$a and b=$b form a hypotenuse of c=$c'
+%  pl.tex.prt(s:fmt(t))
+%  end
+%\end{luacode*}
+%\NewDocumentCommand{\pyth}{m}{%
+%  \tblfrkv{pyth}{#1}[defaults={a=false,b=false,c=false,d=0,e=extras}]
+%  \luadirect{prt_pyth()}%
+%}
+%
+%\pyth{a=3,c=5}\\
+%\pyth{a=3.2,b=4.2,d=2}\\
+%C: \tblget{c}
+%
+%\end{LTXexample}
+
+%
+
+%
+%\begin{luacode*}
+%function prttol()
+%  local dec = penlight.tbls.tol[4] or 1
+%  penlight.wrth(dec,'??')
+%  penlight.tbls.tol[3] =  penlight.tbls.tol[3] or 3
+%  penlight.tbls.tol[4] =  penlight.tbls.tol[1]*(1.0-penlight.tbls.tol[3]/100.0) + 0.0
+%  penlight.tbls.tol[5] =  penlight.tbls.tol[1]*(1.0+penlight.tbls.tol[3]/100.0) + 0.0
+%  --penlight.tbls.tol['k'] = 'fuckboi'
+%  --ttt = pl.tbx.fmt(penlight.tbls.tol, '.3f')
+%  penlight.wrth(('$1\\$2 (\\pmpct{$3} tolerance, $4\\ndash$5\\$2)'):fmt(penlight.tbls.tol, '4=.'..dec..'f, 5=.'..dec..'f'), 'XYZ')
+%end
+%\end{luacode*}
+%\NewDocumentCommand{\prttol}{ m }{\tblfrcsv{tol}{#1}\luadirect{prttol()}}%  {50.0,kV,3,P}   % 50\us (\pmpct{20} tolerance, 40=--60\us), P is optional and precision of the range (number of decimals)
+%
+%\prttol{50,kV,3}
+%
+%\begin{luacode*}
+%  pl.wrth(pl.filterfiles('.',true,'.*%.tex'), 'FF')
+%\end{luacode*}
+
+
+
+
+%\begin{luacode*}
+%	for t, k, v in luatbls._iter_tbls_vals('my|*,:') do
+%	--for t, k, v in luatbls._iter_tbls_vals('my/1') do
+%		penlight.wrth({t,k,v})
+%	end
+%\end{luacode*}
+
+


Property changes on: trunk/Master/texmf-dist/doc/lualatex/luatbls/luatbls.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.lua
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.lua	2025-01-01 20:55:39 UTC (rev 73266)
@@ -0,0 +1,310 @@
+--% Kale Ewasiuk (kalekje at gmail.com)
+--% 2025-01-01
+--% Copyright (C) 2025 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.
+
+
+local luatbls = {}
+
+luatbls._luakeys = require'luakeys'()
+
+luatbls._rec_tbl = ''
+luatbls._rec_tbl_opts = {}
+
+luatbls._xysep = '%s+' -- spaces separate x-y coordinates
+luatbls._tblv = '<v>'
+luatbls._tblk = '<k>'
+luatbls._cspfx = 'dtbl'
+luatbls._debug = false
+
+function luatbls._dprint(s1, s2)
+    if luatbls._debug then
+        penlight.wrth(s1, s1)
+    end
+end
+
+
+setmetatable(luatbls, {__call=function(t,s)return t._get_tbl_item(s) end})
+
+function luatbls._get_tbl_name(s)
+    s = s:strip()
+    if s == '' then
+        return luatbls._rec_tbl
+    end
+    for _, delim in ipairs{'.', '/', '|'} do
+        s = s:split(delim)[1] -- if tbl reference had a . | or /, an indexer was used
+    end
+    if luatbls[s] == nil then
+        local validtbls = penlight.List(penlight.tablex.kkeys(luatbls)):filter(function(s) return not s:startswith('_')  end):join(', ')
+        penlight.tex.pkgerror('luatbls', 'Tried to access undefined tbl: "'..s..'".   Valid tbls are: '..validtbls)
+        return luatbls._rec_tbl
+    end
+    return s
+end
+
+function luatbls._get_tbl(s)
+    s = luatbls._get_tbl_name(s)
+    return luatbls[s]
+end
+
+function luatbls._get_tbl_index(s, undec)
+    undec = undec or false -- flag for allowing undeclared indexing
+    local tbl = ''
+    local key = ''
+    local s_raw = s
+    if s:find('%.') then
+        local tt = s:split('.')
+        tbl = tt[1]
+        key = tt[2]
+    elseif s:find('/') then
+        local tt = s:split('/')
+        tbl = tt[1]
+        if tbl == '' then tbl = luatbls._rec_tbl end
+        key = tonumber(tonumber(tt[2]))
+        if key < 0 then key = #luatbls[tbl]+1+key end
+    else
+        tbl = luatbls._rec_tbl
+        key = tonumber(s) or s
+        if type(key) == 'number' and key < 0 then key = #luatbls[tbl]+1+key end
+    end
+    if tbl == '' then tbl = luatbls._rec_tbl end
+
+    if (luatbls[tbl] == nil) or ((not undec) and (luatbls[tbl][key] == nil)) then
+        penlight.tex.pkgerror('luatbls',  'Invalid tbl index attempt using: "'..s_raw..'". We tried to use tbl="' ..tbl..'" and key="'..key..'"'..
+                'Note that "|" is forbidden here. The recent table is:  '..luatbls._rec_tbl)
+    end
+    return tbl, key
+end
+
+function luatbls._get_tbl_seq(s)
+    local tblseq = s:split('|')
+    local tbl = nil
+    local seq = nil
+    if #tblseq == 1 then
+        tbl = luatbls._get_tbl_name('')
+        seq = tblseq[1]
+        if seq == '' then seq = ':,*' end
+    elseif #tblseq == 2 then
+        tbl = luatbls._get_tbl_name(tblseq[1])
+        seq = tblseq[2]
+        if seq == '' then seq = ':,*' end
+    end
+    return tbl, seq
+end
+
+
+
+function luatbls._get_tbl_item(s, p) -- get item with string, p means print value
+  p = p or false
+  local tbl, key = luatbls._get_tbl_index(s)
+  local itm = luatbls[tbl][key]
+  if p then
+    tex.sprint(tostring(itm))
+  end
+  return itm
+end
+
+
+function luatbls._set_tbl_item(s, v)
+  tbl, key = luatbls._get_tbl_index(s)
+  luatbls[tbl][key] = v
+end
+
+function luatbls._check_recent_tbl_undefault()
+    local undefaults = {}
+    if luatbls._rec_tbl_opts ~= nil then
+        local defaults = penlight.tablex.union(
+                luatbls._rec_tbl_opts.defs or {},
+                luatbls._rec_tbl_opts.defaults or {}
+        )
+        for k, v in pairs(luatbls[luatbls._rec_tbl]) do
+            if defaults[k] == nil then
+                undefaults[#undefaults+1] = k
+            end
+        end
+        if penlight.hasval(undefaults) then
+            penlight.tex.pkgerror('luatbls',
+                    'Invalid keys passed to tbl keyval:  ' .. (', '):join(undefaults) ..
+                    ' ;   choices are:  ' .. (', '):join(penlight.tablex.keys(defaults))
+            )
+        end
+    end
+end
+
+function luatbls._make_alpha_key(k)
+     if tonumber(k) ~= nil then
+         k = penlight.Char(tonumber(k))
+     end
+    return k
+end
+
+function luatbls._def_tbl(ind, def, g)
+  local _tbl, _key = luatbls._get_tbl_index(ind)
+   if def == '' then def = luatbls._cspfx.._tbl..luatbls._make_alpha_key(_key) end
+  luatbls._def_tbl_one(luatbls[_tbl][_key], def, g)
+end
+
+
+function luatbls._def_tbl_some(tblseq, def, g)
+  for t, k, v in luatbls._iter_tbls_vals(tblseq) do
+      if def == '' then def = luatbls._cspfx..t end
+      local def2 = def .. luatbls._make_alpha_key(k)
+         luatbls._def_tbl_one(v, def2, g)
+     end
+end
+
+function luatbls._def_tbl_one(v, cs, g)
+    if type(v) == 'table' then
+        for kk, vv in pairs(v) do
+            kk = luatbls._make_alpha_key(kk)
+            token.set_macro(cs..kk, tostring(vv), g)
+        end
+    else
+        token.set_macro(cs, tostring(v), g)
+    end
+end
+
+function luatbls._def_tbl_coords(ind, def)
+    local tbl, key = luatbls._get_tbl_index(ind)
+    local str = luatbls[tbl][key]
+    if def == '' then def = luatbls._cspfx..tbl..key end
+    local x, y = str:strip():splitv(luatbls._xysep)
+     if (not penlight.hasval(x)) or (not penlight.hasval(y))  then
+       penlight.tex.pkgerror('luatbls', '_def_tbl_coords function could not parse coordiantes given as "'..str..'" ensure two numbers separated by space are given!', '', true)
+     end
+    token.set_macro(def..'x', tostring(x))
+    token.set_macro(def..'y', tostring(y))
+end
+
+
+function luatbls._for_tbl_prt(k, v,cmd)
+    local cmd_new = cmd:gsub(luatbls._tblv, tostring(v)):gsub(luatbls._tblk, tostring(k)):gsub('(\\%w+) ', '%1') -- for some reason a space gets added to \cs, maybe
+    luatbls._dprint(cmd_new, '_for_tbl replacement')
+    tex.sprint(cmd_new)
+end
+
+function luatbls._for_tbl(tblseq, cmd)
+  for t, k, v in luatbls._iter_tbls_vals(tblseq) do
+        luatbls._for_tbl_prt(k, v,cmd)
+  end
+end
+
+function luatbls._for_tbl_e(tbl, cmd)
+  for k, v in pairs(tbl) do
+        luatbls._for_tbl_prt(k, v,cmd)
+  end
+end
+
+
+function luatbls._iter_tbls_vals(s)
+    if s:find('|') or ((s:find('%.') == nil) and (s:find('/') == nil))  then
+        local tbl, seq = luatbls._get_tbl_seq(s)
+        local keyval = {}
+        for key, val in penlight.seq.tbltrain(luatbls._get_tbl(tbl), seq) do
+         -- todo this should check validity of keys for sequences
+            keyval[#keyval+1] = {key, val}
+        end
+        luatbls._dprint(keyval, 'luatbls._iter_tbls_vals is iterating through tbl: '..tbl..' with sequence:  '..seq)
+        local i = 0
+        return function()
+            i = i + 1
+            if i <= #keyval then
+                return tbl, keyval[i][1], keyval[i][2]
+            end
+        end
+    else
+        local tbl, key = luatbls._get_tbl_index(s)
+        local val = luatbls[tbl][key]
+        luatbls._dprint(keyval, 'luatbls._iter_tbls_vals is using tbl: '..tbl..' with key: '..key)
+        local i = 1
+        return function()
+            if i == 1 then
+                i = i + 1 -- only return the single value
+                return tbl, key, val
+            end
+        end
+    end
+end
+
+function luatbls._make_args(s, key, val)
+    local args = {val}
+    if s == nil then
+        return args
+    end
+    s = s:split(')')[1]
+    args = luatbls._luakeys.parse(s, {naked_as_value=true})
+    for i, v in ipairs(args) do
+        if v == luatbls._tblv then
+            args[i] = val
+        elseif v == luatbls._tblk then
+            args[i] = key
+        end
+    end
+    return args
+end
+
+function luatbls._make_func(f, key, val)
+    f = f:strip()
+    fargs = f:split('(')
+    f = fargs[1]
+    args = luatbls._make_args(fargs[2], key, val)
+    if f:startswith(':') then
+        f = f:sub(2,-1)
+        if type(val) == 'string' then
+            f = string[f]
+        elseif type(val) == 'table' then
+            f = penlight.tablex[f]
+        end
+    else
+        f = penlight._Gdot(f)
+    end
+    --luatbls._dprint() -- todo more debug printing
+    return f, args
+end
+
+
+
+function luatbls._make_newtbl(tblind, newtbl)
+    if tblind == '' then tblind = luatbls._rec_tbl..'|' end
+    if newtbl ~= '' then -- determine if new tbl is needed
+        local ogtbl = luatbls._get_tbl_name(tblind)
+        luatbls[newtbl] = penlight.tablex.deepcopy(luatbls[ogtbl])
+        luatbls._rec_tbl = newtbl
+        tblind, _ = string.gsub(tblind, ogtbl, newtbl, 1)
+    end
+    return tblind
+end
+
+function luatbls._apply_tbl(tblind, func, newtbl)
+    tblind = luatbls._make_newtbl(tblind, newtbl)
+    for _, f in pairs(func:split('|')) do
+        for tbl, key, val in luatbls._iter_tbls_vals(tblind) do
+            local thefunc, args = luatbls._make_func(f, key, val)
+            if thefunc == nil then
+                penlight.tex.pkgerror('luatbls', 'Tried to apply function: "'..f..'" to tbl value. It yielded no function. Ensure : is used for self-methods')
+            end
+            luatbls[tbl][key] = thefunc(penlight.utils.unpack(args))
+        end
+    end
+end
+
+return luatbls
\ No newline at end of file


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.sty
===================================================================
--- trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.sty	2025-01-01 20:55:39 UTC (rev 73266)
@@ -0,0 +1,163 @@
+% Kale Ewasiuk (kalekje at gmail.com)
+% 2025-01-01
+% Copyright (C) 2025 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.
+
+\RequirePackage{luacode}
+\RequirePackage{luakeys}
+\RequirePackage{penlightplus}
+
+
+\luadirect{luatbls = require'luatbls'}
+
+
+\NewDocumentCommand{\tblnew}{m}{\luadirect{% initialize a tbl and set empty
+  luatbls[\luastring{#1}] = {}
+  luatbls._rec_tbl = \luastring{#1}
+}}
+
+
+\NewDocumentCommand{\tblchg}{ m }{\luadirect{% change recent table
+  luatbls._rec_tbl = luatbls._get_tbl_name(\luastring{#1})
+}}
+
+\NewDocumentCommand{\tblfrkv}{m +m O{}}{\luadirect{% parse a tbl from key-vals, naked are set to boolean
+  luatbls._rec_tbl_opts = luatbls._luakeys.parse(\luastring{#3})
+  luatbls[\luastring{#1}] = luatbls._luakeys.parse(string.subpar(\luastring{#2}), luatbls._rec_tbl_opts)
+  luatbls._rec_tbl = \luastring{#1}
+}}
+
+\NewDocumentCommand{\tblfrkvN}{m +m O{}}{\luadirect{%
+  luatbls._rec_tbl_opts = luatbls._luakeys.parse(\luastring{#3})
+  luatbls[\luastring{#1}] = luatbls._luakeys.parse(string.subpar(\luastringN{#2}), luatbls._rec_tbl_opts)
+  luatbls._rec_tbl = \luastring{#1}
+}}
+
+\NewDocumentCommand{\tblfrcsv}{m +m O{}}{\tblfrkv{#1}{#2}[naked_as_value=true,#3]}% naked are set to array
+
+\NewDocumentCommand{\tblfrcsvN}{m +m O{}}{\tblfrkvN{#1}{#2}[naked_as_value=true,#3]}
+
+\NewDocumentCommand{\tblkvundefcheck}{}{\luadirect{luatbls._check_recent_tbl_undefault()}}% check defaults list and throw error if foreign keys were used
+
+
+
+\NewDocumentCommand{\tblapp}{m m}{\luadirect{% append to a table (ie using integer index)  with a value (second arg)
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  table.insert(luatbls[__tbl__], \luastring{#2})
+}}
+
+
+\NewDocumentCommand{\tblappN}{m m}{\luadirect{% append to a table (ie using integer index)  with a value (second arg) #
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  table.insert(luatbls[__tbl__], \luastringN{#2})
+}}
+
+
+\NewDocumentCommand{\tblcon}{m m}{\luadirect{% concatenate to a table (ie using integer index)  with a  list of comma separated values (second arg) #
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  for k, v in ipairs(luatbls._luakeys.parse(string.subpar(\luastring{#2}), {naked_as_value=true})) do
+    table.insert(luatbls[__tbl__], v)
+  end
+}}
+
+
+\NewDocumentCommand{\tblconN}{m m}{\luadirect{% concatenate to a table (ie using integer index)  with a  list of comma separated values (second arg) #
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  for k, v in ipairs(luatbls._luakeys.parse(string.subpar(\luastringN{#2}), {naked_as_value=true})) do
+    table.insert(luatbls[__tbl__], v)
+  end
+}}
+
+
+\NewDocumentCommand{\tbladd}{m m}{\luadirect{% add a kv pair to a table
+  __tbl__, __key__ = luatbls._get_tbl_index(\luastring{#1}, true)
+  luatbls[__tbl__][__key__] = \luastring{#2}
+}}
+
+\NewDocumentCommand{\tbladdN}{m m}{\luadirect{% add a kv pair to a table
+  __tbl__, __key__ = luatbls._get_tbl_index(\luastring{#1}, true)
+  luatbls[__tbl__][__key__] = \luastringN{#2}
+}}
+
+
+\NewDocumentCommand{\tblupd}{m m}{\luadirect{% update to a table (ie using integer index)  with a  list of comma separated values (second arg) #
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  __tbl_new__ = luatbls._luakeys.parse(string.subpar(\luastring{#2})
+  penlight.tablex.update(luatbls[__tbl__], __tbl_new__)
+}}
+
+
+\NewDocumentCommand{\tblupdN}{m m}{\luadirect{% update to a table (ie using integer index)  with a  list of comma separated values (second arg) #
+  __tbl__ = luatbls._get_tbl_name(\luastring{#1})
+  __tbl_new__ = luatbls._luakeys.parse(string.subpar(\luastringN{#2})
+  penlight.tablex.update(luatbls[__tbl__], __tbl_new__)
+}}
+
+
+
+
+\NewDocumentCommand{\tblget}{m}{\luadirect{% get an item using i syntax
+  luatbls._get_tbl_item(\luastring{#1}, true)
+}}
+
+\NewDocumentCommand{\tblgetE}{m}{\luadirect{% get an item explicitly
+  tex.sprint(tostring(luatbls.#1))
+}}
+
+\NewDocumentCommand{\tblset}{m m}{\luadirect{% set item with {value}
+  luatbls._set_tbl_item(\luastring{#1}, \luastring{#2})
+}}
+
+\NewDocumentCommand{\tblsetN}{m m}{\luadirect{% set item with {value}
+  luatbls._set_tbl_item(\luastring{#1}, \luastringN{#2})
+}}
+
+
+\NewDocumentCommand{\tblif}{ m m O{}}{\ifluax{luatbls._get_tbl_item(\luastring{#1})}{#2}[#3]}
+
+\NewDocumentCommand{\tblifv}{m m O{}}{\ifluaxv{luatbls._get_tbl_item(\luastring{#1})}{#2}[#3]}
+
+\NewDocumentCommand{\tblifeq}{m m m O{}}{\ifluax{luatbls._get_tbl_item(\luastring{#1}) == #2}{#3}[#4]}
+
+
+\NewDocumentCommand{\tblfor}{  m m }{\luadirect{luatbls._for_tbl(\luastring{#1}, \luastring{#2})}}
+\NewDocumentCommand{\tblforN}{ m m }{\luadirect{luatbls._for_tbl(\luastring{#1}, \luastringN{#2})}}
+
+\NewDocumentCommand{\tblforE}{  m m }{\luadirect{luatbls._for_tbl_e(luatbls.#1, \luastring{#2})}}
+\NewDocumentCommand{\tblforEN}{ m m }{\luadirect{luatbls._for_tbl_e(luatbls.#1, \luastringN{#2})}}
+
+
+\NewDocumentCommand{\tbldef}{  m m }{\luadirect{luatbls._def_tbl(\luastring{#1}, \luastring{#2})}}
+\NewDocumentCommand{\tblgdef}{ m m }{\luadirect{luatbls._def_tbl(\luastring{#1}, \luastring{#2}, 'global')}}
+
+\NewDocumentCommand{\tbldefs}{ m O{} }{\luadirect{luatbls._def_tbl_some(\luastring{#1}, \luastring{#2})}}
+\NewDocumentCommand{\tblgdefs}{ m  O{} }{\luadirect{luatbls._def_tbl_some(\luastring{#1},  \luastring{#2}, 'global')}}
+
+\NewDocumentCommand{\tbldefxy}{ m O{} }{\luadirect{luatbls._def_tbl_coords(\luastring{#1}, \luastring{#2})}}% define #2x and #2y from a space delimited x-y pair
+
+\NewDocumentCommand{\tblapply}{m m O{}}{\luadirect{luatbls._apply_tbl(\luastring{#1}, \luastring{#2}, \luastring{#3})}}
+
+\NewDocumentCommand{\tblprt}{s m}{%
+  \luadirect{penlight.wrth(luatbls._get_tbl(\luastring{#2}),'luatbls: '..\luastring{#2})}%
+  \IfBooleanTF{#1}{\PackageError{luatbls}{Program terminated by tblprt*}{}\stop}{}%
+}
+


Property changes on: trunk/Master/texmf-dist/tex/lualatex/luatbls/luatbls.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	2025-01-01 20:55:05 UTC (rev 73265)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2025-01-01 20:55:39 UTC (rev 73266)
@@ -547,7 +547,8 @@
     luamesh luamml luamodulartables luamplib luanumint luaoptions luaotfload
     luapackageloader luaplot luaprogtable luapstricks
     luaquotes luarandom
-    luaset luasseq luatex85 luatexbase luatexja luatexko luatextra luatikz
+    luaset luasseq
+    luatbls luatex85 luatexbase luatexja luatexko luatextra luatikz
     luatodonotes luatruthtable luavlna luaxml
     lutabulartools luwiantype lwarp lxfonts ly1 lyluatex
   macrolist macros2e macroswap mafr magaz magicnum magicwatermark magra

Modified: trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2025-01-01 20:55:05 UTC (rev 73265)
+++ trunk/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc	2025-01-01 20:55:39 UTC (rev 73266)
@@ -72,6 +72,7 @@
 depend luaquotes
 depend luarandom
 depend luaset
+depend luatbls
 depend luatex85
 depend luatexbase
 depend luatexko

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


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