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