% Kale Ewasiuk (kalekje@gmail.com) % 2024-08-17 % Copyright (C) 2021-2024 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}[2024-08-17] \RequirePackage{luacode} \RequirePackage{luakeys} \RequirePackage[import]{penlight} \RequirePackage{etoolbox} \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})}% } %%%% \newtoggle{luaexpr}\togglefalse{luaexpr} \begin{luacode*} \end{luacode*} \NewDocumentCommand{\ifluax}{m m O{}}{% if lua expression is true do {m} if not [o] \luadirect{penlight.toggle_luaexpr(#1)}% \iftoggle{luaexpr}{#2}{#3}% \togglefalse{luaexpr}% safety set to false } \NewDocumentCommand{\ifluaxv}{m m O{}}{\ifluax{penlight.hasval(#1)}{#2}[#3]}% if lua expression is truthy do {m} else [o] \NewDocumentCommand{\caseswitch}{s m +m}{\ignorespaces\luadirect{penlight.caseswitch(\luastring{#1},\luastring{#2},\luastringN{#3})}\unskip} % argument 1 is star option, which throws an error if case is not found % argument 2 is the case, fully expanded % argument 3 is a luakeys table of options, not expanded %%% tbls below \NewDocumentCommand{\tblnew}{m}{\luadirect{% initialize a tbl and set blank penlight.tbls[\luastring{#1}] = {} penlight.rec_tbl = \luastring{#1} }} \NewDocumentCommand{\tblfrkv}{m +m O{}}{\luadirect{% penlight.rec_tbl_opts = penlight.luakeys.parse(\luastring{#3}) penlight.tbls[\luastring{#1}] = penlight.luakeys.parse(string.subpar(\luastring{#2}), penlight.rec_tbl_opts) penlight.rec_tbl = \luastring{#1} }} \NewDocumentCommand{\tblfrkvCD}{m +m O{}}{\tblfrkv{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}} %% tbl from key-vals, then check defaults, then define all keys using default format \NewDocumentCommand{\tblfrkvNCD}{m +m O{}}{\tblfrkvN{#1}{#2}[#3]\tblkvundefcheck\tbldefall{}{}} \NewDocumentCommand{\tblfrkvN}{m +m O{}}{\luadirect{% penlight.rec_tbl_opts = penlight.luakeys.parse(\luastring{#3}) penlight.tbls[\luastring{#1}] = penlight.luakeys.parse(string.subpar(\luastringN{#2}), penlight.rec_tbl_opts) penlight.rec_tbl = \luastring{#1} }} \NewDocumentCommand{\tblfrcsv}{m +m O{}}{\tblfrkv{#1}{#2}[naked_as_value=true,#3]} \NewDocumentCommand{\tblfrcsvN}{m +m O{}}{\tblfrkvN{#1}{#2}[naked_as_value=true,#3]} \NewDocumentCommand{\tblkvundefcheck}{}{\luadirect{penlight.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) # todo option for string or number __tbl__ = penlight.get_tbl_name(\luastring{#1}) table.insert(penlight.tbls[__tbl__], \luastring{#2}) }} \NewDocumentCommand{\tblcon}{m m}{\luadirect{% concatenate to a table (ie using integer index) with a list of comma separated values (second arg) # __tbl__ = penlight.get_tbl_name(\luastring{#1}) for k, v in ipairs(penlight.luakeys.parse(string.subpar(\luastring{#2}), {naked_as_value=true})) do table.insert(penlight.tbls[__tbl__], v) end }} \NewDocumentCommand{\tbladd}{m m}{\luadirect{% add a kv pair to a table __tbl__, __key__ = penlight.get_tbl_index(\luastring{#1}, true) penlight.tbls[__tbl__][__key__] = \luastring{#2} }} \NewDocumentCommand{\tbladdN}{m m m}{\luadirect{% add a kv pair to a table __tbl__, __key__ = penlight.get_tbl_index(\luastring{#1}, true) penlight.tbls[__tbl__][__key__] = \luastringN{#2} }} \NewDocumentCommand{\tblchg}{ m }{\luadirect{% change recent table penlight.rec_tbl = \luastring{#1} }} \NewDocumentCommand{\tblget}{m}{\luadirect{% get an item penlight.get_tbl_item(\luastring{#1}, true) }} \NewDocumentCommand{\tblset}{m m}{\luadirect{% set item with {value} penlight.set_tbl_item(\luastring{#1}, \luastring{#2}) }} \NewDocumentCommand{\tbldef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2})}} % define a table, use * to make global definition \NewDocumentCommand{\tblgdef}{ m m }{\luadirect{penlight.def_tbl(\luastring{#1}, \luastring{#2}, 'global')}} \NewDocumentCommand{\tbldefall}{ m m }{\luadirect{penlight.def_tbl_all(\luastring{#1}, \luastring{#2})}} \NewDocumentCommand{\tbldefxy}{ m m }{\luadirect{penlight.def_tbl_coords(\luastring{#1}, \luastring{#2})}}% define #2x and #2y from a space delimited x-y pair \NewDocumentCommand{\tblif}{m m O{}}{\ifluax{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]} \NewDocumentCommand{\tblifv}{m m O{}}{\ifluaxv{penlight.get_tbl_item(\luastring{#1})}{#2}[#3]} \NewDocumentCommand{\tblprt}{m}{\luadirect{penlight.wrth(penlight.get_tbl(\luastring{#1}),'penlightplus table: '..\luastring{#1})}} % legacy code, delete this \let\kvtblundefcheck\tblkvundefcheck \NewDocumentCommand{\tbladdo}{m m m}{\luadirect{% add a kv pair to a table __tbl__ = penlight.get_tbl_name(\luastring{#1}) penlight.tbls[__tbl__][\luastring{#2}] = \luastring{#3} }} \NewDocumentCommand{\tbladdNo}{m m m}{\luadirect{% add a kv pair to a table __tbl__ = penlight.get_tbl_name(\luastring{#1}) penlight.tbls[__tbl__][\luastring{#2}] = \luastringN{#3} }} \let\chgtbl\tblchg \let\newtbl\tblnew \let\gettbl\tblget \let\settbl\tblset \let\deftbl\tbldef \let\gdeftbl\tblgdef \let\iftbl\tblif \let\iftblv\tblifv