%% lua-placeholders-manual.tex %% Copyright 2024 E. Nijenhuis % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status ‘maintained’. % % The Current Maintainer of this work is E. Nijenhuis. % % This work consists of the files lua-placeholders.sty % lua-placeholders-manual.pdf lua-placeholders.lua % lua-placeholders-common.lua lua-placeholders-namespace.lua % lua-placeholders-parser.lua and lua-placeholders-types.lua \documentclass{ltxdoc} \usepackage[english]{babel} \usepackage[titlepage,authors,rootdir]{gitinfo-lua} \usepackage{listings} \usepackage{lua-placeholders} \usepackage{multicol} \usepackage{calc} \usepackage{fmtcount} \usepackage[nodayofweek]{datetime} \usepackage{hyperref,embedfile} \usepackage{textcomp} \usepackage{attachfile2} \usepackage{enumitem} \usepackage{biblatex} \usepackage[english]{isodate} \DefineBibliographyStrings{english}{% bibliography = {References}, } %! suppress = MissingBibliographystyle \bibliography{lua-placeholders-deps} \embedfile[desc={Parameter Specification Example},filespec=example.pdf]{lua-placeholders-example/example.pdf} \embedfile[desc={Parameter Specification Example (YAML)},filespec=example-specification.yaml]{lua-placeholders-example/example-specification.yaml} \embedfile[desc={Values Specification Example},filespec=example.yaml]{lua-placeholders-example/example.yaml} \def\projecturl{https://github.com/Xerdi/lua-placeholders} \newcommand\showexample[5][15pt]{% \begin{minipage}[t]{.5\linewidth - .5 \columnsep}% \lstinputlisting[firstnumber={#2},linerange={#3},style=YAML,frame=single,numbers=left,xleftmargin=0pt,numbersep=10pt,columns=fullflexible]{lua-placeholders-example/example-specification.yaml} \end{minipage}\hspace*{\columnsep}% \begin{minipage}[t]{.5\linewidth - .5 \columnsep}% \lstinputlisting[firstnumber={#4},linerange={#5},style=YAML,frame=single,numbers=left,xleftmargin={#1},numbersep=10pt,columns=fullflexible]{lua-placeholders-example/example.yaml} \end{minipage}\\% } \usepackage[headsepline]{scrlayer-scrpage} \automark[section]{section} \lohead{\normalfont Lua placeholders {\footnotesize v\gitversion}} \rohead{\normalfont Section \rightmark} \cofoot{\thepage} \begin{document} \title{Lua \paramplaceholder{placeholders}\thanks{This document corresponds to \texttt{lua-placeholders} version \gitversion, written on \gitdate}} \maketitle \begin{abstract} A package for producing `example' documents --- parameters rendered as placeholders --- and `actual copy' documents --- parameters replaced with real values --- driven by YAML and a small Lua core. Supports Lua\LaTeX\ via \texttt{lua-placeholders.sty} and plain Lua\TeX\ via \texttt{lua-placeholders.tex}. \end{abstract} \tableofcontents \clearpage \section{Introduction} This package is meant for setting parameters in a document programmatically via YAML\@. Parameters can be specified by adding a `recipe' file. These recipe files describe the parameter's type, placeholders and/or default values. From thereon, the placeholders can be displayed in the document and an `\textit{example}' document can be created. An `\textit{actual copy}' document can be created by loading additional payload files, which all must correspond to a recipe file. \paragraph{A note on engines and naming.} \texttt{lua-placeholders} is a Lua module wrapped by two thin engine bridges: a \LaTeX\ package, \texttt{lua-placeholders.sty} for use under Lua\LaTeX, and a plain-format input, \texttt{lua-placeholders.tex} for use under Lua\TeX. Throughout this manual, where we write \LaTeX\ we specifically mean Lua\LaTeX, and where we write \TeX\ we mean plain Lua\TeX --- there is no support for any other engine, since the runtime requires Lua\TeX\ primitives. Each macro section also states the plain-\TeX\ form when it differs from the \LaTeX\ one (typically by lacking the optional \meta{namespace} argument). \begin{multicols}{2} \subsection{Pros} \begin{enumerate}[align=left] \item Create an `\textit{example}' or `\textit{actual copy}' document from the same source and YAML recipe. \item Integration is as easy as compiling a normal document, especially thanks to the fallback support to JSON. \item Supports multiple data types and formatting macros which work in most environments, like \texttt{enumerate} or \texttt{tabular}. \item Same Lua core powers both the \LaTeX\ and the \TeX\ bridge; new macros land in both at once. \end{enumerate} \columnbreak \subsection{Cons} \begin{enumerate}[align=left] \item Requires a Lua-based engine: Lua\LaTeX\ or plain Lua\TeX. Other engines are not supported. \item In order for the files to be loaded, commandline option `\texttt{--shell-restricted}' is required. \end{enumerate} \textbf{Important:} In the 1.x.x series this documentation suggested `\texttt{--shell-escape}' instead, which allows the execution of programs and isn't a requirement for this package since the introduction of \texttt{lua-tinyyaml}. \end{multicols} \begin{multicols}{2} \subsection{Security Considerations} When using \texttt{--shell-escape} instead of \texttt{--shell-restricted}, one should be aware of the security vulnerabilities it might introduce. While it may not seem to be a risk for most users and use cases, for best practices, one should avoid using \texttt{--shell-escape}, since this package is meant for seamless workflow integration, which could introduce vulnerabilities in an unknown variety of ways. Therefore, I urge everyone that still requires the execution of programs to whitelist those programs in \texttt{shell\_escape\_commands} instead. This can be configured system-wide in \texttt{texmf.cnf} or within a Lua initialization script using the \texttt{texconfig} table, thoroughly explained in section 4.1.3, 4.2.4 and 10.4 of the Lua\TeX\ manual\cite{luatex}. \subsection{Dependencies}\label{sec:deps} The Lua core has \emph{no hard dependency} on any \LaTeX\ package. The \LaTeX\ bridge (\texttt{.sty}) loads \texttt{textcomp} for the placeholder symbols and \texttt{xspace} for trailing-space handling inside the \texttt{paramobject} environment; the \TeX\ bridge (\texttt{.tex}) needs neither. The following packages are \emph{optional} --- the \LaTeX\ bridge falls back gracefully if they are absent: \begin{itemize}[align=left,leftmargin=*] \item \texttt{numprint}\cite{numprint} for number formatting via \cmd{\paramnumberformat}; without it, numeric values render as-is. \item \texttt{isodate}\cite{isodate} for date formatting via \cmd{\paramdateformat} when \texttt{lua-tinyyaml} produces a Lua date table from a \texttt{YYYY-MM-DD} payload scalar. \end{itemize} Booleans are handled by a self-contained \cmd{\newif}-style flag bridge built on \cmd{\let} and \cmd{\csname}; \texttt{ifthen} is no longer required. \subsubsection{YAML Support} During the 1.x.x series the preferred YAML implementation changed from \texttt{lyaml}\cite{lyaml} to \texttt{lua-tinyyaml}\cite{lua-tinyyaml}. The reason for this change is that \texttt{lua-tinyyaml} doesn't require any platform-specific dependencies, such as \texttt{libYAML}\cite{libYAML}. The older YAML implementation will still function for older installations that do not have \texttt{lua-tinyyaml}. As before, when no YAML implementation is found, \texttt{lua-placeholders} will fall back to JSON support. \subsubsection{\TeX\ vs \LaTeX\ differences}\label{sec:engine-diff} The Lua core is identical for both engines; only the bridge file changes. Concretely: \begin{itemize}[align=left,leftmargin=*] \item \textbf{Optional arguments.}\hspace*{0.5em} \LaTeX\ macros take an optional \oarg{namespace}; the \TeX\ forms have no optional argument and use \cmd{\curnamespace} (settable via \cmd{\setnamespace}). \item \textbf{Environments.}\hspace*{0.5em} The \texttt{paramobject} environment is a \cmd{\begin}/\cmd{\end} pair under \LaTeX\ and a \cmd{\paramobject}/\cmd{\endparamobject} macro pair under \TeX. \item \textbf{Hooks.}\hspace*{0.5em} Under \LaTeX\ each \cmd{\loadrecipe} fires \texttt{namespace/}\meta{name} via \texttt{lthooks}, and each \cmd{\loadpayload} fires \texttt{namespace/}\meta{name}\texttt{/loaded}; under \TeX\ no hook system is available so the emissions are skipped at the Lua level. The parameter state is fully populated either way --- only attached callbacks are unavailable in \TeX. \item \textbf{Booleans.}\hspace*{0.5em} Same call shape on both sides (\cmd{\paramnewbool} / \cmd{\paramsetbool}); the bridge backs them with \cmd{\let}-based flags rather than \cmd{\newif} so they work identically without \texttt{ifthen}. \item \textbf{Engine wrappers} (\cmd{\paramnumberformat}, \cmd{\paramdateformat}, \cmd{\paramfieldterm}).\hspace*{0.5em} \LaTeX\ wires them to \texttt{numprint}, \texttt{isodate} and \cmd{\xspace}; \TeX\ leaves them as plain pass-throughs. See \S\ref{sec:bridges}. \end{itemize} \end{multicols} \section{Usage} This section describes the basic commands of \texttt{lua-placeholders}. For more detail about type specific commands or the behavior of types with commands described here, see section~\ref{sec:spec}.\\ \subsection{Configuration} \DescribeMacro{\strictparams} In order to give an error when values are missing, the \cmd{\strictparams}\footnote{The \cmd{\strictparams} command is still under development.} command can be used. Make sure to do it before loading any \meta{recipe} and \meta{payload} files. Identical form in \TeX. \DescribeMacro{\loadrecipe} In order to load a recipe the macro \cmd{\loadrecipe}\oarg{namespace}\marg{filename} can be used. Where the \meta{filename} is a YAML file with its corresponding extension. The optional \meta{namespace} is only a placeholder in order to prevent any conflicts between duplicate \meta{key}s. If left out, the \meta{namespace} defaults to the base name of the filename. \DescribeMacro{\loadpayload} The same behaviour counts for \cmd{\loadpayload}\oarg{namespace}\marg{filename}. The order of loading \meta{recipe} and \meta{payload} files doesn't matter. If the \meta{payload} file got loaded first, it will be yielded until the corresponding \meta{recipe} file is loaded. The hook emissions on each load are described in section~\ref{sec:engine-diff} (\LaTeX\ only). Plain \TeX\ form: \cmd{\loadrecipe}\marg{filename} and \cmd{\loadpayload}\marg{filename} take only the filename. The active namespace is whatever \cmd{\curnamespace} expands to at call time --- defaulting to \cmd{\jobname} and adjustable with \cmd{\setnamespace}. All other macros of this package also take the optional \meta{namespace}, which by default is equal to \cmd{\jobname}. \DescribeMacro{\setnamespace} This default \meta{namespace} can be changed with \cmd{\setnamespace}\marg{new default namespace}. Identical form in \TeX.\\ \subsection{Displaying Parameters} For displaying variables, the commands \cmd{\param} and \cmd{\PARAM} share the same interface. \DescribeMacro{\param} The most trivial, displaying the variable as-is, is \cmd{\param}\oarg{namespace}\marg{key}. \DescribeMacro{\PARAM} The \cmd{\PARAM} however, shows the value as upper case. Plain \TeX\ forms: \cmd{\param}\marg{key} and \cmd{\PARAM}\marg{key} (no optional argument; namespace comes from \cmd{\curnamespace}). In some cases, it's required to output the text without any \TeX\ related functionality. Another case is that some environments don't take macros with optional arguments well. \DescribeMacro{\rawparam} For these cases there is \cmd{\rawparam}\marg{namespace}\marg{key}, which takes the namespace as mandatory argument, instead of optional, and doesn't output fancy \TeX\ placeholders. Plain \TeX\ form: \cmd{\rawparam}\marg{key} (single argument; namespace from \cmd{\curnamespace}).\\ \DescribeMacro{\hasparam} To check whether a parameter is set, the \cmd{\hasparam}\oarg{namespace}\marg{key}\marg{true case}\marg{false case} command is used. Plain \TeX\ form: drop the optional namespace --- \cmd{\hasparam}\marg{key}\marg{true case}\marg{false case}. \subsection{Engine bridges}\label{sec:bridges} The Lua core never references package-specific commands directly; it emits the following wrappers, which the bridge file (\texttt{.sty} for \LaTeX, \texttt{.tex} for \TeX) backs with engine-appropriate behaviour. Override any of them in your own preamble before the bridge is loaded if you need different formatting. \begin{description}[font=\ttfamily] \item[\textbackslash paramnumberformat\marg{N}] Numeric values pass through here. \LaTeX\ default: \cmd{\numprint}\marg{N} when \texttt{numprint} is loaded, otherwise \meta{N} as-is. \TeX\ default: \meta{N} as-is. \item[\textbackslash paramdateformat\marg{Y}\marg{M}\marg{D}] \texttt{YYYY-MM-DD} payload scalars (parsed as a Lua date table by \texttt{lua-tinyyaml}) pass through here. \LaTeX\ default: \cmd{\printdateTeX}\marg{Y/M/D} when \texttt{isodate} is loaded, otherwise \meta{Y}/\meta{M}/\meta{D} as text. \TeX\ default: \meta{Y}/\meta{M}/\meta{D} as text. \item[\textbackslash paramfieldterm] Appended after each field binding inside the \texttt{paramobject} environment. \LaTeX\ default: \cmd{\xspace}. \TeX\ default: empty (the author writes \cmd{\name}\cmd{\space} or \cmd{\name}\texttt{\{\}} explicitly). \end{description} \clearpage \section{Parameter Specification}\label{sec:spec} Every parameter specified has a \meta{type} set. Optionally there is a choice between setting a \meta{default} or a \meta{placeholder} for the parameter. \begin{description} \item[bool] Next to the textual representation of \textit{true} and \textit{false}, the bridge tracks each boolean as a \cmd{\newif}-style flag. Therefore, only the \meta{default} setting makes sense.\\[5pt] \hspace*{5pt}\parbox{\linewidth-5pt}{% \hfill\texttt{Recipe}\hfill\hspace*{\columnsep}% \hfill\texttt{Payload}\hfill\hspace*{\columnsep}}\\% \showexample{1}{1-3}{1}{1-1} \DescribeMacro{\param} With a boolean type the \cmd{\param}\oarg{namespace}\marg{name} returns either \textit{true} or \textit{false}. \DescribeMacro{\ifparam} Additionally, it provides the \cmd{\ifparam}\oarg{namespace}\marg{name}\marg{true code}\marg{false code} command for top level boolean types. The flag is set via \cmd{\paramsetbool} and tested with \cmd{\csname if}\meta{name}\cmd{\endcsname}, which supports spaces in names without any package dependency (no \texttt{ifthen} is needed). Plain \TeX\ form: \cmd{\ifparam}\marg{name}\marg{true code}\marg{false code} (no optional namespace). \item[string] representing a piece of text. Values are passed through to \TeX\ verbatim --- only embedded newlines are normalised to spaces. \TeX-special characters (\texttt{\textbackslash}, \texttt{\%}, \texttt{\#}, \texttt{\&}, \texttt{\_}, \texttt{\$}, \texttt{\^{}}, \texttt{\~{}}) are \emph{not} escaped: pass an unescaped \texttt{\%} and \TeX\ will treat the rest of the value as a comment, pass a bare \texttt{\&} and you'll get a misplaced-alignment-tab error, etc. Escape them in the YAML payload using their usual \LaTeX\ forms (e.g.\ \texttt{\textbackslash\%} for a literal percent, \texttt{\textbackslash\&} for an ampersand, \texttt{\textbackslash textbackslash} for a backslash).\\ \showexample{4}{4-6}{2}{2-2} \DescribeMacro{\param} A string type can easily be placed in \LaTeX\ using the \cmd{\param} command. \paragraph{YAML date caveat.} When the YAML payload is parsed by \texttt{lua-tinyyaml}, scalars matching the ISO~8601 date pattern \texttt{YYYY-MM-DD} are returned as a Lua table \texttt{\{year=,~month=,~day=\}} rather than a string. \texttt{lua-placeholders} hands the three components to \cmd{\paramdateformat}\marg{Y}\marg{M}\marg{D} (see~\ref{sec:bridges}); the \LaTeX\ bridge wraps that in \cmd{\printdateTeX} from \texttt{isodate}\cite{isodate} when available, and the \TeX\ bridge prints \meta{Y}/\meta{M}/\meta{D} as text. The \texttt{date~example} field below illustrates this:\\ \showexample{7}{7-9}{3}{3-3} Note that \cmd{\rawparam} bypasses this conversion and will not produce useful output for a date-typed value. The \texttt{lyaml} fallback and JSON do not perform this conversion --- the same \texttt{YYYY-MM-DD} payload is delivered as a plain string instead. \item[number] representing a number, like the number type of Lua. In most cases it's necessary to use \meta{default} instead of \meta{placeholder}, especially when the number is used in calculations, since a placeholder will cause errors in \LaTeX\ calculations.\\ \showexample{10}{10-12}{4}{4-4} \DescribeMacro{\param} A number type can be used with \cmd{\param}, just like the string type. In the 1.x.x series there was a special command \cmd{\numparam}, which is now deprecated as it is the default implementation for number types using \cmd{\param}. Numeric values pass through \cmd{\paramnumberformat} (see~\ref{sec:bridges}); the \LaTeX\ bridge wraps in \cmd{\numprint} from \texttt{numprint}\cite{numprint} when loaded, the \TeX\ bridge prints the value as-is. The same behaviour applies to number values inside a \texttt{list}, \texttt{object} or \texttt{table}. If you need a nonformatted version of the number, use \cmd{\rawparam} instead. \item[list] representing a list of values. The simplest form sets the item shape with \meta{item type} (one of \texttt{string}, \texttt{number}, \texttt{bool}). For nested complex item types, use the long form \meta{item}: a full nested parameter spec, e.g.\ \texttt{item: \{type: object, fields: \dots\}} or \texttt{item: \{type: table, columns: \dots\}}. A \meta{default} setting can be set. Due to its structure, a \meta{placeholder} would be somewhat incompatible with the corresponding macros; instead, set placeholder content as children of the \meta{default} list.\\ \showexample{13}{13-18}{5}{5-7} \DescribeMacro{\param} Command \cmd{\param} concatenates every item with command \cmd{\paramlistconjunction}. \DescribeMacro{\paramlistconjunction} By default, the conjunction is set to `\texttt{,\textasciitilde}'. \DescribeMacro{\forlistitem} There's also the \cmd{\forlistitem}\oarg{namespace}\marg{name}\marg{csname} command, which takes an additional \meta{csname} and will execute it for every item in the list. For primitive item types the \meta{csname} is invoked with the value as its single argument. For complex item types (\texttt{object}, \texttt{list}, \texttt{table}) each item is pushed onto the lookup context: object items expose every field as a direct \cmd{\} macro, while list/table items are bound under the synthetic key \texttt{self} so the row macro can drill in with \cmd{\fortablerow}\marg{self}\marg{...} or \cmd{\forlistitem}\marg{self}\marg{...}. Plain \TeX\ form: \cmd{\forlistitem}\marg{name}\marg{csname} (no optional namespace). \item[object] representing a list of key value pairs. This parameter type requires a \meta{fields} specification to be set. Each field is itself a parameter spec, so \texttt{bool}, \texttt{number}, \texttt{string} as well as nested \texttt{list}, \texttt{object} and \texttt{table} types are all permitted.\\ \showexample{19}{19-30}{8}{8-11} There is no support for the \cmd{\param} command. \DescribeMacro{\paramfield} In order to show to contents there is the \cmd{\paramfield}\oarg{namespace}\marg{name}\marg{field} command. However, unlike the common command \cmd{\param}, the command \cmd{\hasparam} does work with object types. Plain \TeX\ form: \cmd{\paramfield}\marg{name}\marg{field}. \DescribeEnv{paramobject} There's also the \texttt{paramobject} environment, which takes an optional \meta{namespace} and the \meta{name} of the object as arguments and then defines for every primitive field name a corresponding command. Each binding is appended with \cmd{\paramfieldterm} (\cmd{\xspace} under \LaTeX, empty under \TeX) so the author doesn't have to end the command with accolades `\{\}' to get the expected output. Complex (list, object, table) sub-fields are not flattened to a macro; they remain reachable inside the environment via \cmd{\forlistitem}\marg{field}\marg{...}, \cmd{\paramfield}\marg{field}\marg{...} (for nested objects), \cmd{\fortablerow}\marg{field}\marg{...}, etc.\\ Plain \TeX\ form: \cmd{\paramobject}\marg{name}~\dots~\cmd{\endparamobject} (a macro pair instead of a \cmd{\begin}/\cmd{\end} environment). \item[table] representing a table. This parameter type requires a \meta{columns} specification to be set. The \meta{columns} describes each column by name with its own type specification. Each column may be of any type --- \texttt{bool}, \texttt{number}, \texttt{string}, or a nested \texttt{list}, \texttt{object} or \texttt{table} --- and is reached from the row macro via the corresponding type-specific command (\cmd{\paramfield}, \cmd{\forlistitem}, nested \cmd{\fortablerow}).\\ \showexample[20pt]{31}{31-39}{12}{12-16} \DescribeMacro{\fortablerow} Like the object, the table has no support for \cmd{\param}, but comes with a table-specific command \cmd{\fortablerow}\oarg{namespace}\marg{name}\marg{csname}. The control sequence name \meta{csname} is a user-defined command with no arguments, containing any of the column names in a command form. For example, the name \texttt{example} would be accessible as \cmd{\example} in the user-defined command body. Cells do not require braces; the column macros expand naturally inside \TeX, so \texttt{\textbackslash example} works the same way as \texttt{\textbackslash example\{\}}. Plain \TeX\ form: \cmd{\fortablerow}\marg{name}\marg{csname} (no optional namespace). Internally, \cmd{\fortablerow} pushes a frame onto a context stack shared with \texttt{paramobject} and \cmd{\forlistitem}, then rebinds every primitive column to a global control sequence via \texttt{token.set\_macro} just before each invocation of \meta{csname}. Because the column macros are real \TeX\ control sequences --- not string substitutions --- prefix collisions between column names (e.g.\ a column \texttt{item} alongside \texttt{item\_name}) are no longer a concern, and unreferenced columns in \meta{csname} are silently dropped instead of leaking partial substitutions. \paragraph{Underscore in a column name.} \cmd{\token.set\_macro} is catcode-agnostic, so it can define a control sequence \cmd{\item\_name} regardless of the catcode of \texttt{\_} at the time \cmd{\fortablerow} runs. \emph{Using} that control sequence in \meta{csname}, however, requires \texttt{\_} to have letter catcode (\texttt{11}) when the row macro is parsed --- otherwise \TeX\ reads \cmd{\item\_name} as \cmd{\item} followed by the subscript token \texttt{\_} and the letters \texttt{name}. The standard idiom is to wrap the row macro definition in \cmd{\ExplSyntaxOn}~\dots\cmd{\ExplSyntaxOff}, which temporarily flips \texttt{\_} (and \texttt{:}) to letter catcode for the parser: \begin{verbatim} \ExplSyntaxOn \cs_new:Npn \rowU {\item & \item_name & \unit_price \\} \ExplSyntaxOff \fortablerow{my-table}{rowU}\end{verbatim} Once \cmd{\rowU} has been tokenised, the catcode of \texttt{\_} no longer matters at expansion time. \end{description} \clearpage % Enlarge the \textwidth for the coming pages \addtolength\textwidth{2cm}% \setlength\linewidth{\textwidth}% \addtolength\oddsidemargin{-2cm}% \addtolength\evensidemargin{-1cm}% \printbibliography[heading=bibnumbered] \clearpage \begin{multicols}{2} \section{Change Log} \newcommand\setcurdate[1]{\def\curdate{#1}}% \newcommand\commitline[4]{% \ifthenelse{\equal{#2}{\curdate}}{}{\item[] \hrulefill~{\scriptsize\printdate{#2}}\def\curdate{#2}}% \item[\href{https://github.com/Xerdi/lua-placeholders/commit/#4}{#4}]% {\small\fontfamily{\sfdefault}\selectfont#1}% \ifx&\else\\% {\footnotesize#3}% \fi% } \newcommand\formatversion[3]{% {\bfseries\large Release \href{https://github.com/Xerdi/lua-placeholders/releases/tag/#1}{#1}}~\hrulefill~% \gittag[(taggerdate)(taggerdate:short)(authordate:short)]{setcurdate}{#1}% {\scriptsize\gittag[(taggerdate)(taggerdate:short)(authordate:short)]{printdate}{#1}} \begin{description}[font=\small\ttfamily,itemsep=1pt] \forgitcommit[s,as,b,h]{commitline}{#3,flags={no-merges}} \end{description} \bigskip }% \forgittagseq{formatversion} \end{multicols} \clearpage \section{Example} The source file \texttt{example.tex} is a perfect demonstration of all macros in action. It shows perfectly what happens when there's a \meta{payload} file loaded and when not. The result of this example \attachfile[icon=Paperclip,description={Lua Parameters Example v\gitversion}]{lua-placeholders-example/example.pdf} is attached in the digital version of this document. \lstinputlisting[language={[LaTeX]TeX},frame=single,caption={\ttfamily example.tex},captionpos=t,numbers=left,keywordsprefix={\\},firstnumber=20,firstline=20,columns=fullflexible]{lua-placeholders-example/example.tex} \end{document}