texlive[65468] Master/texmf-dist: luakeys (5jan23)
commits+karl at tug.org
commits+karl at tug.org
Thu Jan 5 22:18:54 CET 2023
Revision: 65468
http://tug.org/svn/texlive?view=revision&revision=65468
Author: karl
Date: 2023-01-05 22:18:54 +0100 (Thu, 05 Jan 2023)
Log Message:
-----------
luakeys (5jan23)
Modified Paths:
--------------
trunk/Master/texmf-dist/doc/luatex/luakeys/README.md
trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty
trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.tex
trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua
trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty
trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.tex
Added Paths:
-----------
trunk/Master/texmf-dist/doc/luatex/luakeys/documentation.tex
trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf
Removed Paths:
-------------
trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.pdf
trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.tex
Modified: trunk/Master/texmf-dist/doc/luatex/luakeys/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luakeys/README.md 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/doc/luatex/luakeys/README.md 2023-01-05 21:18:54 UTC (rev 65468)
@@ -14,7 +14,7 @@
## License
-Copyright 2021-2022 Josef Friedrich
+Copyright 2021-2023 Josef Friedrich
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License, either version 1.3c
@@ -48,11 +48,16 @@
-- Only values listed in the array table are allowed.
choices = { 'one', 'two', 'three' },
- -- Possible data types: boolean, dimension, integer, number, string
+ -- Possible data types:
+ -- any, boolean, dimension, integer, number, string, list
data_type = 'string',
+ -- To provide a default value for each naked key individually.
default = true,
+ -- Can serve as a comment.
+ description = 'Describe your key-value pair.',
+
-- The key belongs to a mutually exclusive group of keys.
exclusive_group = 'name',
@@ -64,11 +69,27 @@
-- The name of the key, can be omitted
name = 'key',
+
+ -- Convert opposite (naked) keys
+ -- into a boolean value and store this boolean under a target key:
+ -- show -> opposite_keys = true
+ -- hide -> opposite_keys = false
+ -- Short form: opposite_keys = { 'show', 'hide' }
opposite_keys = { [true] = 'show', [false] = 'hide' },
+
+ -- Pick a value by its data type:
+ -- 'any', 'string', 'number', 'dimension', 'integer', 'boolean'.
+ pick = false, -- ’false’ disables the picking.
+
+ -- A function whose return value is passed to the key.
process = function(value, input, result, unknown)
return value
end,
+
+ -- To enforce that a key must be specified.
required = true,
+
+ -- To build nested key-value pair definitions.
sub_keys = { key_level_2 = { } },
}
}
@@ -78,6 +99,9 @@
```lua
local opts = {
+ -- Result table that is filled with each call of the parse function.
+ accumulated_result = accumulated_result,
+
-- Configure the delimiter that assigns a value to a key.
assignment_operator = '=',
@@ -176,9 +200,6 @@
[Lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua)
extension in Visual Studio Code. This extension understands the modified
[EmmyLua annotations](https://github.com/sumneko/lua-language-server/wiki/Annotations).
-The Lua source code documentation is generated with
-[LDoc](https://stevedonovan.github.io/ldoc/manual/doc.md.html).
-
The Lua code is automatically formatted with the help of the
[LuaFormatter](https://github.com/Koihik/LuaFormatter).
@@ -212,7 +233,7 @@
Update version in:
-* luakeys-doc.tex
+* documentation.tex
* luakeys-debug.sty
* luakeys.sty
* luakeys.lua
Added: trunk/Master/texmf-dist/doc/luatex/luakeys/documentation.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luakeys/documentation.tex (rev 0)
+++ trunk/Master/texmf-dist/doc/luatex/luakeys/documentation.tex 2023-01-05 21:18:54 UTC (rev 65468)
@@ -0,0 +1,2161 @@
+\documentclass{ltxdoc}
+
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+
+\usepackage{mdframed}
+\usepackage{minted}
+\usepackage{luakeys}
+\usepackage{luakeys-debug}
+\usepackage{multicol}
+\usepackage{luacode}
+\usepackage{syntax}
+\usepackage{graphicx}
+
+\definecolor{bg}{rgb}{0.95,0.95,0.95}
+
+\usemintedstyle{friendly}
+\setminted{
+ breaklines=true,
+ fontsize=\footnotesize,
+ style=manni,
+}
+\def\lua#1{\mintinline{lua}|#1|}
+\def\latex#1{\mintinline{latex}|#1|}
+
+\NewDocumentCommand { \InputLatex } { O{} m } {
+ \inputminted[
+ linenos=false,
+ bgcolor=bg,
+ #1
+ ]{latex}{examples/#2}
+}
+
+\NewDocumentCommand { \InputLua } { O{} m } {
+ \inputminted[
+ linenos=false,
+ bgcolor=bg,
+ #1
+ ]{lua}{examples/#2}
+}
+
+\catcode`_=12
+\def\DefaultOpt#1{%
+ \texttt{\directlua{
+ tex.print(luakeys.print_default('opts', '#1'))
+ }}%
+}
+
+\def\DefaultOptDescription#1{
+\noindent
+The default value of the option “\texttt{#1}” is:
+\DefaultOpt{#1}.
+}
+
+\begin{document}
+
+\providecommand*{\url}{\texttt}
+
+\title{The \textsf{luakeys} package}
+\author{%
+ Josef Friedrich\\%
+ \url{josef at friedrich.rocks}\\%
+ \href{https://github.com/Josef-Friedrich/luakeys}
+ {github.com/Josef-Friedrich/luakeys}%
+}
+\date{v0.12.0 from 2023/01/05}
+
+\maketitle
+
+\vfill
+
+\InputLua[firstline=4,lastline=7]{first-page.lua}
+
+\noindent
+Result:
+
+\begin{center}
+\begin{minted}{lua}
+{
+ ['level1'] = {
+ ['level2'] = {
+ ['naked'] = true,
+ ['dim'] = 1864679,
+ ['bool'] = false,
+ ['num'] = -0.001,
+ ['str'] = 'lua,{}',
+ }
+ }
+}
+\end{minted}
+\end{center}
+
+\vfill
+
+\strut
+
+\newpage
+
+\tableofcontents
+
+\newpage
+
+% \section{Einführung}
+\section{Introduction}
+
+\noindent
+% |luakeys| ist ein Lua-Modul / Lua\TeX package, das wie die Pakete ...
+% Schlüssel-Wert-Optionen analysieren kann.
+|luakeys| is a Lua module / Lua\TeX{} package that can parse key-value
+options like the \TeX{} packages
+\href{https://www.ctan.org/pkg/keyval}{keyval},
+\href{https://www.ctan.org/pkg/kvsetkeys}{kvsetkeys},
+\href{https://www.ctan.org/pkg/kvoptions}{kvoptions},
+\href{https://www.ctan.org/pkg/xkeyval}{xkeyval},
+\href{https://www.ctan.org/pkg/pgfkeys}{pgfkeys} etc.
+%
+% |luakeys|, erfüllt diese Aufgabe jedoch, indem es die Sprache Lua
+% verwendet und nicht auf \TeX{} angewiesen ist.
+|luakeys|, however, accomplishes this task by using the Lua language and
+doesn’t rely on \TeX{}.
+%
+% Deshalb kann dieses Paket nur mit der \TeX{}-Engine Lua\TeX{}
+% verwendet werden.
+Therefore this package can only be used with the
+\TeX{} engine Lua\TeX{}.
+%
+% Da |luakeys| \href{http://www.inf.puc-rio.br/~roberto/lpeg/}{LPeg}
+% verwendet, sollte der Parsing-Mechanismus ziemlich robust sein.
+Since |luakeys| uses
+\href{http://www.inf.puc-rio.br/~roberto/lpeg/}{LPeg}, the parsing
+mechanism should be pretty robust.
+
+% Der Artikel TUGboat
+% \href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf}
+% {“Implementing key–value input: An introduction” (Volume 30 (2009), No.
+% 1)} von \emph{Joseph Wright} und \emph{Christian Feuersänger} gibt einen
+% einen guten Überblick über die verfügbaren Key-Value-Pakete.
+The TUGboat article
+\href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf}
+{“Implementing key–value input: An introduction” (Volume 30 (2009), No.
+1)} by \emph{Joseph Wright} and \emph{Christian Feuersänger} gives a
+good overview of the available key-value packages.
+%
+% Dieser Artikel geht auf eine auf tex.stackexchange.com von Will
+% Robertson: gestellte Frage zurück.
+This article is based on a question asked on tex.stackexchange.com by
+Will Robertson:
+\href{https://tex.stackexchange.com/questions/26771}
+{A big list of every keyval package}.
+%
+% CTAN stellt auch eine Übersichtsseite zum Thema bereit.
+CTAN also provides an overview page on the subject of
+\href{https://www.ctan.org/topic/keyval}
+{Key-Val: packages with key-value argument systems}.
+
+% Dieses Paket wäre ohne den Artikel
+% \href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf}
+% {"Parsing complex data formats in LuaTEX with LPEG" (Volume 40 (2019),
+% No. 2)} nicht möglich gewesen.
+This package would not be possible without the article
+\href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf}
+{“Parsing complex data formats in LuaTEX with LPEG” (Volume 40 (2019),
+No. 2)}.
+
+\subsection{Pros of \texttt{luakeys}}
+
+\begin{itemize}
+% \item Schlüssel-Wert-Paare können unabhängig vom Makro-Paket (latex or
+% context) analysiert werden.
+\item Key-value pairs can be parsed independently of the macro
+collection (\LaTeX{} or Con\TeX{}t).
+% Sogar in Plain LuaTex können Schlüssel analysiert werden
+Even in plain Lua\TeX{} keys can be parsed.
+
+% \item |luakeys| kann mit ineinander verschachtelten listen an
+% Schlüssel-Wert-Paaren umgehen, d. h. es kann mit einer rekursiven
+% Datenstruktur an Schlüssel umgehen.
+\item |luakeys| can handle nested lists of key-value pairs, i.e. it can
+handle a recursive data structure of keys.
+
+% \item Schlüssel müssen nicht, aber können definiert werden.
+\item Keys do not have to be defined, but can they can be defined.
+\end{itemize}
+
+\subsection{Cons of \texttt{luakeys}}
+
+\begin{itemize}
+% \item Das Packet funktioniert nur in der Verbindung mit Lua\TeX.
+\item The package works only in combination with Lua\TeX.
+
+% \item Du musst zwei Sprachen beherrschen: \TeX{} und Lua.
+\item You need to know two languages: \TeX{} and Lua.
+\end{itemize}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+% \section{Wie das Paket geladen wird}
+\section{How the package is loaded}
+
+%%
+%
+%%
+
+\subsection{Using the Lua module \texttt{luakeys.lua}}
+
+% Die Kernfunktionalität dieses Pakets ist in Lua realisiert.
+The core functionality of this package is realized in Lua.
+%
+% Sie können also |luakeys| auch ohne die Wrapper-Dateien
+% \texttt{luakeys.sty} und \texttt{luakeys.tex} verwenden.
+So you can use |luakeys| even without using the wrapper files
+|luakeys.sty| and |luakeys.tex|.
+
+\InputLatex{loading/lua.tex}
+
+%%
+%
+%%
+
+\subsection{Using the Lua\LaTeX{} wrapper \texttt{luakeys.sty}}
+
+% Der Paketmanager MikTeX lädt beispielsweise Pakete erst bei Bedarf
+% herunter.
+For example, the MiK\TeX{} package manager downloads packages only when
+needed.
+%
+% Es wurde berichtet, dass dieser automatische Download nur mit Hilfe
+% der Hüll-Dateien funktioniert.
+It has been reported that this automatic download only works with this
+wrapper files.
+%
+% Wahrscheinlich hält MiK\TeX nach einem Auftreten des LaTeX macros
+% “\latex{\usepackage{luakeys}} ”Ausschau.
+Probably MiK\TeX{} is searching for an occurrence of the \LaTeX{} macro
+“\latex{\usepackage{luakeys}}”.
+%
+% Die Datei \texttt{luakeys.sty} lädt das Lua-Modul in die globale
+% Variable \texttt{luakeys}.
+The \texttt{luakeys.sty} file loads the Lua module into the global
+variable \texttt{luakeys}.
+
+\InputLatex{loading/tex-latex.tex}
+
+%%
+%
+%%
+
+% \subsection{Verwendung des Plain-Lua\TeX{}-Hüllpakets
+% \texttt{luakeys.tex}}
+\subsection{Using the plain Lua\TeX{} wrapper \texttt{luakeys.tex}}
+
+\noindent
+% Es macht dasselbe wie das Lua\LaTeX{}-Hüllpacket und lädt das
+% Lua-Modul \texttt{luakeys.lua} in die globale Variable
+% \texttt{luakeys}.
+The file \texttt{luakeys.tex} does the same as the Lua\LaTeX{} wrapper
+and loads the Lua module \texttt{luakeys.lua} into the global variable
+\texttt{luakeys}.
+
+\InputLatex{loading/tex-plain.tex}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Lua interface / API}
+
+% Luakeys exportiert nur eine Funktion, die aufgerufen werden muss, um auf
+% die öffentliche API zuzugreifen
+Luakeys exports only one function that must be called to access the
+public API.
+%
+% Das Lua-Modul exportiert diese Funktionen und Tabellen:
+The Lua module exports this functions and tables:
+
+\InputLua[firstline=3,lastline=16]{export.lua}
+
+% Das Projekt verwendet einige wenige Abkürzungen für Variablennamen,
+% die hoffentlich für externe Leser eindeutig und bekannt sind.
+The project uses a few abbreviations for variable names that are
+hopefully unambiguous and familiar to external readers.
+
+\begin{center}
+\begin{tabular}{lll}
+Abbreviation & spelled out & Example \\\hline
+\lua{kv_string} & Key-value string & \lua{'key=value'} \\
+\lua{opts} & Options (for the parse function) &
+\lua{ { no_error = false } } \\
+\lua{defs} & Definitions \\
+\lua{def} & Definition \\
+\lua{attr} & Attributes (of a definition) \\
+\end{tabular}
+\end{center}
+
+\noindent
+% Diese nicht abgekürzten Variablennamen werden häufig verwendet.
+These unabbreviated variable names are commonly used.
+\begin{center}
+\begin{tabular}{ll}
+
+\lua{result} &
+% Das Endergebnis aller einzelnen Übersetzungs- und
+% Normalisierungsschritte
+The final result of all individual parsing and normalization steps. \\
+
+\lua{unknown} &
+% Ein Tabelle mit unbekannten, nicht definierten Schlüssel-Wert-Paaren
+A table with unknown, undefinied key-value pairs. \\
+
+\lua{raw} &
+% Das unbearbeitete, rohe Ergebnis der LPeg-Syntaxanalyse.
+The raw result of the Lpeg grammar parser. \\
+\end{tabular}
+\end{center}
+
+%%
+%
+%%
+
+\subsection{Function “\texttt{parse(kv_string, opts): result, unknown,
+raw}”}
+\label{parse}
+
+% Die Function parse ist die wichtigste Funktion des Pakets.
+The function \lua{parse(kv_string, opts)} is the most important function
+of the package.
+%
+%
+% Sie konvertiert eine Schlüssel-Wert-Zeichenkette in eine Lua Tabelle.
+It converts a key-value string into a Lua table.
+
+\InputLatex{functions/parse/tex-latex.tex}
+
+\noindent
+In plain \TeX:
+
+\InputLatex{functions/parse/tex-plain.tex}
+
+\subsection{Options to configure the \texttt{parse} function}
+
+\noindent
+% Die Funktion \lua{parse} kann mit einer Optionstabelle aufgerufen
+% werden.
+The \lua{parse} function can be called with an options table.
+% Diese Optionen werden unterstützt:
+This options are supported: \catcode`_=12
+\directlua{luakeys.print_names('opts')}
+
+\InputLua[firstline=7,lastline=99]{opts/all-opts.lua}
+
+\subsection{Table “\texttt{opts}”}
+\label{table-opts}
+
+\noindent
+% Die Optionen können auch global über die exportierte Tabelle
+% \lua{opts} gesetzt werden:
+The options can also be set globally using the exported table
+\lua{opts}:
+
+\InputLua[firstline=4,lastline=4]{opts/exported-default-opts.lua}
+
+\InputLua[firstline=10,lastline=11]{opts/exported-default-opts.lua}
+
+\noindent
+% Damit es zu keinen Wechselwirkungen mit anderen Paketen kommt, die auch
+% |luakeys| verwenden und die Optionen global setzen, ist es anzuraten,
+% die Funktion \lua{get_private_instance()} zum Laden das Paket verwenden.
+To avoid interactions with other packages that also use |luakeys| and
+set the options globally, it is recommended to use the
+\lua{get_private_instance()} function
+(\ref{function:get-private-instance}) to load the package.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{accumulated_result}”}
+
+% Streng genommen handelt es sich hier um keine Option
+Strictly speaking, this is not an option.
+%
+% Mit der Option \lua{accumulated_result} kann eine Ergebnistabelle
+% angegeben werden, die bei jedem Aufruf der \lua{parse}-Funktion weiter
+% befüllt wird.
+The \lua{accumulated_result} “option” can be used to specify a result
+table that is filled with each call of the \lua{parse} function.
+
+\InputLua[firstline=5,lastline=14]{opts/accumulated-result.lua}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{assignment_operator}”}
+\label{option:assignment-operator}
+\label{options-delimiter}
+
+The option \lua{assignment_operator} configures the delimiter that
+assigns a value to a key. The default value of this option is
+\texttt{"="}.
+
+The code example below demonstrates all six delimiter related options.
+
+\InputLua[firstline=4,lastline=13]{opts/delimiters.lua}
+
+\begin{tabular}{ll}
+\textbf{Delimiter options} & \textbf{Section} \\
+assignment_operator & \ref{option:assignment-operator}\\
+group_begin & \ref{option:group-begin}\\
+group_end & \ref{option:group-end}\\
+list_separator & \ref{option:list-separator}\\
+quotation_begin & \ref{option:quotation-begin}\\
+quotation_end & \ref{option:quotation-end}\\
+\end{tabular}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{convert_dimensions}”}
+
+% Wenn Sie die Option \lua{convert_dimensions} auf \lua{true} setzen,
+% erkennt |luakeys| die \TeX{}-Dimensionen und konvertiert sie mit Hilfe
+% der die Funktion \lua{tex.sp(dim)} in scaled points.
+If you set the option \lua{convert_dimensions} to \lua{true}, |luakeys|
+detects the \TeX{} dimensions and converts them into scaled points using
+the function \lua{tex.sp(dim)}.
+
+\InputLua[firstline=4,lastline=7]{opts/convert-dimensions/true.lua}
+
+\noindent
+% Standardmäßig werden die Dimensionen nicht in skalierte Punkte
+% umgewandelt.
+By default the dimensions are not converted into scaled points.
+
+\InputLua[firstline=4,lastline=9]{opts/convert-dimensions/false.lua}
+
+\noindent
+% Wenn Sie eine skalierte Punktzahl in einen Dimensionszeichenketten
+% umwandeln möchten, können Sie das Modul
+If you want to convert a scaled points number into a dimension string
+you can use the module
+\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua}
+{lualibs-util-dim.lua}.
+
+\begin{minted}{lua}
+require('lualibs')
+tex.print(number.todimen(tex.sp('1cm'), 'cm', '%0.0F%s'))
+\end{minted}
+
+\DefaultOptDescription{convert_dimensions}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{debug}”}
+
+% Wenn die Option \lua{debug} auf true gesetzt ist, wird die
+% Ergebnistabelle in der Konsole ausgegeben.
+If the option \lua{debug} is set to true, the result table is printed to
+the console.
+
+\InputLatex{opts/debug-latex.tex}
+
+\begin{verbatim}
+This is LuaHBTeX, Version 1.15.0 (TeX Live 2022)
+...
+(./debug.aux) (/usr/local/texlive/texmf-dist/tex/latex/base/ts1cmr.fd)
+{
+ ['three'] = true,
+ ['two'] = true,
+ ['one'] = true,
+}
+ [1{/usr/
+local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./debug.aux)
+)
+...
+Transcript written on debug.log.
+\end{verbatim}
+
+\DefaultOptDescription{debug}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{default}”}
+\label{option-default}
+
+% Mit der Option \lua{default} kann angegeben werden, welchen Wert
+% nackte Schlüssel (Schlüssel ohne Wert) erhalten. Diese Option hat
+% keinen Einfluss auf Schlüssel mit Werten.
+The option \lua{default} can be used to specify which value naked keys
+(keys without a value) get. This option has no influence on keys with
+values.
+
+\InputLua[firstline=4,lastline=5]{opts/default.lua}
+
+\noindent
+% Standardmäßig erhalten nackte Schlüssel den Wert \lua{true}.
+By default, naked keys get the value \lua{true}.
+
+\InputLua[firstline=11,lastline=12]{opts/default.lua}
+
+\DefaultOptDescription{default}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{defaults}”}
+\label{options-defaults}
+
+% Mit der Attribut „defaults“ kann nicht nur ein einiger Standardwert
+% angegeben werden, sondern eine ganze Tabelle mit Standardwerten.
+The option “defaults” can be used to specify not only one default value,
+but a whole table of default values.
+% Die Ergebnistabelle wird mit der Tabelle bestehend aus Standardwerten
+% vereinigt.
+The result table is merged into the defaults table.
+% Werte aus der Tabelle mit Standardwerten werden von Werten der
+% Ergebnistabelle überschrieben.
+Values in the defaults table are
+overwritten by values in the result table.
+
+\InputLua[firstline=4,lastline=7]{opts/defaults.lua}
+
+\DefaultOptDescription{defaults}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{defs}”}
+
+% Für mehr Information wie Schlüssel definiert werden, lesen sie das
+% kapitel 3.2
+For more informations on how keys are defined, see section \ref{define}.
+% Wenn sie die Option \lua{defs} verwenden, können sie auf den
+% Aufruf der Funktion \lua{define} verzichten.
+If you use the \lua{defs} option, you don't need to call the
+\lua{define} function.
+%
+% Anstatt
+Instead of ...
+
+\InputLua[firstline=4,lastline=5]{opts/defs.lua}
+
+\noindent
+% können wir schreiben ..
+we can write ...
+
+\InputLua[firstline=11,lastline=13]{opts/defs.lua}
+
+\DefaultOptDescription{defs}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{false_aliases}”}
+\label{option:false-aliases}
+
+% Mit den den Optionen \lua{true_aliases} and \lua{false_aliases} können
+% die Zeichenketten festgelegt werden, die vom Parser als Wahrheitswerte
+% erkannt werden.
+The \lua{true_aliases} and \lua{false_aliases} options can be used to
+specify the strings that will be recognized as boolean values by the
+parser.
+% Standardmäßig sind folgende Zeichenketten konfiguriert
+The following strings are configured by default.
+
+\InputLua[firstline=4,lastline=8]{opts/boolean-aliases.lua}
+
+\InputLua[firstline=14,lastline=18]{opts/boolean-aliases.lua}
+
+\InputLua[firstline=24,lastline=28]{opts/boolean-aliases.lua}
+
+% Siehe Abschnitt \label{option:true-aliases} für die entsprechende
+% Option.
+See section \ref{option:true-aliases} for the corresponding option.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{format_keys}”}
+
+% Mit Hilfe der Option \lua{format_keys} können die Schlüssel formatiert
+% werden.
+With the help of the option \lua{format_keys} the keys can be formatted.
+% Die Werte dieser Option müssen in einer Tabelle angegeben werden.
+The values of this option must be specified in a table.
+
+\begin{description}
+\item[lower]
+
+% Um alle Schlüssel in \emph{Kleinbuchstaben} umzuwandeln, geben sie in
+% der Optionentabelle \lua{lower} an.
+To convert all keys to \emph{lowercase}, specify \lua{lower} in the
+options table.
+
+\InputLua[firstline=4,lastline=5]{opts/format-keys.lua}
+
+\item[snake]
+
+% Um alle Schlüssel in \emph{snake case} (Die Wörter sind durch
+% Unterstriche getrennt) umzuwandeln, geben sie in der Optionentabelle
+% \lua{snake} an.
+To make all keys \emph{snake case} (The words are separated by
+underscores), specify \lua{snake} in the options
+table.
+
+\InputLua[firstline=11,lastline=12]{opts/format-keys.lua}
+
+\item[upper]
+
+% Um alle Schlüssel in \emph{Grossbuchstaben} umzuwandeln, geben sie in
+% der Optionentabelle \lua{upper} an.
+To convert all keys to \emph{uppercase}, specify \lua{upper} in the
+options table.
+
+\InputLua[firstline=18,lastline=19]{opts/format-keys.lua}
+\end{description}
+
+% Sie können auch mehrere Formatierungsarten kombinieren.
+You can also combine several types of formatting.
+
+\InputLua[firstline=25,lastline=26]{opts/format-keys.lua}
+
+\DefaultOptDescription{format_keys}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{group_begin}”}
+\label{option:group-begin}
+
+The option \lua{group_begin} configures the delimiter that marks the
+beginning of a group. The default value of this option is \texttt{"\{"}.
+A code example can be found in section \ref{options-delimiter}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{group_end}”}
+\label{option:group-end}
+
+The option \lua{group_end} configures the delimiter that marks the end
+of a group. The default value of this option is \texttt{"\}"}. A code
+example can be found in section \ref{options-delimiter}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{invert_flag}”}
+
+% Wird ein nackter Schlüssel mit einem vorangestellten Ausrufezeichen versehen, so wird sein Standardwert invertiert.
+If a naked key is prefixed with an exclamation mark, its default value
+is inverted.
+% Statt \lua{true} nimmt der Schlüssel jetzt den Wert \lua{falsch} an.
+Instead of \lua{true} the key now takes the value \lua{false}.
+
+\InputLua[firstline=4,lastline=5]{opts/invert-flat.lua}
+
+\noindent
+% Mit der Option \lua{invert_flag} kann dieses Invertierungszeichen
+% geändert werden.
+The \lua{invert_flag} option can be used to change this inversion
+character.
+
+\InputLua[firstline=11,lastline=12]{opts/invert-flat.lua}
+
+\noindent
+% Ist der Standardwert für nackte Schlüssel beispielweise auf \lua{false}
+% gesetzt, so nehmen die mit dem Umkehrungszeichen versehenen nackten
+% Schlüssel den Wert \lua{true} an.
+For example, if the default value for naked keys is set to \lua{false},
+the naked keys prefixed with the invert flat take the value \lua{true}.
+
+\InputLua[firstline=18,lastline=19]{opts/invert-flat.lua}
+
+\noindent
+% Setzen sie die Option \lua{invert_flag} auf \lua{false}, um diese
+% automatische Wertumkehrung zu deaktivieren.
+Set the \lua{invert_flag} option to \lua{false} to disable this
+automatic boolean value inversion.
+
+\InputLua[firstline=25,lastline=26]{opts/invert-flat.lua}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{hooks}”}
+
+% Die folgenden Hooks bzw. Callback-Funktionen ermöglichen es in den
+% Verarbeitungsprozess der \lua{parse}-Function einzugreifen.
+The following hooks or callback functions allow to intervene in the
+processing of the \lua{parse} function.
+%
+% Die Funktionen sind in der Verarbeitungsreihenfolge aufgelistet.
+The functions are listed in processing order.
+%
+% \lua{*_before_opts} bedeutet, dass die Hooks nach der LPeg
+% Syntaxanalyse und vor dem Anwenden der Optionen ausgeführt
+\lua{*_before_opts} means that the hooks are executed after the LPeg
+syntax analysis and before the options are applied.
+%
+% Die Hooks \lua{*_before_defs} werden vor dem Anwenden der
+% Schlüssel-Wert-Definitionen ausgeführt
+The \lua{*_before_defs} hooks are executed before applying the key value
+definitions.
+
+\def\TmpSignature#1{
+ {
+ \scriptsize\texttt{ = #1}
+ }
+}
+
+\def\TmpKeySignature{
+ \TmpSignature{function(key, value, depth, current, result): key, value}
+}
+\def\TmpResultSignature{
+ \TmpSignature{function(result): void}
+}
+
+\begin{enumerate}
+\item \lua{kv_string} \TmpSignature{function(kv_string): kv_string}
+\item \lua{keys_before_opts} \TmpKeySignature
+\item \lua{result_before_opts} \TmpResultSignature
+\item \lua{keys_before_def} \TmpKeySignature
+\item \lua{result_before_def} \TmpResultSignature
+\item (\lua{process}) (has to be definied using defs, see \ref{attr-process})
+\item \lua{keys} \TmpKeySignature
+\item \lua{result} \TmpResultSignature
+\end{enumerate}
+
+\paragraph{\texttt{kv_string}}
+
+% Der Hook \lua{kv_string} wird als erste
+% der Hook-Funktionen noch vor der LPeg-Syntax-Analyse aufgerufen.
+The \lua{kv_string} hook is called as the first of the hook functions
+before the LPeg syntax parser is executed.
+
+\InputLua[firstline=4,lastline=11]{hooks/kv-string.lua}
+
+\paragraph{\texttt{keys_*}}
+
+% Die Hooks \lua{keys_*} werden rekursiv auf jeden Schlüssel in der
+% aktuellen Ergebnistabelle aufgerufen.
+The hooks \lua{keys_*} are called recursively on each key in the current
+result table.
+% Die Hook-Funktion muss zwei Werte zurückgeben: \lua{key, value}
+The hook function must return two values: \lua{key, value}.
+%
+% Das folgende Beispiel gibt \lua{key} und \lua{value} unverändert
+% zurück, sodass die Ergebnistabelle nicht verändert wird.
+The following example returns \lua{key} and \lua{value} unchanged, so
+the result table is not changed.
+
+\InputLua[firstline=4,lastline=11]{hooks/keys-unchanged.lua}
+
+\noindent
+% Das nächste Beispiel demonstriert den dritten Parameter \lua{depth}
+% der Hook-Funktion.
+The next example demonstrates the third parameter \lua{depth} of the
+hook function.
+
+\InputLua[firstline=4,lastline=16]{hooks/keys-depth.lua}
+
+\paragraph{\texttt{result_*}}
+
+% Die Hooks \lua{result_*} werden einmal mit der aktuellen
+% Ergebnistabelle als Parameter aufgerufen.
+The hooks \lua{result_*} are called once with the current result table
+as a parameter.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{list_separator}”}
+\label{option:list-separator}
+
+The option \lua{list_separator} configures the delimiter that separates
+list items from each other. The default value of this option is
+\texttt{","}. A code example can be found in section
+\ref{options-delimiter}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{naked_as_value}”}
+
+% Mit Hilfe der Option \lua{naked_as_value} werden nackte Schlüssel
+% nicht mit einem Standardwert versehen, sondern als Werte in die
+% Lua-Tabelle abgelegt.
+With the help of the option \lua{naked_as_value}, naked keys are not
+given a default value, but are stored as values in a Lua table.
+
+\InputLua[firstline=4,lastline=5]{opts/naked-as-value.lua}
+
+\noindent
+If we set the option \lua{naked_as_value} to \lua{true}:
+
+\InputLua[firstline=11,lastline=14]{opts/naked-as-value.lua}
+
+\DefaultOptDescription{naked_as_value}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{no_error}”}
+
+% Standardmaßig wirft parse-Funktion einen Fehler, wenn es unbekannte
+% Schlüssel gibt.
+By default the parse function throws an error if there are unknown keys.
+% Mit Hilfe der Option \lua{no_error} kann dies unterbunden werden.
+This can be prevented with the help of the \lua{no_error} option.
+
+\InputLua[firstline=5,lastline=6]{opts/no-error.lua}
+
+\noindent
+If we set the option \lua{no_error} to \lua{true}:
+
+\InputLua[firstline=9,lastline=10]{opts/no-error.lua}
+
+\DefaultOptDescription{no_error}
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{quotation_begin}”}
+\label{option:quotation-begin}
+
+The option \lua{quotation_begin} configures the delimiter that marks the
+beginning of a string. The default value of this option is
+\texttt{'"'} (double quotes). A code example can be found in section
+\ref{options-delimiter}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{quotation_end}”}
+\label{option:quotation-end}
+
+The option \lua{quotation_end} configures the delimiter that marks the
+end of a string. The default value of this option is \texttt{'"'}
+(double quotes). A code example can be found in section
+\ref{options-delimiter}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{true_aliases}”}
+\label{option:true-aliases}
+
+See section \ref{option:false-aliases}.
+
+%%
+%
+%%
+
+\subsubsection{Option “\texttt{unpack}”}
+
+% Mit Hilfe der Option \lua{unpack} werden alle Tabellen, die nur aus
+% einem einzigen nackten Schlüssel bzw. einen einzigen alleinstehenden
+% Wert bestehen, aufgelöst.
+With the help of the option \lua{unpack}, all tables that consist of
+only a single naked key or a single standalone value are unpacked.
+
+\InputLua[firstline=4,lastline=5]{opts/unpack.lua}
+
+\InputLua[firstline=11,lastline=12]{opts/unpack.lua}
+
+\DefaultOptDescription{unpack}
+
+%%
+%
+%%
+
+\subsection{Function “\texttt{define(defs, opts): parse}”}
+\label{define}
+
+The \lua{define} function returns a \lua{parse} function (see
+\ref{parse}).
+The name of a key can be specified in three ways:
+
+\begin{enumerate}
+\item as a string.
+\item as a key in a Lua table. The definition of the corresponding
+key-value pair is then stored under this key.
+\item by the “name” attribute.
+\end{enumerate}
+
+\InputLua[firstline=4,lastline=16]{functions/define.lua}
+
+\noindent
+% Bei verschachtelten Definitionen können nur die letzten beiden
+% Möglichkeiten zur Angabe der Schlüsselnamen verwendet werden.
+For nested definitions, only the last two ways of specifying the key
+names can be used.
+
+\InputLua[firstline=26,lastline=33]{functions/define.lua}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\subsection{Attributes to define a key-value pair}
+
+% Die Definition eines Schlüssel-Wert-Paares kann mit Hilfe von
+% verschiedenen Attributen vorgenommen werden.
+The definition of a key-value pair can be made with the help of various
+attributes.
+%
+% Der Name „Attribut“ für eine Option, einen Schlüssel, eine Eigenschaft
+% (um nur einige Benennungsmöglichkeiten aufzuzählen) zur
+% Schlüssel-Definition, wurde bewusst gewählt, um sie von den Optionen
+% der Funktion \lua{parse} zu unterscheiden.
+The name \emph{“attribute”} for an option, a key, a property ... (to
+list just a few naming possibilities) to define keys, was deliberately
+chosen to distinguish them from the options of the \lua{parse} function.
+%
+% Diese Attribute sind erlaubt.
+These attributes are allowed:
+\directlua{luakeys.print_names('attrs')}.
+%
+% Das folgende Codebeispiel listet alle Attribute auf, die verwendet
+% werden können, um Schlüssel-Wert-Paare zu definieren.
+The code example below lists all the attributes that can be used to
+define key-value pairs.
+
+\InputLua[firstline=5,lastline=62]{defs/all-attrs.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{alias}”}
+
+With the help of the \lua{alias} attribute, other key names can be used.
+The value is always stored under the original key name. A single alias
+name can be specified by a string ...
+
+\InputLua[firstline=4,lastline=7]{defs/attrs/alias.lua}
+
+\noindent
+multiple aliases by a list of strings.
+
+\InputLua[firstline=13,lastline=16]{defs/attrs/alias.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{always_present}”}
+
+% Die Option \lua{default} wird nur bei nackten Schlüsseln verwendet.
+The \lua{default} attribute is used only for naked keys.
+
+\InputLua[firstline=4,lastline=5]{defs/attrs/always-present.lua}
+
+\noindent
+% Wird die Option \lua{always_present} auf wahr gesetzt, wird der
+% Schlüssel immer ins Ergebnis mit übernommen.
+If the attribute \lua{always_present} is set to true, the key is always
+included in the result. If no default value is definied, true is taken
+as the value.
+
+\InputLua[firstline=11,lastline=12]{defs/attrs/always-present.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{choices}”}
+
+% source: Python argparse documentation.
+Some key values should be selected from a restricted set of choices.
+These can be handled by passing an array table containing choices.
+
+\InputLua[firstline=4,lastline=5]{defs/attrs/choices.lua}
+
+\noindent
+When the key-value pair is parsed, values will be checked, and an error
+message will be displayed if the value was not one of the acceptable
+choices:
+
+\InputLua[firstline=13,lastline=15]{defs/attrs/choices.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{data_type}”}
+
+% source: Python argparse documentation.
+The \lua{data_type} attribute allows type-checking and type conversions
+to be performed.
+%
+% Folgende Datentypen werden unterstützt:
+The following data types are supported:
+\lua{'boolean'},
+\lua{'dimension'},
+\lua{'integer'},
+\lua{'number'},
+\lua{'string'},
+\lua{'list'}.
+%
+% Bei den drei Datentypen integer, number, dimension kann eine
+% Typenumwandlung scheitern.
+A type conversion can fail with the three data types
+\lua{'dimension'},
+\lua{'integer'},
+\lua{'number'}.
+%
+% Dann wird eine Fehlermeldung ausgegeben.
+Then an error message is displayed.
+
+\InputLua[firstline=4,lastline=8]{defs/attrs/data-type.lua}
+\InputLua[firstline=11,lastline=15]{defs/attrs/data-type.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{default}”}
+
+% Verwenden Sie das Attribut „\lua{default}“, um für jeden nackten Schlüssel
+% einzeln einen Standardwert bereit zu stellen.
+Use the \lua{default} attribute to provide a default value for each naked
+key individually.
+%
+% Mit der globalen \lua{default} Option kann für alle nackten Schlüssel ein
+% Standardwert vorgegeben werden.
+With the global \lua{default} attribute (\ref{option-default}) a default
+value can be specified for all naked keys.
+
+\InputLua[firstline=4,lastline=9]{defs/attrs/default.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{description}”}
+
+% Dieses Attribut wird momentan nicht weiterverarbeitet.
+This attribute is currently not processed further.
+% Es kann als Kommentar dienen.
+It can serve as a comment.
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{exclusive_group}”}
+
+% Alle Schlüssel, die der gleichen ausschließenden Gruppe angehören,
+% dürfen nicht gemeinsam angegeben werden.
+All keys belonging to the same exclusive group must not be specified
+together.
+%
+% Nur ein Schlüssel aus dieser Gruppe ist erlaubt.
+Only one key from this group is allowed.
+%
+% Als Name für diese ausschließende Gruppe kann irgend ein beliebiger
+% Wert verwendet werden.
+Any value can be used as a name for this exclusive group.
+
+\InputLua[firstline=4,lastline=9]{defs/attrs/exclusive-group.lua}
+
+\noindent
+% Werden mehrer Schlüssel der Gruppe angegeben, so wird eine
+% Fehlermeldung geworfen.
+If more than one key of the group is specified, an error message is
+thrown.
+
+\InputLua[firstline=21,lastline=23]{defs/attrs/exclusive-group.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{macro}”}
+
+The attribute \texttt{macro} stores the value in a \TeX{} macro.
+
+\begin{minted}{lua}
+local parse = luakeys.define({
+ key = {
+ macro = 'MyMacro'
+ }
+})
+parse('key=value')
+\end{minted}
+
+\begin{minted}{latex}
+\MyMacro % expands to “value”
+\end{minted}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{match}”}
+
+% Der Wert des Schlüssel wird zuerst der Lua Funktion
+% \lua{string.match(value, match)} übergeben, bevor er dem Schlüssel
+% zugewiesen wird.
+The value of the key is first passed to the Lua function
+\lua{string.match(value, match)}
+(\url{http://www.lua.org/manual/5.3/manual.html#pdf-string.match})
+before being assigned to the key.
+%
+% Du kannst das Attribut \lua{match} deshalb mit einer Pattern-Matching-
+% Zeichenkette konfigurieren, wie sie in Lua zu Einsatz kommt.
+You can therefore configure the \lua{match} attribute with a pattern
+matching string used in Lua.
+%
+% Werfe einen Blick in das Lua-Handbuch, wie man Patterns schreibt.
+Take a look at the Lua manual on how to write patterns
+(\url{http://www.lua.org/manual/5.3/manual.html#6.4.1}).
+
+\InputLua[firstline=4,lastline=7]{defs/attrs/match/birthday.lua}
+
+\noindent
+% Kann das Pattern im Wert nicht gefunden werden, wird eine
+% Fehlermeldung ausgegeben.
+If the pattern cannot be found in the value, an error message is issued.
+
+\InputLua[firstline=15,lastline=18]{defs/attrs/match/birthday.lua}
+
+\noindent
+% Der Schlüssel erhält das Ergebnis der Funktion \lua{string.match(value,
+% match)}, dass bedeutet, dass der ursprüngliche Wert unter
+% Umständen nicht vollständig in den Schlüssel gespeichert wird.
+The key receives the result of the function \lua{string.match(value,
+match)}, which means that the original value may not be stored
+completely in the key.
+%
+% Im nächsten Beispiel wird der gesamte Eingabewert akzeptiert:
+In the next example, the entire input value is accepted:
+
+\InputLua[firstline=4,lastline=5]{defs/attrs/match/year.lua}
+
+\noindent
+% Das Präfix “waste ” und das Suffix “ rubbisch” der Zeichenketten wird
+% verworfen.
+The prefix “waste ” and the suffix “ rubbisch” of the string are
+discarded.
+
+\InputLua[firstline=11,lastline=11]{defs/attrs/match/year.lua}
+
+\noindent
+% Da Funktion \lua{string.match(value, match)} immer eine Zeichenkette
+% zurückgibt, ist der Wert des Schlüssel auch immer eine Zeichenkette.
+Since function \lua{string.match(value, match)} always returns a string,
+the value of the key is also always a string.
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{name}”}
+
+% Die Option \lua{name} ermöglicht eine alternative Notation von
+% Schlüsselnamen.
+The \lua{name} attribute allows an alternative notation of key names.
+%
+% Anstatt ...
+Instead of ...
+
+\InputLua[firstline=4,lastline=8]{defs/attrs/name/as-key.lua}
+
+\noindent
+% ... können wir schreiben:
+... we can write:
+
+\InputLua[firstline=4,lastline=8]{defs/attrs/name/name-attr.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{opposite_keys}”}
+
+% Die Option \lua{opposite_keys} ermöglicht es, gegensätzliche (nackte)
+% Schlüssel in Wahrheitswerte umzuwandeln und diesen Wahrheitswert unter
+% einem Zielschlüssel zu speichern.
+The \lua{opposite_keys} attribute allows to convert opposite (naked)
+keys into a boolean value and store this boolean under a target key.
+%
+% Lua erlaubt es in Tabellen Wahrheitswerte als Schlüssel zu verwenden.
+% Es müssen jedoch eckige Klammern verwendet werden.
+Lua allows boolean values to be used as keys in tables.
+%
+% Die Wahrheitswerte müssen jedoch in eckige Klammern geschrieben werden.
+However, the boolean values must be written in square brackets, e. g.
+\lua{{ opposite_keys = { [true] = 'show', [false] = 'hide' } }}.
+%
+% Beispiele für gegensätzliche Schlüssel sind:
+Examples of opposing keys are: \lua{show} and \lua{hide}, \lua{dark} and
+\lua{light}, \lua{question} and \lua{solution}.
+%
+% Das untenstehende Beispiel verwendet als gegensätzliches Schlüsselpaar
+% die Schlüssel \lua{show} und \lua{hide}.
+The example below uses the \lua{show} and \lua{hide} keys as the
+opposite key pair.
+%
+% Wird der Schlüssel \lua{show} von der Funktion \lua{parse} gelesen,
+% dann erhält der Zielschlüssel \lua{visibility} den Wert \lua{true}.
+If the key \lua{show} is parsed by the \lua{parse} function, then the
+target key \lua{visibility} receives the value \lua{true}.
+
+\InputLua[firstline=4,lastline=7]{defs/attrs/opposite-keys.lua}
+
+% Wird der Schlüssel \lua{hide} gelesen, dann \lua{falsch}.
+\noindent
+If the key \lua{hide} is parsed, then \lua{false}.
+
+\InputLua[firstline=13,lastline=13]{defs/attrs/opposite-keys.lua}
+
+\noindent
+% Gegensätzliche Schlüsselpaare können in einer Kurzschreibweise
+% angegeben werden, nämlich als Liste
+Opposing key pairs can be specified in a short form, namely as a list:
+% Der gegensätzliche Schlüssel, der den Wahrwert repräsentiert, muss in
+% dieser Liste zuerst angegeben werden, dann folgt der Falschwert.
+The opposite key, which represents the true value, must be specified
+first in this list, followed by the false value.
+
+\InputLua[firstline=19,lastline=21]{defs/attrs/opposite-keys.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{pick}”}
+
+% Das Attribut \lua{pick} sucht nach einem Wert, der keinem Schlüssel
+% zugeordnet ist.
+The attribute \lua{pick} searches for a value not assigned to a key.
+% Der zuerst gefundene Wert, d. h. der weiter links stehende Wert, wird
+% einem Schlüssel zugewiesen.
+The first value found, i.e. the one further to the left, is assigned to
+a key.
+
+\InputLua[firstline=4,lastline=6]{defs/attrs/pick/dimension.lua}
+
+\noindent
+% Es wird nur in der aktuellen Ergebnistabelle gesucht und nicht auf
+% anderen Ebenen in der rekursiven Datenstruktur.
+Only the current result table is searched, not other levels in the
+recursive data structure.
+
+\InputLua[firstline=4,lastline=11]{defs/attrs/pick/different-levels.lua}
+
+\noindent
+% Die Suche nach Werte wird aktiviert, wenn das Attribut \lua{pick} auf
+% \lua{true} gesetzt wird.
+The search for values is activated when the attribute \lua{pick} is set
+to a data type.
+% Mit diesen Datentypen kann nach Werten gesucht werden
+These data types can be used to search for values:
+string, number, dimension, integer, boolean, any.
+% Verwendet den Datentyp any um jeden beliebigen Wert zu akzeptieren.
+Use the data type “any” to accept any value.
+% Wird einem Schlüssel bereits bei der Eingabe ein Wert zugewiesen, dann
+% wird nicht weiter nach Werten gesucht.
+If a value is already assigned to a key when it is entered, then no
+further search for values is performed.
+\InputLua[firstline=4,lastline=8]{defs/attrs/pick/value-set.lua}
+
+\noindent
+% Das Attribut \lua{pick} akzeptiert auch mehrere Datentypen, die in
+% einer Tabelle angegeben werden.
+The \lua{pick} attribute also accepts multiple data types
+specified in a table.
+
+\InputLua[firstline=4,lastline=10]{defs/attrs/pick/multiple-data-types.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{process}”}
+\label{attr-process}
+
+% Das Attribut \lua{process} kann dazu verwendet werden, um eine Funktion
+% zu definieren, deren Rückgabewert an den Schlüssel übergeben wird.
+The \lua{process} attribute can be used to define a function whose
+return value is passed to the key.
+%
+% Beim Aufruf der Funktion werden vier Parameter übergeben:
+Four parameters are passed when the function is called:
+
+\begin{enumerate}
+\item \lua{value}:
+% Der zum Schlüssel gehörende aktuelle Wert.
+The current value asssociated with the key.
+
+\item \lua{input}:
+% Die Ergebnis-Tabelle, die vor dem Zeitpunkt geklont wurde, als mit dem
+% Anwenden der Definitionen begonnen wurde.
+The result table cloned before the time the definitions started to be
+applied.
+
+\item \lua{result}: The table in which the final result will be saved.
+
+\item \lua{unknown}: The table in which the unknown key-value pairs
+are stored.
+\end{enumerate}
+
+\noindent
+% Das folgende Beispiel demonstriert den Parameter \lua{value}:
+The following example demonstrates the \lua{value} parameter:
+\InputLua[firstline=4,lastline=14]{defs/attrs/process/parameter-value.lua}
+
+\noindent
+% Das folgende Beispiel demonstriert den Parameter \lua{input}:
+The following example demonstrates the \lua{input} parameter:
+
+\InputLua[firstline=4,lastline=16]{defs/attrs/process/parameter-input.lua}
+
+\noindent
+% Das folgende Beispiel demonstriert den Parameter \lua{result}:
+The following example demonstrates the \lua{result} parameter:
+
+\InputLua[firstline=4,lastline=12]{defs/attrs/process/parameter-result.lua}
+
+\noindent
+% Das folgende Beispiel demonstriert den Parameter \lua{unknown}:
+The following example demonstrates the \lua{unknown} parameter:
+
+\InputLua[firstline=4,lastline=11]{defs/attrs/process/parameter-unknown.lua}
+\InputLua[firstline=15,lastline=15]{defs/attrs/process/parameter-unknown.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{required}”}
+
+% Durch das Attribut \lua{required} kann erzwungen werden, dass ein
+% bestimmter Schlüssel angegeben werden muss.
+The \lua{required} attribute can be used to enforce that a specific key
+must be specified.
+%
+% Im untenstehenden Beispiel wird der Schlüssel \lua{important} als
+% zwingend notwendig definiert.
+In the example below, the key \lua{important} is defined as mandatory.
+
+\InputLua[firstline=4,lastline=5]{defs/attrs/required.lua}
+
+\noindent
+% Fehlt der Schlüssel \lua{important} in der Eingabe, so tritt eine
+% Fehlermeldung auf.
+If the key \lua{important} is missing in the input, an error message
+occurs.
+
+\InputLua[firstline=13,lastline=14]{defs/attrs/required.lua}
+
+\noindent
+A recursive example:
+
+\InputLua[firstline=18,lastline=23]{defs/attrs/required.lua}
+
+\noindent
+% Der Schlüssel \lua{important2} auf der Ebene 2 fehlt.
+The \lua{important2} key on level 2 is missing.
+
+\InputLua[firstline=29,lastline=30]{defs/attrs/required.lua}
+
+\noindent
+% Der Schlüssel \lua{important1} auf der untersten Schlüssel-Ebene fehlt.
+The \lua{important1} key at the lowest key level is missing.
+
+\InputLua[firstline=38,lastline=39]{defs/attrs/required.lua}
+
+%%
+%
+%%
+
+\subsubsection{Attribute “\texttt{sub_keys}”}
+
+% Mit dem Attribut \lua{sub_keys} können ineinander verschachtelte
+% Schlüssel-Wert-Paar-Definitionen aufgebaut werden.
+The \lua{sub_keys} attribute can be used to build nested key-value pair
+definitions.
+
+\InputLua[firstline=4,lastline=16]{defs/attrs/sub-keys.lua}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\subsection{Function “\texttt{render(result): string}”}
+
+The function \lua{render(result)} reverses the function
+\lua{parse(kv_string)}. It takes a Lua table and converts this table
+into a key-value string. The resulting string usually has a different
+order as the input table.
+
+\InputLua[firstline=4,lastline=10]{functions/render.lua}
+
+\noindent
+In Lua only tables with 1-based consecutive integer keys (a.k.a. array
+tables) can be parsed in order.
+
+\InputLua[firstline=16,lastline=17]{functions/render.lua}
+
+%%
+%
+%%
+
+\subsection{Function “\texttt{debug(result): void}”}
+
+The function \lua{debug(result)} pretty prints a Lua table to standard
+output (stdout). It is a utility function that can be used to debug and
+inspect the resulting Lua table of the function \lua{parse}. You have to
+compile your \TeX{} document in a console to see the terminal output.
+
+\InputLua[firstline=4,lastline=5]{functions/debug.lua}
+
+\noindent
+The output should look like this:
+
+\begin{minted}{md}
+{
+ ['level1'] = {
+ ['level2'] = {
+ ['key'] = 'value',
+ },
+ }
+}
+\end{minted}
+
+%%
+%
+%%
+
+\subsection{Function “\texttt{save(identifier, result): void}”}
+
+The function \lua{save(identifier, result)} saves a result (a
+table from a previous run of \lua{parse}) under an identifier.
+Therefore, it is not necessary to pollute the global namespace to
+store results for the later usage.
+
+%%
+%
+%%
+
+\subsection{Function “\texttt{get(identifier): result}”}
+
+The function \lua{get(identifier)} retrieves a saved result from the
+result store.
+
+%%
+%
+%%
+
+\subsection{Table “\texttt{is}”}
+
+% In der Tabelle \lua{is} werden einige Funktionen zusammengefasst, die
+% überprüft ob eine Eingabe einem bestimmen Datentyp entspricht.
+In the table \lua{is} some functions are summarized, which check whether
+an input corresponds to a certain data type.
+%
+% Einige Funktionen akzeptieren nicht nur die entsprechenden
+% Lua-Datentypen, sondern auch Eingaben als Zeichenketten.
+Some functions accept not only the corresponding Lua data types, but also
+input as strings.
+%
+% Beispielsweise wird die Zeichenkette \lua{'true'} von der
+% \lua{is.boolean()}-Funktion als Wahrheitswert erkannt.
+For example, the string \lua{'true'} is recognized by the
+\lua{is.boolean()} function as a boolean value.
+
+\subsubsection{Function “\texttt{is.boolean(value): boolean}”}
+\InputLua[firstline=6,lastline=23]{functions/is/boolean.lua}
+
+\subsubsection{Function “\texttt{is.dimension(value): boolean}”}
+\InputLua[firstline=6,lastline=16]{functions/is/dimension.lua}
+
+\subsubsection{Function “\texttt{is.integer(value): boolean}”}
+\InputLua[firstline=6,lastline=11]{functions/is/integer.lua}
+
+\subsubsection{Function “\texttt{is.number(value): boolean}”}
+\InputLua[firstline=6,lastline=13]{functions/is/number.lua}
+
+\subsubsection{Function “\texttt{is.string(value): boolean}”}
+\InputLua[firstline=6,lastline=12]{functions/is/string.lua}
+
+\subsubsection{Function “\texttt{is.list(value): boolean}”}
+\InputLua[firstline=6,lastline=16]{functions/is/list.lua}
+
+\subsubsection{Function “\texttt{is.any(value): boolean}”}
+
+% Die Funktion \lua{is.any(value)} gibt immer wahr zurück und
+% akzeptiert deshalb jeden Datentyp.
+The function \lua{is.any(value)} always returns \lua{true} and
+therefore accepts any data type.
+
+%%
+%
+%%
+
+\subsection{Table “\texttt{utils}”}
+
+% In der Tabelle \lua{utils} sind einige Hilfsfunktionen gebündelt.
+The \lua{utils} table bundles some auxiliary functions.
+
+\InputLua[firstline=3,lastline=34]{utils/all.lua}
+
+%%
+%
+%%
+
+\subsubsection{Function “\texttt{utils.merge_tables(target, source, overwrite): table}”}
+
+% Die Funktion \lua{merge_tables} führt zwei Tabellen in die erste
+% angegebene Tabelle zusammen. Sie kopiert Schlüssel aus der
+% `source` Tabelle in die `target`-Tabelle. Sie gibt die geänderte
+% Zieltabelle zurück.
+The function \lua{merge_tables} merges two tables into the first
+specified table. It copies keys from the `source` table into the
+`target` table. It returns the target table.
+
+% Wird der Parameter \lua{overwrite} auf wahr gesetzten, so werden Werte
+% in der Zieltabelle überschrieben
+If the \lua{overwrite} parameter is set to \lua{true}, values in the
+target table are overwritten.
+
+\InputLua[firstline=4,lastline=8]{utils/merge-tables.lua}
+
+\noindent
+% Geben sie dem Parameter \lua{overwrite} den Wert \lua{false}, um Werte
+% in der Zieltabelle zu überschreiben.
+Give the parameter \lua{overwrite} the value \lua{false} to overwrite
+values in the target table.
+
+\InputLua[firstline=14,lastline=18]{utils/merge-tables.lua}
+
+%%
+%
+%%
+
+\subsubsection{Function “\texttt{utils.scan_oarg(initial_delimiter?, end_delimiter?): string}”}
+
+% Plain \TeX{} kennt keine optionalen Argumente (oarg).
+Plain \TeX{} does not know optional arguments (oarg).
+%
+% Die Funktion ermöglicht es nicht nur in \LaTeX{}, sondern auch in
+% Plain \TeX{} nach optionalen Argumenten zu suchen.
+The function \\ \lua{utils.scan_oarg(initial_delimiter?,
+end_delimiter?): string} allows to search for optional arguments not only
+in \LaTeX{} but also in Plain \TeX.
+%
+% Die Funktion basiert auf der Token-Bibliothek.
+The function uses the token library built into Lua\TeX{}.
+%
+% Die beiden Parameter \lua{initial_delimiter} und \lua{end_delimiter}
+% können weggelassen werden.
+The two parameters \lua{initial_delimiter} and \lua{end_delimiter} can
+be omitted.
+%
+% Dann werden eckige Klammern als Begrenzungszeichen angenommen.
+Then square brackets are assumed to be delimiters.
+%
+% Dieser Lua-Code \lua{utils.scan_oarg('(', ')')} sucht beispielsweise
+% nach an einem optionalen Argument in runden Klammern.
+For example, this Lua code \lua{utils.scan_oarg('(', ')')} searches for
+an optional argument in round brackets
+%
+% Die Funktion gibt die Zeichenkette zwischen den Begrenzungszeichen
+% zurück, oder nil wenn Begrenzungszeichen gefunden werden konnten.
+The function returns the string between the delimiters or \lua{nil} if
+no delimiters could be found.
+%
+% Die Begrenzungszeichen sind im Ergebnis nicht enthalten.
+The delimiters themselves are not included in the result.
+%
+% Nach dem \latex{\directlua{}} darf das Makro, indem
+% \lua{utils.scan_oarg} eingesetzt wird, zu keinen Zeichen expandieren.
+After the \latex{\directlua{}}, the macro using \lua{utils.scan_oarg}
+must not expand to any characters.
+
+\InputLatex{utils/scan-oarg-plain.tex}
+
+%%
+%
+%%
+
+\subsection{Table “version”}
+
+% Das luakeys Projekt verwendet semantic versioning
+The luakeys project uses semantic versioning.
+% Die drei Versionenzahlen des Semantic Versioning Schemas werden in
+% einer Tabelle in der Reihenfolge MAJOR, MINOR, PATCH als Ganzzahlen
+% abgelegt.
+The three version numbers of the semantic versioning scheme are stored
+in a table as integers in the order MAJOR, MINOR, PATCH.
+% Mit Hilfe dieser Tabelle kann überprüft werden, ob die richtige
+% Version installiert ist.
+This table can be used to check whether the correct version is
+installed.
+
+\InputLua[firstline=4,lastline=10]{version.lua}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\section{Syntax of the recognized key-value format}
+
+%%
+%
+%%
+
+\subsection{An attempt to put the syntax into words}
+
+A key-value pair is definied by an equal sign (\texttt{key=value}).
+Several key-value pairs or keys without values (naked keys) are lined up
+with commas (\texttt{key=value,naked}) and build a key-value list. Curly
+brackets can be used to create a recursive data structure of nested
+key-value lists (\texttt{level1=\{level2=\{key=value,naked\}\}}).
+
+%%
+%
+%%
+
+\subsection{An (incomplete) attempt to put the syntax into the Extended Backus-Naur Form}
+
+\begin{grammar}
+<list> ::= \{ <list-item> \}
+
+<list-container> ::= `{' <list> `}'
+
+<list-item> ::= ( <list-container> | <key-value-pair> | <value> ) [ `,' ]
+
+<key-value-pair> ::= <value> `=' ( <list-container> | <value> )
+
+<value> ::= <boolean>
+ \alt <dimension>
+ \alt <number>
+ \alt <string-quoted>
+ \alt <string-unquoted>
+
+<dimension> ::= <number> <unit>
+
+<number> ::= <sign> ( <integer> [ <fractional> ] | <fractional> )
+
+<fractional> ::= `.' <integer>
+
+<sign> ::= `-' | `+'
+
+<integer> ::= <digit> \{ <digit> \}
+
+<digit> ::= `0' | `1' | `2' | `3' | `4' | `5' | `6' | `7' | `8' | `9'
+
+<unit> ::= `bp' | `BP'
+ \alt `cc' | `CC'
+ \alt `cm' | `CM'
+ \alt `dd' | `DD'
+ \alt `em' | `EM'
+ \alt `ex' | `EX'
+ \alt `in' | `IN'
+ \alt `mm' | `MM'
+ \alt `mu' | `MU'
+ \alt `nc' | `NC'
+ \alt `nd' | `ND'
+ \alt `pc' | `PC'
+ \alt `pt' | `PT'
+ \alt `px' | `PX'
+ \alt `sp' | `SP'
+
+<boolean> ::= <boolean-true> | <boolean-false>
+
+<boolean-true> ::= `true' | `TRUE' | `True'
+
+<boolean-false> ::= `false' | `FALSE' | `False'
+\end{grammar}
+
+... to be continued
+
+%%
+%
+%%
+
+\subsection{Recognized data types}
+
+\subsubsection{boolean}
+
+The strings \texttt{true}, \texttt{TRUE} and \texttt{True} are converted
+into Lua’s boolean type \lua{true}, the strings \texttt{false},
+\texttt{FALSE} and \texttt{False} into \lua{false}.
+
+\begin{multicols}{2}
+\InputLatex[firstline=5,lastline=12]{luakeysdebug/boolean-latex.tex}
+
+\columnbreak
+
+\begin{minted}{lua}
+{
+ ['lower case true'] = true,
+ ['upper case true'] = true,
+ ['title case true'] = true,
+ ['lower case false'] = false,
+ ['upper case false'] = false
+ ['title case false'] = false,
+}
+\end{minted}
+\end{multicols}
+
+%%
+%
+%%
+
+\subsubsection{number}
+
+\begin{multicols}{2}
+\InputLatex[firstline=5,lastline=13]{luakeysdebug/number-latex.tex}
+
+\columnbreak
+
+\begin{minted}{lua}
+{
+ ['num0'] = 42,
+ ['num1'] = 42,
+ ['num2'] = -42,
+ ['num3'] = 4.2,
+ ['num4'] = 0.42,
+ ['num5'] = 0.42,
+ ['num6'] = '0 . 42', -- string
+}
+\end{minted}
+\end{multicols}
+
+%%
+%
+%%
+
+\subsubsection{dimension}
+
+% Luakeys versucht alle Einheiten zu erkennen, die in der TeX-Welt
+% verwendet werden.
+|luakeys| tries to recognize all units used in the \TeX{} world.
+%
+% Nach dem Lua\TeX-Quellcode .
+According to the Lua\TeX{} source code
+(\href{https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625}
+{source/texk/web2c/luatexdir/lua/ltexlib.c})
+%
+% und nach dem Dimensionen-Modul der lulibs-Bibliothek
+and the dimension module of the lualibs library
+(\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua}
+{lualibs-util-dim.lua}),
+%
+% müssten alle Einheiten erkannt werden
+all units should be recognized.
+\begin{multicols}{3}
+\tiny
+\begin{center}
+\begin{tabular}{rl}
+% \textbf{Unit name}
+& \textbf{Description} \\\hline
+bp & big point \\
+cc & cicero \\
+cm & centimeter \\
+dd & didot \\
+em & horizontal measure of \emph{M} \\
+ex & vertical measure of \emph{x} \\
+in & inch \\
+mm & milimeter \\
+mu & math unit \\
+nc & new cicero \\
+nd & new didot \\
+pc & pica \\
+pt & point \\
+px & x height current font \\
+sp & scaledpoint \\
+\end{tabular}
+\end{center}
+
+\columnbreak
+
+\InputLatex[firstline=5,lastline=21]{luakeysdebug/dimension/all-latex.tex}
+
+\columnbreak
+
+\begin{minted}{lua}
+{
+ ['bp'] = 65781,
+ ['cc'] = 841489,
+ ['cm'] = 1864679,
+ ['dd'] = 70124,
+ ['em'] = 655360,
+ ['ex'] = 282460,
+ ['in'] = 4736286,
+ ['mm'] = 186467,
+ ['mu'] = 65536,
+ ['nc'] = 839105,
+ ['nd'] = 69925,
+ ['pc'] = 786432,
+ ['pt'] = 65536,
+ ['px'] = 65781,
+ ['sp'] = 1,
+}
+\end{minted}
+\end{multicols}
+
+\noindent
+% Im nächsten Beispiel werden die unterschiedlichen Notationsformen der
+% Dimensionen illustriert.
+The next example illustrates the different notations of the dimensions.
+
+\begin{multicols}{2}
+\InputLatex[firstline=5,lastline=12]{luakeysdebug/dimension/notations-latex.tex}
+
+\columnbreak
+
+\begin{minted}{lua}
+{
+ ['upper'] = 1864679,
+ ['lower'] = 1864679,
+ ['space'] = 1864679,
+ ['plus'] = 1864679,
+ ['minus'] = -1864679,
+ ['nodim'] = '1 c m', -- string
+}
+\end{minted}
+\end{multicols}
+
+%%
+%
+%%
+
+\subsubsection{string}
+
+% Es gibt zwei Möglichkeiten Zeichenketten anzugeben:
+There are two ways to specify strings:
+%
+% Mit oder ohne doppelte Anführungszeichen.
+With or without double quotes.
+%
+% Wenn der Text Kommas, geschweifte Klammern oder Gleichheitszeichen
+% enthalten soll, müssen doppelte Anführungszeichen verwendet werden.
+If the text have to contain commas, curly braces or equal signs, then
+double quotes must be used.
+
+\InputLua[firstline=4,lastline=17]{data-types/string.lua}
+
+\subsubsection{Naked keys}
+
+% Nackte Schlüssel sind Schlüssel ohne Wert.
+Naked keys are keys without a value.
+%
+% Mit der Option \lua{naked_as_value} können sie als Werte in ein Feld
+% übernommen werden.
+Using the option \lua{naked_as_value} they can be converted into values
+and stored into an array.
+%
+% In Lua ist ein Feld eine Tabelle mit numerischen Indizes (der erste
+% Index ist 1).
+In Lua an array is a table with numeric indexes (The first index is 1).
+
+\InputLatex[firstline=5,lastline=12]{luakeysdebug/naked-keys-latex.tex}
+
+\noindent
+% Alle erkannten Datentypen können als eigenständige Werte verwendet
+% werden.
+All recognized data types can be used as standalone values.
+
+\InputLatex[firstline=14,lastline=19]{luakeysdebug/naked-keys-latex.tex}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\clearpage
+
+\section{Examples}
+
+%%
+%
+%%
+
+\subsection{Extend and modify keys of existing macros}
+
+Extend the includegraphics macro with a new key named \latex{caption}
+and change the accepted values of the \latex{width} key. A number
+between 0 and 1 is allowed and converted into
+\latex{width=0.5\linewidth}
+
+\InputLua{extend-includegraphics/extend-keys.lua}
+\InputLatex{extend-includegraphics/extend-keys-latex.tex}
+
+%%
+%
+%%
+
+\subsection{Process document class options}
+
+% Auf die Optionen einer \LaTeX{} Dokumentenklasse kann über das Macro
+% \latex{\LuakeysGetClassOptions} zu gegriffen werden.
+The options of a \LaTeX{} document class can be accessed via the
+\latex{\LuakeysGetClassOptions} macro.
+%
+% \latex{\LuakeysGetClassOptions} ist ein anderer Name für
+\latex{\LuakeysGetClassOptions} is an alias for
+
+\begin{center}
+\latex{\luaescapestring{\@raw at classoptionslist}}.
+\end{center}
+
+\InputLatex{class-options/test-class.cls}
+\InputLatex{class-options/use-test-class-latex.tex}
+
+%%
+%
+%%
+
+\subsection{Process package options}
+
+\noindent
+% Auf die Optionen eines \LaTeX{}-Pakets kann über das Macro
+% \latex{\LuakeysGetPackageOptions} zu gegriffen werden.
+The options of a \LaTeX{} package can be accessed via the
+\latex{\LuakeysGetPackageOptions} macro.
+% \latex{\LuakeysGetPackageOptions} ist ein anderer Name für
+\latex{\LuakeysGetPackageOptions} is an alias for
+
+\begin{center}
+\latex{\luaescapestring{\@ptionlist{\@currname.\@currext}}}.
+\end{center}
+
+\InputLatex{package-options/test-package.sty}
+\InputLatex{package-options/use-test-package-latex.tex}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\clearpage
+
+\section{Debug packages}
+
+Two small debug packages are included in |luakeys|. One debug package
+can be used in \LaTeX{} (luakeys-debug.sty) and one can be used in plain
+\TeX{} (luakeys-debug.tex). Both packages provide only one command:
+|\luakeysdebug{kv-string}|
+
+\begin{minted}{latex}
+\luakeysdebug{one,two,three}
+\end{minted}
+
+\noindent
+Then the following output should appear in the document:
+\bigskip
+
+\luakeysdebug{one,two,three}
+
+%%
+%
+%%
+
+\subsection{For plain \TeX: luakeys-debug.tex}
+
+An example of how to use the command in plain \TeX:
+
+\begin{minted}{latex}
+\input luakeys-debug.tex
+\luakeysdebug{one,two,three}
+\bye
+\end{minted}
+
+%%
+%
+%%
+
+\subsection{For \LaTeX: luakeys-debug.sty}
+
+An example of how to use the command in \LaTeX:
+
+\begin{minted}{latex}
+\documentclass{article}
+\usepackage{luakeys-debug}
+\begin{document}
+\luakeysdebug[
+ unpack=false,
+ convert dimensions=false
+]{one,two,three}
+\end{document}
+\end{minted}
+
+\section{Activity diagramm of the parsing process}
+
+\begin{center}
+\includegraphics[width=0.8\linewidth]{Activity-Diagramm.eps}
+\end{center}
+
+%-----------------------------------------------------------------------
+%
+%-----------------------------------------------------------------------
+
+\clearpage
+
+\section{Implementation}
+
+%%
+%
+%%
+
+\subsection{luakeys.lua}
+
+\inputminted[linenos=true]{lua}{luakeys.lua}
+
+%%
+%
+%%
+
+\clearpage
+
+\subsection{luakeys.tex}
+
+\inputminted[linenos=true]{latex}{luakeys.tex}
+
+%%
+%
+%%
+
+\clearpage
+
+\subsection{luakeys.sty}
+
+\inputminted[linenos=true]{latex}{luakeys.sty}
+
+%%
+%
+%%
+
+\clearpage
+
+\subsection{luakeys-debug.tex}
+
+\inputminted[linenos=true]{latex}{luakeys-debug.tex}
+
+%%
+%
+%%
+
+\clearpage
+
+\subsection{luakeys-debug.sty}
+
+\inputminted[linenos=true]{latex}{luakeys-debug.sty}
+
+\changes{v0.1.0}{2021/01/18}{Inital release}
+\changes{v0.2.0}{2021/09/19}{
+* Allow all recognized data types as keys.
+* Allow TeX macros in the values.
+* New public Lua functions: save(identifier, result), get(identifier).
+}
+\changes{v0.3.0}{2021/11/05}{
+* Add a LuaLaTeX wrapper “luakeys.sty”.
+* Add a plain LuaTeX wrapper “luakeys.tex”.
+* Rename the previous documentation file “luakeys.tex” to luakeys-doc.tex”.
+}
+\changes{v0.4.0}{2021/12/31}{
+* Parser: Add support for nested tables (for example {{'a', 'b'}}).
+* Parser: Allow only strings and numbers as keys.
+* Parser: Remove support from Lua numbers with exponents (for example '5e+20').
+* Switch the Lua testing framework to busted.
+}
+\changes{v0.5.0}{2022/04/04}{
+* Add possibility to change options globally.
+* New option: standalone_as_true.
+* Add a recursive converter callback / hook to process the parse tree.
+* New option: case_insensitive_keys.
+}
+\changes{v0.6.0}{2022/06/09}{
+* New feature: keys now can be defined using the function
+ “define(defs, opts)” or “define(kv_string, { defs = { key = { ... } } })”
+* Rename the global options table from “default_options” to “opts”.
+* New option “format_keys”.
+* Remove option “case_insensitive_keys”. Use
+ “format_keys = \{ lower \}” to achieve the same effect.
+* The default value of the option “convert_dimension” is now false.
+* The option “standalone_as_true” is renamed to “naked_as_value”.
+ The boolean value of the option must be changed to the opposite to.
+ produce the previous effect.
+* The function “print()” is now called “debug()”.
+}
+\changes{v0.7.0}{2022/07/06}{
+* The project now uses semantic versioning.
+* New definition attribute “pick” to pick standalone values and assign
+ them to a key.
+* New function “utils.scan_oarg()” to search for an optional argument,
+ that means scan for tokens that are enclosed in square brackets.
+* Extend and improve the documentation.
+}
+\changes{v0.8.0}{2022/11/17}{
+* Add 6 new options to change the delimiters: “assignment_operator”,
+ “group_begin”, “group_end”, “list_separator”, “quotation_begin”,
+ “quotation_end”.
+* Extend the documentation about the option “format_keys”.
+}
+\changes{v0.9.0}{2022/11/21}{
+* The definition attibute “pick” accepts a new data type: “any”.
+* The attribute value “true” for the attribute “pick” is deprecated.
+* The attribute “pick” accepts now multiple data types specified in
+ a table.
+* Add a new function called “any(value)” in the “is” table that accepts
+ any data type.
+}
+\changes{v0.10.0}{2022/12/16}{
+* Add support for an invert flat that flips the value of naked keys.
+* Add new options to specify which strings are recognized as Boolean
+ values.
+}
+\changes{v0.11.0}{2022/12/23}{
+* Add a new function called “get_private_instance()” to load a private
+ version of the luakeys module.
+}
+\changes{v0.12.0}{2023/01/05}{
+Added
+* Macros \cmd{\LuakeysGetPackageOptions}, \cmd{\LuakeysGetClassOptions}.
+* Option “accumulated_result”.
+* Data type “list” to the attribute “data_type”.
+* Attribute “description”.
+* Tables “utils.log” and “utils.ansi_color”.
+* Table “errors_message” to set custom messages.
+* Short form syntax for the definition attribute “opposite_keys”.
+Changed
+* Breaking change! luakeys exports now a function instead of a table.
+ Use “require('luakeys')()” or “luakeys.new()” instead of
+ “require('luakeys')”.
+* Breaking change! “luakeys.parse()”, “luakeys.define()”, “luakeys.save()”
+ and “luakeys.get()” can’t be used anymore from the global variable luakeys.
+* New name for the function “new()” instead of “get_private_instance()".
+}
+
+\pagebreak
+\PrintChanges
+\pagebreak
+\PrintIndex
+\end{document}
Property changes on: trunk/Master/texmf-dist/doc/luatex/luakeys/documentation.tex
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Deleted: trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.pdf
===================================================================
(Binary files differ)
Deleted: trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.tex 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys-doc.tex 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,2102 +0,0 @@
-\documentclass{ltxdoc}
-
-\EnableCrossrefs
-\CodelineIndex
-\RecordChanges
-
-\usepackage{mdframed}
-\usepackage{minted}
-\usepackage{luakeys}
-\usepackage{luakeys-debug}
-\usepackage{multicol}
-\usepackage{luacode}
-\usepackage{syntax}
-\usepackage{graphicx}
-
-\usemintedstyle{friendly}
-\BeforeBeginEnvironment{minted}{\begin{mdframed}}
-\AfterEndEnvironment{minted}{\end{mdframed}}
-\setminted{
- breaklines=true,
- fontsize=\footnotesize,
- style=manni,
-}
-\def\lua#1{\mintinline{lua}|#1|}
-\def\latex#1{\mintinline{latex}|#1|}
-
-\NewDocumentCommand { \InputLatex } { O{} m } {
- \begin{mdframed}
- \inputminted[linenos=false,#1]{latex}{examples/#2}
- \end{mdframed}
-}
-
-\NewDocumentCommand { \InputLua } { O{} m } {
- \begin{mdframed}
- \inputminted[linenos=false,#1]{lua}{examples/#2}
- \end{mdframed}
-}
-
-\catcode`_=12
-\def\DefaultOpt#1{%
- \texttt{\directlua{
- tex.print(luakeys.print_default('opts', '#1'))
- }}%
-}
-
-\def\DefaultOptDescription#1{
-\noindent
-The default value of the option “\texttt{#1}” is:
-\DefaultOpt{#1}.
-}
-
-\begin{document}
-
-\providecommand*{\url}{\texttt}
-
-\title{The \textsf{luakeys} package}
-\author{%
- Josef Friedrich\\%
- \url{josef at friedrich.rocks}\\%
- \href{https://github.com/Josef-Friedrich/luakeys}
- {github.com/Josef-Friedrich/luakeys}%
-}
-\date{0.11.0 from 2022/12/23}
-
-\maketitle
-
-\vfill
-
-\InputLua[firstline=4,lastline=7]{first-page.lua}
-
-\noindent
-Result:
-
-\begin{center}
-\begin{minted}{lua}
-{
- ['level1'] = {
- ['level2'] = {
- ['naked'] = true,
- ['dim'] = 1864679,
- ['bool'] = false,
- ['num'] = -0.001,
- ['str'] = 'lua,{}',
- }
- }
-}
-\end{minted}
-\end{center}
-
-\vfill
-
-\strut
-
-\newpage
-
-\tableofcontents
-
-\newpage
-
-% \section{Einführung}
-\section{Introduction}
-
-\noindent
-% |luakeys| ist ein Lua-Modul / Lua\TeX package, das wie die Pakete ...
-% Schlüssel-Wert-Optionen analysieren kann.
-|luakeys| is a Lua module / Lua\TeX package that can parse key-value
-options like the \TeX{} packages
-\href{https://www.ctan.org/pkg/keyval}{keyval},
-\href{https://www.ctan.org/pkg/kvsetkeys}{kvsetkeys},
-\href{https://www.ctan.org/pkg/kvoptions}{kvoptions},
-\href{https://www.ctan.org/pkg/xkeyval}{xkeyval},
-\href{https://www.ctan.org/pkg/pgfkeys}{pgfkeys} etc.
-%
-% |luakeys|, erfüllt diese Aufgabe jedoch, indem es die Sprache Lua
-% verwendet und nicht auf \TeX{} angewiesen ist.
-|luakeys|, however, accomplishes this task by using the Lua language and
-doesn’t rely on \TeX{}.
-%
-% Deshalb kann dieses Paket nur mit der \TeX{}-Engine Lua\TeX{}
-% verwendet werden.
-Therefore this package can only be used with the
-\TeX{} engine Lua\TeX{}.
-%
-% Da |luakeys| \href{http://www.inf.puc-rio.br/~roberto/lpeg/}{LPeg}
-% verwendet, sollte der Parsing-Mechanismus ziemlich robust sein.
-Since |luakeys| uses
-\href{http://www.inf.puc-rio.br/~roberto/lpeg/}{LPeg}, the parsing
-mechanism should be pretty robust.
-
-% Der Artikel TUGboat
-% \href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf}
-% {“Implementing key–value input: An introduction” (Volume 30 (2009), No.
-% 1)} von \emph{Joseph Wright} und \emph{Christian Feuersänger} gibt einen
-% einen guten Überblick über die verfügbaren Key-Value-Pakete.
-The TUGboat article
-\href{http://www.tug.org/tugboat/tb30-1/tb94wright-keyval.pdf}
-{“Implementing key–value input: An introduction” (Volume 30 (2009), No.
-1)} by \emph{Joseph Wright} and \emph{Christian Feuersänger} gives a
-good overview of the available key-value packages.
-
-% Dieses Paket wäre ohne den Artikel
-% \href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf}
-% {"Parsing complex data formats in LuaTEX with LPEG" (Volume 40 (2019),
-% No. 2)} nicht möglich gewesen.
-This package would not be possible without the article
-\href{https://tug.org/TUGboat/tb40-2/tb125menke-lpeg.pdf}
-{“Parsing complex data formats in LuaTEX with LPEG” (Volume 40 (2019),
-No. 2)}.
-
-\subsection{Pros of \texttt{luakeys}}
-
-\begin{itemize}
-% \item Schlüssel-Wert-Paare können unabhängig vom Makro-Paket (latex or
-% context) analysiert werden.
-\item Key-value pairs can be parsed independently of the macro
-collection (\LaTeX{} or Con\TeX{}t).
-
-% \item Sogar in Plain LuaTex können Schlüssel analysiert werden
-\item Even in plain Lua\TeX{} keys can be parsed.
-
-% \item |luakeys| kann mit ineinander verschachtelten listen an
-% Schlüssel-Wert-Paaren umgehen, d. h. es kann mit einer rekursiven
-% Datenstruktur an Schlüssel umgehen.
-\item |luakeys| can handle nested lists of key-value pairs, i.e. it can
-handle a recursive data structure of keys.
-
-% \item Schlüssel müssen nicht, aber können definiert werden.
-\item Keys do not have to be defined, but can they can be defined.
-\end{itemize}
-
-\subsection{Cons of \texttt{luakeys}}
-
-\begin{itemize}
-% \item Das Packet funktioniert nur in der Verbindung mit Lua\TeX.
-\item The package works only in combination with Lua\TeX.
-
-% \item Du musst zwei Sprachen beherrschen: \TeX{} und Lua.
-\item You need to know two languages: \TeX{} and Lua.
-\end{itemize}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-% \section{Wie das Paket geladen wird}
-\section{How the package is loaded}
-
-%%
-%
-%%
-
-\subsection{Using the Lua module \texttt{luakeys.lua}}
-
-% Die Kernfunktionalität dieses Pakets ist in Lua realisiert.
-The core functionality of this package is realized in Lua.
-%
-% Sie können also |luakeys| auch ohne die Wrapper-Dateien
-% \texttt{luakeys.sty} und \texttt{luakeys.tex} verwenden.
-So you can use |luakeys| even without using the wrapper files
-|luakeys.sty| and |luakeys.tex|.
-
-\InputLatex{loading/lua.tex}
-
-%%
-%
-%%
-
-\subsection{Using the Lua\LaTeX{} wrapper \texttt{luakeys.sty}}
-
-% Der Paketmanager MikTeX lädt beispielsweise Pakete erst bei Bedarf
-% herunter.
-For example, the MiK\TeX{} package manager downloads packages only when
-needed.
-%
-% Es wurde berichtet, dass dieser automatische Download nur mit Hilfe
-% der Hüll-Dateien funktioniert.
-It has been reported that this automatic download only works with this
-wrapper files.
-%
-% Wahrscheinlich hält MiK\TeX nach einem Auftreten des LaTeX macros
-% “\latex{\usepackage{luakeys}} ”Ausschau.
-Probably MiK\TeX{} is searching for an occurrence of the \LaTeX{} macro
-“\latex{\usepackage{luakeys}}”.
-%
-% Die mitgelieferte Lua\LaTeX{}-Datei ist recht klein:
-The supplied Lua\LaTeX{} file is quite small:
-
-\begin{minted}{latex}
-\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luakeys}
-\directlua{luakeys = require('luakeys')}
-\end{minted}
-
-\noindent
-% Es lädt das Lua-Modul in die globale Variable \texttt{luakeys}.
-It loads the Lua module into the global variable \texttt{luakeys}.
-
-\InputLatex{loading/tex-latex.tex}
-
-%%
-%
-%%
-
-% \subsection{Verwendung des Plain-Lua\TeX{}-Hüllpakets
-% \texttt{luakeys.tex}}
-\subsection{Using the plain Lua\TeX{} wrapper \texttt{luakeys.tex}}
-
-% Noch kleiner ist die Datei \texttt{luakeys.tex}.
-Even smaller is the file \texttt{luakeys.tex}.
-%
-% Sie besteht aus nur einer Zeile:
-It consists of only one line:
-
-\begin{minted}{latex}
-\directlua{luakeys = require('luakeys')}
-\end{minted}
-
-\noindent
-% Es macht dasselbe wie das Lua\LaTeX{}-Hüllpacket und lädt das
-% Lua-Modul \texttt{luakeys.lua} in die globale Variable
-% \texttt{luakeys}.
-It does the same as the Lua\LaTeX{} wrapper and loads the Lua module
-\texttt{luakeys.lua} into the global variable \texttt{luakeys}.
-
-\InputLatex{loading/tex-plain.tex}
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\section{Lua interface / API}
-
-% Das Lua-Modul exportiert diese Funktionen und Tabellen:
-The Lua module exports this functions and tables:
-
-\InputLua[firstline=3,lastline=15]{export.lua}
-
-\noindent
-% Diese Dokumentation stellt nur die öffentlichen Funktionen und
-% Tabellen vor.
-This documentation presents only the public functions and tables.
-%
-% Um mehr über die privaten, nicht exportierten Funktionen zu erfahren,
-% lesen Sie bitte die
-% \href{https://josef-friedrich.github.io/luakeys/}{Quellcode
-% Dokumentation}, die mit
-% \href{http://stevedonovan.github.io/ldoc/}{LDoc} erstellt wurde.
-To learn more about the private, not exported functions, please
-read the \href{https://josef-friedrich.github.io/luakeys/}{source code
-documentation}, which was created with
-\href{http://stevedonovan.github.io/ldoc/}{LDoc}.
-
-\subsection{Lua indentifier names}
-
-% Das Projekt verwendet einige wenige Abkürzungen für Variablennamen,
-% die hoffentlich für externe Leser eindeutig und bekannt sind.
-The project uses a few abbreviations for variable names that are
-hopefully unambiguous and familiar to external readers.
-
-\begin{center}
-\begin{tabular}{lll}
-Abbreviation & spelled out & Example \\\hline
-\lua{kv_string} & Key-value string & \lua{'key=value'} \\
-\lua{opts} & Options (for the parse function) &
-\lua{ { no_error = false } } \\
-\lua{defs} & Definitions \\
-\lua{def} & Definition \\
-\lua{attr} & Attributes (of a definition) \\
-\end{tabular}
-\end{center}
-
-\noindent
-% Diese nicht abgekürzten Variablennamen werden häufig verwendet.
-These unabbreviated variable names are commonly used.
-\begin{center}
-\begin{tabular}{ll}
-
-\lua{result} &
-% Das Endergebnis aller einzelnen Übersetzungs- und
-% Normalisierungsschritte
-The final result of all individual parsing and normalization steps. \\
-
-\lua{unknown} &
-% Ein Tabelle mit unbekannten, nicht definierten Schlüssel-Wert-Paaren
-A table with unknown, undefinied key-value pairs. \\
-
-\lua{raw} &
-% Das unbearbeitete, rohe Ergebnis der LPeg-Syntaxanalyse.
-The raw result of the Lpeg grammar parser. \\
-\end{tabular}
-\end{center}
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{get_private_instance(): table}”}
-\label{function:get-private-instance}
-
-% Über die Tabelle \lua{opts} können die Standardoptionen global
-% geändert werden.
-The default options can be changed globally via the \lua{opts} table
-(\ref{table-opts}).
-% Um zu verhindern, dass andere Module die Standardeinstellungen
-% ändern, kann mit Hilfe der Funktion \lua{get_private_instance()} eine neue
-% Instanz des Moduls \lua{luakeys} erzeugt werden.
-To prevent another modules from changing the default settings, a new
-instance of the \lua{luakeys} module can be created using the
-\lua{get_private_instance()} function.
-
-\InputLua[firstline=3,lastline=4]{functions/get-private-instance.lua}
-
-\noindent
-% Die Funktion \lua{require()} gibt standardmäßig beim mehrmaligen
-% Aufruf immer die gleiche Tabelle zurück.
-The \lua{require()} function always returns the same table
-when called multiple times.
-
-\InputLua[firstline=14,lastline=17]{functions/get-private-instance.lua}
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{parse(kv_string, opts): result, unknown,
-raw}”}
-\label{parse}
-
-% Die Function parse ist die wichtigste Funktion des Pakets.
-The function \lua{parse(kv_string, opts)} is the most important function
-of the package.
-%
-%
-% Sie konvertiert eine Schlüssel-Wert-Zeichenkette in eine Lua Tabelle.
-It converts a key-value string into a Lua table.
-
-\InputLatex{functions/parse/tex-latex.tex}
-
-\noindent
-In plain \TeX:
-
-\InputLatex{functions/parse/tex-plain.tex}
-
-\subsection{Options to configure the \texttt{parse} function}
-
-\noindent
-% Die Funktion \lua{parse} kann mit einer Optionstabelle aufgerufen
-% werden.
-The \lua{parse} function can be called with an options table.
-% Diese Optionen werden unterstützt:
-This options are supported: \catcode`_=12
-\directlua{luakeys.print_names('opts')}
-
-\InputLua[firstline=5,lastline=94]{opts/all-opts.lua}
-
-\subsection{Table “\texttt{opts}”}
-\label{table-opts}
-
-\noindent
-% Die Optionen können auch global über die exportierte Tabelle
-% \lua{opts} gesetzt werden:
-The options can also be set globally using the exported table
-\lua{opts}:
-
-\InputLua[firstline=4,lastline=4]{opts/exported-default-opts.lua}
-
-\InputLua[firstline=10,lastline=11]{opts/exported-default-opts.lua}
-
-\noindent
-% Damit es zu keinen Wechselwirkungen mit anderen Paketen kommt, die auch
-% |luakeys| verwenden und die Optionen global setzen, ist es anzuraten,
-% die Funktion \lua{get_private_instance()} zum Laden das Paket verwenden.
-To avoid interactions with other packages that also use |luakeys| and
-set the options globally, it is recommended to use the
-\lua{get_private_instance()} function
-(\ref{function:get-private-instance}) to load the package.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{assignment_operator}”}
-\label{option:assignment-operator}
-\label{options-delimiter}
-
-The option \lua{assignment_operator} configures the delimiter that
-assigns a value to a key. The default value of this option is
-\texttt{"="}.
-
-The code example below demonstrates all six delimiter related options.
-
-\InputLua[firstline=4,lastline=13]{opts/delimiters.lua}
-
-\begin{tabular}{ll}
-\textbf{Delimiter options} & \textbf{Section} \\
-assignment_operator & \ref{option:assignment-operator}\\
-group_begin & \ref{option:group-begin}\\
-group_end & \ref{option:group-end}\\
-list_separator & \ref{option:list-separator}\\
-quotation_begin & \ref{option:quotation-begin}\\
-quotation_end & \ref{option:quotation-end}\\
-\end{tabular}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{convert_dimensions}”}
-
-% Wenn Sie die Option \lua{convert_dimensions} auf \lua{true} setzen,
-% erkennt |luakeys| die \TeX{}-Dimensionen und konvertiert sie mit Hilfe
-% der die Funktion \lua{tex.sp(dim)} in scaled points.
-If you set the option \lua{convert_dimensions} to \lua{true}, |luakeys|
-detects the \TeX{} dimensions and converts them into scaled points using
-the function \lua{tex.sp(dim)}.
-
-\InputLua[firstline=4,lastline=7]{opts/convert-dimensions/true.lua}
-
-\noindent
-% Standardmäßig werden die Dimensionen nicht in skalierte Punkte
-% umgewandelt.
-By default the dimensions are not converted into scaled points.
-
-\InputLua[firstline=4,lastline=9]{opts/convert-dimensions/false.lua}
-
-\noindent
-% Wenn Sie eine skalierte Punktzahl in einen Dimensionszeichenketten
-% umwandeln möchten, können Sie das Modul
-If you want to convert a scaled points number into a dimension string
-you can use the module
-\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua}
-{lualibs-util-dim.lua}.
-
-\begin{minted}{lua}
-require('lualibs')
-tex.print(number.todimen(tex.sp('1cm'), 'cm', '%0.0F%s'))
-\end{minted}
-
-\DefaultOptDescription{convert_dimensions}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{debug}”}
-
-% Wenn die Option \lua{debug} auf true gesetzt ist, wird die
-% Ergebnistabelle in der Konsole ausgegeben.
-If the option \lua{debug} is set to ture, the result table is printed to
-the console.
-
-\InputLatex{opts/debug-latex.tex}
-
-\begin{verbatim}
-This is LuaHBTeX, Version 1.15.0 (TeX Live 2022)
-...
-(./debug.aux) (/usr/local/texlive/texmf-dist/tex/latex/base/ts1cmr.fd)
-{
- ['three'] = true,
- ['two'] = true,
- ['one'] = true,
-}
- [1{/usr/
-local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./debug.aux)
-)
-...
-Transcript written on debug.log.
-\end{verbatim}
-
-\DefaultOptDescription{debug}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{default}”}
-\label{option-default}
-
-% Mit der Option \lua{default} kann angegeben werden, welchen Wert
-% nackte Schlüssel (Schlüssel ohne Wert) erhalten. Diese Option hat
-% keinen Einfluss auf Schlüssel mit Werten.
-The option \lua{default} can be used to specify which value naked keys
-(keys without a value) get. This option has no influence on keys with
-values.
-
-\InputLua[firstline=4,lastline=5]{opts/default.lua}
-
-\noindent
-% Standardmäßig erhalten nackte Schlüssel den Wert \lua{true}.
-By default, naked keys get the value \lua{true}.
-
-\InputLua[firstline=11,lastline=12]{opts/default.lua}
-
-\DefaultOptDescription{default}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{defaults}”}
-\label{options-defaults}
-
-% Mit der Attribut „defaults“ kann nicht nur ein einiger Standardwert
-% angegeben werden, sondern eine ganze Tabelle mit Standardwerten.
-The option “defaults” can be used to specify not only one default value,
-but a whole table of default values.
-% Die Ergebnistabelle wird mit der Tabelle bestehend aus Standardwerten
-% vereinigt.
-The result table is merged into the defaults table.
-% Werte aus der Tabelle mit Standardwerten werden von Werten der
-% Ergebnistabelle überschrieben.
-Values in the defaults table are
-overwritten by values in the result table.
-
-\InputLua[firstline=4,lastline=7]{opts/defaults.lua}
-
-\DefaultOptDescription{defaults}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{defs}”}
-
-% Für mehr Information wie Schlüssel definiert werden, lesen sie das
-% kapitel 3.2
-For more informations on how keys are defined, see section \ref{define}.
-% Wenn sie die Option \lua{defs} verwenden, können sie auf den
-% Aufruf der Funktion \lua{define} verzichten.
-If you use the \lua{defs} option, you don't need to call the
-\lua{define} function.
-%
-% Anstatt
-Instead of ...
-
-\InputLua[firstline=4,lastline=5]{opts/defs.lua}
-
-\noindent
-% können wir schreiben ..
-we can write ...
-
-\InputLua[firstline=11,lastline=13]{opts/defs.lua}
-
-\DefaultOptDescription{defs}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{false_aliases}”}
-\label{option:false-aliases}
-
-% Mit den den Optionen \lua{true_aliases} and \lua{false_aliases} können
-% die Zeichenketten festgelegt werden, die vom Parser als Wahrheitswerte
-% erkannt werden.
-The \lua{true_aliases} and \lua{false_aliases} options can be used to
-specify the strings that will be recognized as boolean values by the
-parser.
-% Standardmäßig sind folgende Zeichenketten konfiguriert
-The following strings are configured by default.
-
-\InputLua[firstline=4,lastline=8]{opts/boolean-aliases.lua}
-
-\InputLua[firstline=14,lastline=18]{opts/boolean-aliases.lua}
-
-\InputLua[firstline=24,lastline=28]{opts/boolean-aliases.lua}
-
-% Siehe Abschnitt \label{option:true-aliases} für die entsprechende
-% Option.
-See section \ref{option:true-aliases} for the corresponding option.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{format_keys}”}
-
-% Mit Hilfe der Option \lua{format_keys} können die Schlüssel formatiert
-% werden.
-With the help of the option \lua{format_keys} the keys can be formatted.
-% Die Werte dieser Option müssen in einer Tabelle angegeben werden.
-The values of this option must be specified in a table.
-
-\begin{description}
-\item[lower]
-
-% Um alle Schlüssel in \emph{Kleinbuchstaben} umzuwandeln, geben sie in
-% der Optionentabelle \lua{lower} an.
-To convert all keys to \emph{lowercase}, specify \lua{lower} in the
-options table.
-
-\InputLua[firstline=4,lastline=5]{opts/format-keys.lua}
-
-\item[snake]
-
-% Um alle Schlüssel in \emph{snake case} (Die Wörter sind durch
-% Unterstriche getrennt) umzuwandeln, geben sie in der Optionentabelle
-% \lua{snake} an.
-To make all keys \emph{snake case} (The words are separated by
-underscores), specify \lua{snake} in the options
-table.
-
-\InputLua[firstline=11,lastline=12]{opts/format-keys.lua}
-
-\item[upper]
-
-% Um alle Schlüssel in \emph{Grossbuchstaben} umzuwandeln, geben sie in
-% der Optionentabelle \lua{upper} an.
-To convert all keys to \emph{uppercase}, specify \lua{upper} in the
-options table.
-
-\InputLua[firstline=18,lastline=19]{opts/format-keys.lua}
-\end{description}
-
-% Sie können auch mehrere Formatierungsarten kombinieren.
-You can also combine several types of formatting.
-
-\InputLua[firstline=25,lastline=26]{opts/format-keys.lua}
-
-\DefaultOptDescription{format_keys}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{group_begin}”}
-\label{option:group-begin}
-
-The option \lua{group_begin} configures the delimiter that marks the
-beginning of a group. The default value of this option is \texttt{"\{"}.
-A code example can be found in section \ref{options-delimiter}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{group_end}”}
-\label{option:group-end}
-
-The option \lua{group_end} configures the delimiter that marks the end
-of a group. The default value of this option is \texttt{"\}"}. A code
-example can be found in section \ref{options-delimiter}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{invert_flag}”}
-
-% Wird ein nackter Schlüssel mit einem vorangestellten Ausrufezeichen versehen, so wird sein Standardwert invertiert.
-If a naked key is prefixed with an exclamation mark, its default value
-is inverted.
-% Statt \lua{true} nimmt der Schlüssel jetzt den Wert \lua{falsch} an.
-Instead of \lua{true} the key now takes the value \lua{false}.
-
-\InputLua[firstline=4,lastline=5]{opts/invert-flat.lua}
-
-\noindent
-% Mit der Option \lua{invert_flag} kann dieses Invertierungszeichen
-% geändert werden.
-The \lua{invert_flag} option can be used to change this inversion
-character.
-
-\InputLua[firstline=11,lastline=12]{opts/invert-flat.lua}
-
-\noindent
-% Ist der Standardwert für nackte Schlüssel beispielweise auf \lua{false}
-% gesetzt, so nehmen die mit dem Umkehrungszeichen versehenen nackten
-% Schlüssel den Wert \lua{true} an.
-For example, if the default value for naked keys is set to \lua{false},
-the naked keys prefixed with the invert flat take the value \lua{true}.
-
-\InputLua[firstline=18,lastline=19]{opts/invert-flat.lua}
-
-\noindent
-% Setzen sie die Option \lua{invert_flag} auf \lua{false}, um diese
-% automatische Wertumkehrung zu deaktivieren.
-Set the \lua{invert_flag} option to \lua{false} to disable this
-automatic boolean value inversion.
-
-\InputLua[firstline=25,lastline=26]{opts/invert-flat.lua}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{hooks}”}
-
-% Die folgenden Hooks bzw. Callback-Funktionen ermöglichen es in den
-% Verarbeitungsprozess der \lua{parse}-Function einzugreifen.
-The following hooks or callback functions allow to intervene in the
-processing of the \lua{parse} function.
-%
-% Die Funktionen sind in der Verarbeitungsreihenfolge aufgelistet.
-The functions are listed in processing order.
-%
-% \lua{*_before_opts} bedeutet, dass die Hooks nach der LPeg
-% Syntaxanalyse und vor dem Anwenden der Optionen ausgeführt
-\lua{*_before_opts} means that the hooks are executed after the LPeg
-syntax analysis and before the options are applied.
-%
-% Die Hooks \lua{*_before_defs} werden vor dem Anwenden der
-% Schlüssel-Wert-Definitionen ausgeführt
-The \lua{*_before_defs} hooks are executed before applying the key value
-definitions.
-
-\def\TmpSignature#1{
- {
- \scriptsize\texttt{ = #1}
- }
-}
-
-\def\TmpKeySignature{
- \TmpSignature{function(key, value, depth, current, result): key, value}
-}
-\def\TmpResultSignature{
- \TmpSignature{function(result): void}
-}
-
-\begin{enumerate}
-\item \lua{kv_string} \TmpSignature{function(kv_string): kv_string}
-\item \lua{keys_before_opts} \TmpKeySignature
-\item \lua{result_before_opts} \TmpResultSignature
-\item \lua{keys_before_def} \TmpKeySignature
-\item \lua{result_before_def} \TmpResultSignature
-\item (\lua{process}) (has to be definied using defs, see \ref{attr-process})
-\item \lua{keys} \TmpKeySignature
-\item \lua{result} \TmpResultSignature
-\end{enumerate}
-
-\paragraph{\texttt{kv_string}}
-
-% Der Hook \lua{kv_string} wird als erste
-% der Hook-Funktionen noch vor der LPeg-Syntax-Analyse aufgerufen.
-The \lua{kv_string} hook is called as the first of the hook functions
-before the LPeg syntax parser is executed.
-
-\InputLua[firstline=4,lastline=11]{hooks/kv-string.lua}
-
-\paragraph{\texttt{keys_*}}
-
-% Die Hooks \lua{keys_*} werden rekursiv auf jeden Schlüssel in der
-% aktuellen Ergebnistabelle aufgerufen.
-The hooks \lua{keys_*} are called recursively on each key in the current
-result table.
-% Die Hook-Funktion muss zwei Werte zurückgeben: \lua{key, value}
-The hook function must return two values: \lua{key, value}.
-%
-% Das folgende Beispiel gibt \lua{key} und \lua{value} unverändert
-% zurück, sodass die Ergebnistabelle nicht verändert wird.
-The following example returns \lua{key} and \lua{value} unchanged, so
-the result table is not changed.
-
-\InputLua[firstline=4,lastline=11]{hooks/keys-unchanged.lua}
-
-\noindent
-% Das nächste Beispiel demonstriert den dritten Parameter \lua{depth}
-% der Hook-Funktion.
-The next example demonstrates the third parameter \lua{depth} of the
-hook function.
-
-\InputLua[firstline=4,lastline=16]{hooks/keys-depth.lua}
-
-\paragraph{\texttt{result_*}}
-
-% Die Hooks \lua{result_*} werden einmal mit der aktuellen
-% Ergebnistabelle als Parameter aufgerufen.
-The hooks \lua{result_*} are called once with the current result table
-as a parameter.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{list_separator}”}
-\label{option:list-separator}
-
-The option \lua{list_separator} configures the delimiter that separates
-list items from each other. The default value of this option is
-\texttt{","}. A code example can be found in section
-\ref{options-delimiter}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{naked_as_value}”}
-
-% Mit Hilfe der Option \lua{naked_as_value} werden nackte Schlüssel
-% nicht mit einem Standardwert versehen, sondern als Werte in die
-% Lua-Tabelle abgelegt.
-With the help of the option \lua{naked_as_value}, naked keys are not
-given a default value, but are stored as values in a Lua table.
-
-\InputLua[firstline=4,lastline=5]{opts/naked-as-value.lua}
-
-\noindent
-If we set the option \lua{naked_as_value} to \lua{true}:
-
-\InputLua[firstline=11,lastline=14]{opts/naked-as-value.lua}
-
-\DefaultOptDescription{naked_as_value}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{no_error}”}
-
-% Standardmaßig wirft parse-Funktion einen Fehler, wenn es unbekannte
-% Schlüssel gibt.
-By default the parse function throws an error if there are unknown keys.
-% Mit Hilfe der Option \lua{no_error} kann dies unterbunden werden.
-This can be prevented with the help of the \lua{no_error} option.
-
-\InputLua[firstline=5,lastline=6]{opts/no-error.lua}
-
-\noindent
-If we set the option \lua{no_error} to \lua{true}:
-
-\InputLua[firstline=9,lastline=10]{opts/no-error.lua}
-
-\DefaultOptDescription{no_error}
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{quotation_begin}”}
-\label{option:quotation-begin}
-
-The option \lua{quotation_begin} configures the delimiter that marks the
-beginning of a string. The default value of this option is
-\texttt{'"'} (double quotes). A code example can be found in section
-\ref{options-delimiter}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{quotation_end}”}
-\label{option:quotation-end}
-
-The option \lua{quotation_end} configures the delimiter that marks the
-end of a string. The default value of this option is \texttt{'"'}
-(double quotes). A code example can be found in section
-\ref{options-delimiter}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{true_aliases}”}
-\label{option:true-aliases}
-
-See section \ref{option:false-aliases}.
-
-%%
-%
-%%
-
-\subsubsection{Option “\texttt{unpack}”}
-
-% Mit Hilfe der Option \lua{unpack} werden alle Tabellen, die nur aus
-% einem einzigen nackten Schlüssel bzw. einen einzigen alleinstehenden
-% Wert bestehen, aufgelöst.
-With the help of the option \lua{unpack}, all tables that consist of
-only a single naked key or a single standalone value are unpacked.
-
-\InputLua[firstline=4,lastline=5]{opts/unpack.lua}
-
-\InputLua[firstline=11,lastline=12]{opts/unpack.lua}
-
-\DefaultOptDescription{unpack}
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{define(defs, opts): parse}”}
-\label{define}
-
-The \lua{define} function returns a \lua{parse} function (see
-\ref{parse}).
-The name of a key can be specified in three ways:
-
-\begin{enumerate}
-\item as a string.
-\item as a key in a Lua table. The definition of the corresponding
-key-value pair is then stored under this key.
-\item by the “name” attribute.
-\end{enumerate}
-
-\InputLua[firstline=4,lastline=16]{functions/define.lua}
-
-\noindent
-% Bei verschachtelten Definitionen können nur die letzten beiden
-% Möglichkeiten zur Angabe der Schlüsselnamen verwendet werden.
-For nested definitions, only the last two ways of specifying the key
-names can be used.
-
-\InputLua[firstline=26,lastline=33]{functions/define.lua}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\subsection{Attributes to define a key-value pair}
-
-% Die Definition eines Schlüssel-Wert-Paares kann mit Hilfe von
-% verschiedenen Attributen vorgenommen werden.
-The definition of a key-value pair can be made with the help of various
-attributes.
-%
-% Der Name „Attribut“ für eine Option, einen Schlüssel, eine Eigenschaft
-% (um nur einige Benennungsmöglichkeiten aufzuzählen) zur
-% Schlüssel-Definition, wurde bewusst gewählt, um sie von den Optionen
-% der Funktion \lua{parse} zu unterscheiden.
-The name \emph{“attribute”} for an option, a key, a property ... (to
-list just a few naming possibilities) to define keys, was deliberately
-chosen to distinguish them from the options of the \lua{parse} function.
-%
-% Diese Attribute sind erlaubt.
-These attributes are allowed:
-\directlua{luakeys.print_names('attrs')}.
-%
-% Das folgende Codebeispiel listet alle Attribute auf, die verwendet
-% werden können, um Schlüssel-Wert-Paare zu definieren.
-The code example below lists all the attributes that can be used to
-define key-value pairs.
-
-\InputLua[firstline=5,lastline=46]{defs/all-attrs.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{alias}”}
-
-With the help of the \lua{alias} attribute, other key names can be used.
-The value is always stored under the original key name. A single alias
-name can be specified by a string ...
-
-\InputLua[firstline=4,lastline=7]{defs/attrs/alias.lua}
-
-\noindent
-multiple aliases by a list of strings.
-
-\InputLua[firstline=13,lastline=16]{defs/attrs/alias.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{always_present}”}
-
-% Die Option \lua{default} wird nur bei nackten Schlüsseln verwendet.
-The \lua{default} attribute is used only for naked keys.
-
-\InputLua[firstline=4,lastline=5]{defs/attrs/always-present.lua}
-
-\noindent
-% Wird die Option \lua{always_present} auf wahr gesetzt, wird der
-% Schlüssel immer ins Ergebnis mit übernommen.
-If the attribute \lua{always_present} is set to true, the key is always
-included in the result. If no default value is definied, true is taken
-as the value.
-
-\InputLua[firstline=11,lastline=12]{defs/attrs/always-present.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{choices}”}
-
-% source: Python argparse documentation.
-Some key values should be selected from a restricted set of choices.
-These can be handled by passing an array table containing choices.
-
-\InputLua[firstline=4,lastline=5]{defs/attrs/choices.lua}
-
-\noindent
-When the key-value pair is parsed, values will be checked, and an error
-message will be displayed if the value was not one of the acceptable
-choices:
-
-\InputLua[firstline=13,lastline=15]{defs/attrs/choices.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{data_type}”}
-
-% source: Python argparse documentation.
-The \lua{data_type} attribute allows type-checking and type conversions to
-be performed.
-%
-% Folgende Datentypen werden unterstützt:
-The following data types are supported:
-\lua{'boolean'},
-\lua{'dimension'},
-\lua{'integer'},
-\lua{'number'},
-\lua{'string'}.
-%
-% Bei den drei Datentypen integer, number, dimension kann eine
-% Typenumwandlung scheitern.
-A type conversion can fail with the three data types
-\lua{'dimension'},
-\lua{'integer'},
-\lua{'number'}.
-%
-% Dann wird eine Fehlermeldung ausgegeben.
-Then an error message is displayed.
-
-\InputLua[firstline=4,lastline=8]{defs/attrs/data-type.lua}
-\InputLua[firstline=11,lastline=15]{defs/attrs/data-type.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{default}”}
-
-% Verwenden Sie das Attribut „\lua{default}“, um für jeden nackten Schlüssel
-% einzeln einen Standardwert bereit zu stellen.
-Use the \lua{default} attribute to provide a default value for each naked
-key individually.
-%
-% Mit der globalen \lua{default} Option kann für alle nackten Schlüssel ein
-% Standardwert vorgegeben werden.
-With the global \lua{default} attribute (\ref{option-default}) a default
-value can be specified for all naked keys.
-
-\InputLua[firstline=4,lastline=9]{defs/attrs/default.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{exclusive_group}”}
-
-% Alle Schlüssel, die der gleichen ausschließenden Gruppe angehören,
-% dürfen nicht gemeinsam angegeben werden.
-All keys belonging to the same exclusive group must not be specified
-together.
-%
-% Nur ein Schlüssel aus dieser Gruppe ist erlaubt.
-Only one key from this group is allowed.
-%
-% Als Name für diese ausschließende Gruppe kann irgend ein beliebiger
-% Wert verwendet werden.
-Any value can be used as a name for this exclusive group.
-
-\InputLua[firstline=4,lastline=9]{defs/attrs/exclusive-group.lua}
-
-\noindent
-% Werden mehrer Schlüssel der Gruppe angegeben, so wird eine
-% Fehlermeldung geworfen.
-If more than one key of the group is specified, an error message is
-thrown.
-
-\InputLua[firstline=21,lastline=23]{defs/attrs/exclusive-group.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{opposite_keys}”}
-
-% Die Option \lua{opposite_keys} ermöglicht es, gegensätzliche (nackte)
-% Schlüssel in Wahrheitswerte umzuwandeln und diesen Wahrheitswert unter
-% einem Zielschlüssel zu speichern.
-The \lua{opposite_keys} attribute allows to convert opposite (naked) keys
-into a boolean value and store this boolean under a target key.
-%
-% Lua erlaubt es in Tabellen Wahrheitswerte als Schlüssel zu verwenden.
-% Es müssen jedoch eckige Klammern verwendet werden.
-Lua allows boolean values to be used as keys in tables.
-%
-% Die Wahrheitswerte müssen jedoch in eckige Klammern geschrieben werden.
-However, the boolean values must be written in square brackets, e. g.
-\lua{{ opposite_keys = { [true] = 'show', [false] = 'hide' } }}.
-%
-% Beispiele für gegensätzliche Schlüssel sind:
-Examples of opposing keys are: \lua{show} and \lua{hide}, \lua{dark} and
-\lua{light}, \lua{question} and \lua{solution}.
-%
-% Das untenstehende Beispiel verwendet als gegensätzliches Schlüsselpaar
-% die Schlüssel \lua{show} und \lua{hide}.
-The example below uses the \lua{show} and \lua{hide} keys as the
-opposite key pair.
-%
-% Wird der Schlüssel \lua{show} von der Funktion \lua{parse} gelesen,
-% dann erhält der Zielschlüssel \lua{visibility} den Wert \lua{true}.
-If the key \lua{show} is parsed by the \lua{parse} function, then the
-target key \lua{visibility} receives the value \lua{true}.
-
-\InputLua[firstline=4,lastline=7]{defs/attrs/opposite-keys.lua}
-
-% Wird der Schlüssel \lua{hide} gelesen, dann \lua{falsch}.
-\noindent
-If the key \lua{hide} is parsed, then \lua{false}.
-
-\InputLua[firstline=13,lastline=13]{defs/attrs/opposite-keys.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{macro}”}
-
-The attribute \texttt{macro} stores the value in a \TeX{} macro.
-
-\begin{minted}{lua}
-local parse = luakeys.define({
- key = {
- macro = 'MyMacro'
- }
-})
-parse('key=value')
-\end{minted}
-
-\begin{minted}{latex}
-\MyMacro % expands to “value”
-\end{minted}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{match}”}
-
-% Der Wert des Schlüssel wird zuerst der Lua Funktion
-% \lua{string.match(value, match)} übergeben, bevor er dem Schlüssel
-% zugewiesen wird.
-The value of the key is first passed to the Lua function
-\lua{string.match(value, match)}
-(\url{http://www.lua.org/manual/5.3/manual.html#pdf-string.match})
-before being assigned to the key.
-%
-% Du kannst das Attribut \lua{match} deshalb mit einer Pattern-Matching-
-% Zeichenkette konfigurieren, wie sie in Lua zu Einsatz kommt.
-You can therefore configure the \lua{match} attribute with a pattern
-matching string used in Lua.
-%
-% Werfe einen Blick in das Lua-Handbuch, wie man Patterns schreibt.
-Take a look at the Lua manual on how to write patterns
-(\url{http://www.lua.org/manual/5.3/manual.html#6.4.1}).
-
-\InputLua[firstline=4,lastline=7]{defs/attrs/match/birthday.lua}
-
-\noindent
-% Kann das Pattern im Wert nicht gefunden werden, wird eine
-% Fehlermeldung ausgegeben.
-If the pattern cannot be found in the value, an error message is issued.
-
-\InputLua[firstline=15,lastline=18]{defs/attrs/match/birthday.lua}
-
-\noindent
-% Der Schlüssel erhält das Ergebnis der Funktion \lua{string.match(value,
-% match)}, dass bedeutet, dass der ursprüngliche Wert unter
-% Umständen nicht vollständig in den Schlüssel gespeichert wird.
-The key receives the result of the function \lua{string.match(value,
-match)}, which means that the original value may not be stored
-completely in the key.
-%
-% Im nächsten Beispiel wird der gesamte Eingabewert akzeptiert:
-In the next example, the entire input value is accepted:
-
-\InputLua[firstline=4,lastline=5]{defs/attrs/match/year.lua}
-
-\noindent
-% Das Präfix “waste ” und das Suffix “ rubbisch” der Zeichenketten wird
-% verworfen.
-The prefix “waste ” and the suffix “ rubbisch” of the string are
-discarded.
-
-\InputLua[firstline=11,lastline=11]{defs/attrs/match/year.lua}
-
-\noindent
-% Da Funktion \lua{string.match(value, match)} immer eine Zeichenkette
-% zurückgibt, ist der Wert des Schlüssel auch immer eine Zeichenkette.
-Since function \lua{string.match(value, match)} always returns a string,
-the value of the key is also always a string.
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{name}”}
-
-% Die Option \lua{name} ermöglicht eine alternative Notation von
-% Schlüsselnamen.
-The \lua{name} attribute allows an alternative notation of key names.
-%
-% Anstatt ...
-Instead of ...
-
-\InputLua[firstline=4,lastline=8]{defs/attrs/name/as-key.lua}
-
-\noindent
-% ... können wir schreiben:
-... we can write:
-
-\InputLua[firstline=4,lastline=8]{defs/attrs/name/name-attr.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{pick}”}
-
-% Das Attribut \lua{pick} sucht nach einem Wert, der keinem Schlüssel
-% zugeordnet ist.
-The attribute \lua{pick} searches for a value not assigned to a key.
-% Der zuerst gefundene Wert, d. h. der weiter links stehende Wert, wird
-% einem Schlüssel zugewiesen.
-The first value found, i.e. the one further to the left, is assigned to
-a key.
-
-\InputLua[firstline=4,lastline=6]{defs/attrs/pick/dimension.lua}
-
-\noindent
-% Es wird nur in der aktuellen Ergebnistabelle gesucht und nicht auf
-% anderen Ebenen in der rekursiven Datenstruktur.
-Only the current result table is searched, not other levels in the
-recursive data structure.
-
-\InputLua[firstline=4,lastline=11]{defs/attrs/pick/different-levels.lua}
-
-\noindent
-% Die Suche nach Werte wird aktiviert, wenn das Attribut \lua{pick} auf
-% \lua{true} gesetzt wird.
-The search for values is activated when the attribute \lua{pick} is set
-to a data type.
-% Mit diesen Datentypen kann nach Werten gesucht werden
-These data types can be used to search for values:
-\directlua{
- local types = {}
- for t, fn in pairs(luakeys.is) do
- table.insert(types, t)
- end
- tex.print(table.concat(types, ', '))
-}.
-% Verwendet den Datentyp any um jeden beliebigen Wert zu akzeptieren.
-Use the data type “any” to accept any value.
-% Wird einem Schlüssel bereits bei der Eingabe ein Wert zugewiesen, dann
-% wird nicht weiter nach Werten gesucht.
-If a value is already assigned to a key when it is entered, then no
-further search for values is performed.
-\InputLua[firstline=4,lastline=8]{defs/attrs/pick/value-set.lua}
-
-\noindent
-% Das Attribut \lua{pick} akzeptiert auch mehrere Datentypen, die in
-% einer Tabelle angegeben werden.
-The \lua{pick} attribute also accepts multiple data types
-specified in a table.
-
-\InputLua[firstline=4,lastline=10]{defs/attrs/pick/multiple-data-types.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{process}”}
-\label{attr-process}
-
-% Das Attribut \lua{process} kann dazu verwendet werden, um eine Funktion
-% zu definieren, deren Rückgabewert an den Schlüssel übergeben wird.
-The \lua{process} attribute can be used to define a function whose
-return value is passed to the key.
-%
-% Beim Aufruf der Funktion werden vier Parameter übergeben:
-Four parameters are passed when the function is called:
-
-\begin{enumerate}
-\item \lua{value}:
-% Der zum Schlüssel gehörende aktuelle Wert.
-The current value asssociated with the key.
-
-\item \lua{input}:
-% Die Ergebnis-Tabelle, die vor dem Zeitpunkt geklont wurde, als mit dem
-% Anwenden der Definitionen begonnen wurde.
-The result table cloned before the time the definitions started to be
-applied.
-
-\item \lua{result}: The table in which the final result will be saved.
-
-\item \lua{unknown}: The table in which the unknown key-value pairs
-are stored.
-\end{enumerate}
-
-\noindent
-% Das folgende Beispiel demonstriert den Parameter \lua{value}:
-The following example demonstrates the \lua{value} parameter:
-\InputLua[firstline=4,lastline=14]{defs/attrs/process/parameter-value.lua}
-
-\noindent
-% Das folgende Beispiel demonstriert den Parameter \lua{input}:
-The following example demonstrates the \lua{input} parameter:
-
-\InputLua[firstline=4,lastline=16]{defs/attrs/process/parameter-input.lua}
-
-\noindent
-% Das folgende Beispiel demonstriert den Parameter \lua{result}:
-The following example demonstrates the \lua{result} parameter:
-
-\InputLua[firstline=4,lastline=12]{defs/attrs/process/parameter-result.lua}
-
-\noindent
-% Das folgende Beispiel demonstriert den Parameter \lua{unknown}:
-The following example demonstrates the \lua{unknown} parameter:
-
-\InputLua[firstline=4,lastline=11]{defs/attrs/process/parameter-unknown.lua}
-\InputLua[firstline=15,lastline=15]{defs/attrs/process/parameter-unknown.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{required}”}
-
-% Durch das Attribut \lua{required} kann erzwungen werden, dass ein
-% bestimmter Schlüssel angegeben werden muss.
-The \lua{required} attribute can be used to enforce that a specific key
-must be specified.
-%
-% Im untenstehenden Beispiel wird der Schlüssel \lua{important} als
-% zwingend notwendig definiert.
-In the example below, the key \lua{important} is defined as mandatory.
-
-\InputLua[firstline=4,lastline=5]{defs/attrs/required.lua}
-
-\noindent
-% Fehlt der Schlüssel \lua{important} in der Eingabe, so tritt eine
-% Fehlermeldung auf.
-If the key \lua{important} is missing in the input, an error message
-occurs.
-
-\InputLua[firstline=13,lastline=14]{defs/attrs/required.lua}
-
-\noindent
-A recursive example:
-
-\InputLua[firstline=18,lastline=23]{defs/attrs/required.lua}
-
-\noindent
-% Der Schlüssel \lua{important2} auf der Ebene 2 fehlt.
-The \lua{important2} key on level 2 is missing.
-
-\InputLua[firstline=29,lastline=30]{defs/attrs/required.lua}
-
-\noindent
-% Der Schlüssel \lua{important1} auf der untersten Schlüssel-Ebene fehlt.
-The \lua{important1} key at the lowest key level is missing.
-
-\InputLua[firstline=38,lastline=39]{defs/attrs/required.lua}
-
-%%
-%
-%%
-
-\subsubsection{Attribute “\texttt{sub_keys}”}
-
-% Mit dem Attribut \lua{sub_keys} können ineinander verschachtelte
-% Schlüssel-Wert-Paar-Definitionen aufgebaut werden.
-The \lua{sub_keys} attribute can be used to build nested key-value pair
-definitions.
-
-\InputLua[firstline=4,lastline=16]{defs/attrs/sub-keys.lua}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\subsection{Function “\texttt{render(result): string}”}
-
-The function \lua{render(result)} reverses the function
-\lua{parse(kv_string)}. It takes a Lua table and converts this table
-into a key-value string. The resulting string usually has a different
-order as the input table.
-
-\InputLua[firstline=4,lastline=10]{functions/render.lua}
-
-\noindent
-In Lua only tables with 1-based consecutive integer keys (a.k.a. array
-tables) can be parsed in order.
-
-\InputLua[firstline=16,lastline=17]{functions/render.lua}
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{debug(result): void}”}
-
-The function \lua{debug(result)} pretty prints a Lua table to standard
-output (stdout). It is a utility function that can be used to debug and
-inspect the resulting Lua table of the function \lua{parse}. You have to
-compile your \TeX{} document in a console to see the terminal output.
-
-\InputLua[firstline=4,lastline=5]{functions/debug.lua}
-
-\noindent
-The output should look like this:
-
-\begin{minted}{md}
-{
- ['level1'] = {
- ['level2'] = {
- ['key'] = 'value',
- },
- }
-}
-\end{minted}
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{save(identifier, result): void}”}
-
-The function \lua{save(identifier, result)} saves a result (a
-table from a previous run of \lua{parse}) under an identifier.
-Therefore, it is not necessary to pollute the global namespace to
-store results for the later usage.
-
-%%
-%
-%%
-
-\subsection{Function “\texttt{get(identifier): result}”}
-
-The function \lua{get(identifier)} retrieves a saved result from the
-result store.
-
-%%
-%
-%%
-
-\subsection{Table “\texttt{is}”}
-
-% In der Tabelle \lua{is} werden einige Funktionen zusammengefasst, die
-% überprüft ob eine Eingabe einem bestimmen Datentyp entspricht.
-In the table \lua{is} some functions are summarized, which check whether
-an input corresponds to a certain data type.
-%
-% Alle Funktionen akzeptieren nicht nur die entsprechenden Lua-Datentypen,
-% sondern auch Eingaben als Zeichenketten.
-All functions accept not only the corresponding Lua data types, but also
-input as strings.
-%
-% Beispielsweise wird die Zeichenkette \lua{'true'} von der
-% \lua{is.boolean()}-Funktion als Wahrheitswert erkannt.
-For example, the string \lua{'true'} is recognized by the
-\lua{is.boolean()} function as a boolean value.
-
-\subsubsection{Function “\texttt{is.boolean(value): boolean}”}
-\InputLua[firstline=6,lastline=23]{functions/is/boolean.lua}
-
-\subsubsection{Function “\texttt{is.dimension(value): boolean}”}
-\InputLua[firstline=6,lastline=16]{functions/is/dimension.lua}
-
-\subsubsection{Function “\texttt{is.integer(value): boolean}”}
-\InputLua[firstline=6,lastline=11]{functions/is/integer.lua}
-
-\subsubsection{Function “\texttt{is.number(value): boolean}”}
-\InputLua[firstline=6,lastline=13]{functions/is/number.lua}
-
-\subsubsection{Function “\texttt{is.string(value): boolean}”}
-\InputLua[firstline=6,lastline=12]{functions/is/string.lua}
-
-\subsubsection{Function “\texttt{is.any(value): boolean}”}
-
-% Die Funktion \lua{is.any(value)} gibt immer wahr zurück und
-% akzeptiert deshalb jeden Datentyp.
-The function \lua{is.any(value)} always returns \lua{true} and
-therefore accepts any data type.
-
-%%
-%
-%%
-
-\subsection{Table “\texttt{utils}”}
-
-\subsubsection{Function “\texttt{utils.scan_oarg(initial_delimiter?, end_delimiter?): string}”}
-
-% Plain \TeX{} kennt keine optionalen Argumente (oarg).
-Plain \TeX{} does not know optional arguments (oarg).
-%
-% Die Funktion ermöglicht es nicht nur in \LaTeX{}, sondern auch in
-% Plain \TeX{} nach optionalen Argumenten zu suchen.
-The function \\ \lua{utils.scan_oarg(initial_delimiter?,
-end_delimiter?): string} allows to search for optional arguments not only
-in \LaTeX{} but also in Plain \TeX.
-%
-% Die Funktion basiert auf der Token-Bibliothek.
-The function uses the token library built into Lua\TeX{}.
-%
-% Die beiden Parameter \lua{initial_delimiter} und \lua{end_delimiter}
-% können weggelassen werden.
-The two parameters \lua{initial_delimiter} and \lua{end_delimiter} can
-be omitted.
-%
-% Dann werden eckige Klammern als Begrenzungszeichen angenommen.
-Then square brackets are assumed to be delimiters.
-%
-% Dieser Lua-Code \lua{utils.scan_oarg('(', ')')} sucht beispielsweise
-% nach an einem optionalen Argument in runden Klammern.
-For example, this Lua code \lua{utils.scan_oarg('(', ')')} searches for
-an optional argument in round brackets
-%
-% Die Funktion gibt die Zeichenkette zwischen den Begrenzungszeichen
-% zurück, oder nil wenn Begrenzungszeichen gefunden werden konnten.
-The function returns the string between the delimiters or \lua{nil} if
-no delimiters could be found.
-%
-% Die Begrenzungszeichen sind im Ergebnis nicht enthalten.
-The delimiters themselves are not included in the result.
-%
-% Nach dem \latex{\directlua{}} darf das Makro, indem
-% \lua{utils.scan_oarg} eingesetzt wird, zu keinen Zeichen expandieren.
-After the \latex{\directlua{}}, the macro using \lua{utils.scan_oarg}
-must not expand to any characters.
-
-\InputLatex{utils/scan-oarg-plain.tex}
-
-%%
-%
-%%
-
-\subsection{Table “version”}
-
-% Das luakeys Projekt verwendet semantic versioning
-The luakeys project uses semantic versioning.
-% Die drei Versionenzahlen des Semantic Versioning Schemas werden in
-% einer Tabelle in der Reihenfolge MAJOR, MINOR, PATCH als Ganzzahlen
-% abgelegt.
-The three version numbers of the semantic versioning scheme are stored
-in a table as integers in the order MAJOR, MINOR, PATCH.
-% Mit Hilfe dieser Tabelle kann überprüft werden, ob die richtige
-% Version installiert ist.
-This table can be used to check whether the correct version is
-installed.
-
-\InputLua[firstline=4,lastline=10]{version.lua}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\section{Syntax of the recognized key-value format}
-
-%%
-%
-%%
-
-\subsection{An attempt to put the syntax into words}
-
-A key-value pair is definied by an equal sign (\texttt{key=value}).
-Several key-value pairs or keys without values (naked keys) are lined up
-with commas (\texttt{key=value,naked}) and build a key-value list. Curly
-brackets can be used to create a recursive data structure of nested
-key-value lists (\texttt{level1=\{level2=\{key=value,naked\}\}}).
-
-%%
-%
-%%
-
-\subsection{An (incomplete) attempt to put the syntax into the Extended Backus-Naur Form}
-
-\begin{grammar}
-<list> ::= \{ <list-item> \}
-
-<list-container> ::= `{' <list> `}'
-
-<list-item> ::= ( <list-container> | <key-value-pair> | <value> ) [ `,' ]
-
-<key-value-pair> ::= <value> `=' ( <list-container> | <value> )
-
-<value> ::= <boolean>
- \alt <dimension>
- \alt <number>
- \alt <string-quoted>
- \alt <string-unquoted>
-
-<dimension> ::= <number> <unit>
-
-<number> ::= <sign> ( <integer> [ <fractional> ] | <fractional> )
-
-<fractional> ::= `.' <integer>
-
-<sign> ::= `-' | `+'
-
-<integer> ::= <digit> \{ <digit> \}
-
-<digit> ::= `0' | `1' | `2' | `3' | `4' | `5' | `6' | `7' | `8' | `9'
-
-<unit> ::= `bp' | `BP'
- \alt `cc' | `CC'
- \alt `cm' | `CM'
- \alt `dd' | `DD'
- \alt `em' | `EM'
- \alt `ex' | `EX'
- \alt `in' | `IN'
- \alt `mm' | `MM'
- \alt `mu' | `MU'
- \alt `nc' | `NC'
- \alt `nd' | `ND'
- \alt `pc' | `PC'
- \alt `pt' | `PT'
- \alt `px' | `PX'
- \alt `sp' | `SP'
-
-<boolean> ::= <boolean-true> | <boolean-false>
-
-<boolean-true> ::= `true' | `TRUE' | `True'
-
-<boolean-false> ::= `false' | `FALSE' | `False'
-\end{grammar}
-
-... to be continued
-
-%%
-%
-%%
-
-\subsection{Recognized data types}
-
-\subsubsection{boolean}
-
-The strings \texttt{true}, \texttt{TRUE} and \texttt{True} are converted
-into Lua’s boolean type \lua{true}, the strings \texttt{false},
-\texttt{FALSE} and \texttt{False} into \lua{false}.
-
-\begin{multicols}{2}
-\InputLatex[firstline=5,lastline=12]{luakeysdebug/boolean-latex.tex}
-
-\columnbreak
-
-\begin{minted}{lua}
-{
- ['lower case true'] = true,
- ['upper case true'] = true,
- ['title case true'] = true,
- ['lower case false'] = false,
- ['upper case false'] = false
- ['title case false'] = false,
-}
-\end{minted}
-\end{multicols}
-
-%%
-%
-%%
-
-\subsubsection{number}
-
-\begin{multicols}{2}
-\InputLatex[firstline=5,lastline=13]{luakeysdebug/number-latex.tex}
-
-\columnbreak
-
-\begin{minted}{lua}
-{
- ['num0'] = 42,
- ['num1'] = 42,
- ['num2'] = -42,
- ['num3'] = 4.2,
- ['num4'] = 0.42,
- ['num5'] = 0.42,
- ['num6'] = '0 . 42', -- string
-}
-\end{minted}
-\end{multicols}
-
-%%
-%
-%%
-
-\subsubsection{dimension}
-
-% Luakeys versucht alle Einheiten zu erkennen, die in der TeX-Welt
-% verwendet werden.
-|luakeys| tries to recognize all units used in the \TeX{} world.
-%
-% Nach dem Lua\TeX-Quellcode .
-According to the Lua\TeX{} source code
-(\href{https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625}
-{source/texk/web2c/luatexdir/lua/ltexlib.c})
-%
-% und nach dem Dimensionen-Modul der lulibs-Bibliothek
-and the dimension module of the lualibs library
-(\href{https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua}
-{lualibs-util-dim.lua}),
-%
-% müssten alle Einheiten erkannt werden
-all units should be recognized.
-\begin{multicols}{3}
-\tiny
-\begin{center}
-\begin{tabular}{rl}
-% \textbf{Unit name}
-& \textbf{Description} \\\hline
-bp & big point \\
-cc & cicero \\
-cm & centimeter \\
-dd & didot \\
-em & horizontal measure of \emph{M} \\
-ex & vertical measure of \emph{x} \\
-in & inch \\
-mm & milimeter \\
-mu & math unit \\
-nc & new cicero \\
-nd & new didot \\
-pc & pica \\
-pt & point \\
-px & x height current font \\
-sp & scaledpoint \\
-\end{tabular}
-\end{center}
-
-\columnbreak
-
-\InputLatex[firstline=5,lastline=21]{luakeysdebug/dimension/all-latex.tex}
-
-\columnbreak
-
-\begin{minted}{lua}
-{
- ['bp'] = 65781,
- ['cc'] = 841489,
- ['cm'] = 1864679,
- ['dd'] = 70124,
- ['em'] = 655360,
- ['ex'] = 282460,
- ['in'] = 4736286,
- ['mm'] = 186467,
- ['mu'] = 65536,
- ['nc'] = 839105,
- ['nd'] = 69925,
- ['pc'] = 786432,
- ['pt'] = 65536,
- ['px'] = 65781,
- ['sp'] = 1,
-}
-\end{minted}
-\end{multicols}
-
-\noindent
-% Im nächsten Beispiel werden die unterschiedlichen Notationsformen der
-% Dimensionen illustriert.
-The next example illustrates the different notations of the dimensions.
-
-\begin{multicols}{2}
-\InputLatex[firstline=5,lastline=12]{luakeysdebug/dimension/notations-latex.tex}
-
-\columnbreak
-
-\begin{minted}{lua}
-{
- ['upper'] = 1864679,
- ['lower'] = 1864679,
- ['space'] = 1864679,
- ['plus'] = 1864679,
- ['minus'] = -1864679,
- ['nodim'] = '1 c m', -- string
-}
-\end{minted}
-\end{multicols}
-
-%%
-%
-%%
-
-\subsubsection{string}
-
-% Es gibt zwei Möglichkeiten Zeichenketten anzugeben:
-There are two ways to specify strings:
-%
-% Mit oder ohne doppelte Anführungszeichen.
-With or without double quotes.
-%
-% Wenn der Text Kommas, geschweifte Klammern oder Gleichheitszeichen
-% enthalten soll, müssen doppelte Anführungszeichen verwendet werden.
-If the text have to contain commas, curly braces or equal signs, then
-double quotes must be used.
-
-\InputLua[firstline=4,lastline=17]{data-types/string.lua}
-
-\subsubsection{Naked keys}
-
-% Nackte Schlüssel sind Schlüssel ohne Wert.
-Naked keys are keys without a value.
-%
-% Mit der Option \lua{naked_as_value} können sie als Werte in ein Feld
-% übernommen werden.
-Using the option \lua{naked_as_value} they can be converted into values
-and stored into an array.
-%
-% In Lua ist ein Feld eine Tabelle mit numerischen Indizes (der erste
-% Index ist 1).
-In Lua an array is a table with numeric indexes (The first index is 1).
-
-\InputLatex[firstline=5,lastline=12]{luakeysdebug/naked-keys-latex.tex}
-
-\noindent
-% VAlle erkannten Datentypen können als eigenständige Werte verwendet
-% werden.
-All recognized data types can be used as standalone values.
-
-\InputLatex[firstline=14,lastline=19]{luakeysdebug/naked-keys-latex.tex}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\clearpage
-
-\section{Examples}
-
-%%
-%
-%%
-
-\subsection{Extend and modify keys of existing macros}
-
-Extend the includegraphics macro with a new key named \latex{caption}
-and change the accepted values of the \latex{width} key. A number
-between 0 and 1 is allowed and converted into
-\latex{width=0.5\linewidth}
-
-\InputLua{extend-includegraphics/extend-keys.lua}
-\InputLatex{extend-includegraphics/extend-keys-latex.tex}
-
-%%
-%
-%%
-
-\subsection{Process document class options}
-
-% Auf die Optionen einer \LaTeX{} Dokumentenklasse kann über das Macro
-% \latex{\@classoptionslist} zu gegriffen werden.
-The options of a \LaTeX{} document class can be accessed via the
-\latex{\@classoptionslist} macro.
-%
-% Die Zeichenkette des Makros \latex{\@classoptionslist} ist bereits
-% expandiert und normalisiert.
-The string of the macro \latex{\@classoptionslist} is already expanded
-and normalized.
-%
-% Neben Leerzeichen werden auch die geschweiften Klammern entfernt.
-In addition to spaces, the curly brackets are also removed.
-% Es ist deshalb nicht möglich, in einander geschachtelte hierarische
-% Schlüssel-Wert-Paare über die Option zu verarbeiten.
-It is therefore not possible to process nested hierarchical key-value
-pairs via the option.
-
-\InputLatex{class-options/test-class.cls}
-\InputLatex{class-options/use-test-class-latex.tex}
-
-\begin{minted}{lua}
-{
- [1] = '12pt',
- [2] = 'landscape',
-}
-\end{minted}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\clearpage
-
-\section{Debug packages}
-
-Two small debug packages are included in |luakeys|. One debug package
-can be used in \LaTeX{} (luakeys-debug.sty) and one can be used in plain
-\TeX{} (luakeys-debug.tex). Both packages provide only one command:
-|\luakeysdebug{kv-string}|
-
-\begin{minted}{latex}
-\luakeysdebug{one,two,three}
-\end{minted}
-
-\noindent
-Then the following output should appear in the document:
-\bigskip
-
-\luakeysdebug{one,two,three}
-
-%%
-%
-%%
-
-\subsection{For plain \TeX: luakeys-debug.tex}
-
-An example of how to use the command in plain \TeX:
-
-\begin{minted}{latex}
-\input luakeys-debug.tex
-\luakeysdebug{one,two,three}
-\bye
-\end{minted}
-
-%%
-%
-%%
-
-\subsection{For \LaTeX: luakeys-debug.sty}
-
-An example of how to use the command in \LaTeX:
-
-\begin{minted}{latex}
-\documentclass{article}
-\usepackage{luakeys-debug}
-\begin{document}
-\luakeysdebug[
- unpack=false,
- convert dimensions=false
-]{one,two,three}
-\end{document}
-\end{minted}
-
-\section{Activity diagramm of the parsing process}
-
-\begin{center}
-\includegraphics[width=0.8\linewidth]{Activity-Diagramm.eps}
-\end{center}
-
-%-----------------------------------------------------------------------
-%
-%-----------------------------------------------------------------------
-
-\clearpage
-
-\section{Implementation}
-
-%%
-%
-%%
-
-\subsection{luakeys.lua}
-
-\inputminted[linenos=true]{lua}{luakeys.lua}
-
-%%
-%
-%%
-
-\clearpage
-
-\subsection{luakeys.tex}
-
-\inputminted[linenos=true]{latex}{luakeys.tex}
-
-%%
-%
-%%
-
-\clearpage
-
-\subsection{luakeys.sty}
-
-\inputminted[linenos=true]{latex}{luakeys.sty}
-
-%%
-%
-%%
-
-\clearpage
-
-\subsection{luakeys-debug.tex}
-
-\inputminted[linenos=true]{latex}{luakeys-debug.tex}
-
-%%
-%
-%%
-
-\clearpage
-
-\subsection{luakeys-debug.sty}
-
-\inputminted[linenos=true]{latex}{luakeys-debug.sty}
-
-\changes{0.1.0}{2021/01/18}{Inital release}
-\changes{0.2.0}{2021/09/19}{
-* Allow all recognized data types as keys.
-* Allow TeX macros in the values.
-* New public Lua functions: save(identifier, result), get(identifier).
-}
-\changes{0.3.0}{2021/11/05}{
-* Add a LuaLaTeX wrapper “luakeys.sty”.
-* Add a plain LuaTeX wrapper “luakeys.tex”.
-* Rename the previous documentation file “luakeys.tex” to luakeys-doc.tex”.
-}
-\changes{0.4.0}{2021/12/31}{
-* Parser: Add support for nested tables (for example {{'a', 'b'}}).
-* Parser: Allow only strings and numbers as keys.
-* Parser: Remove support from Lua numbers with exponents (for example '5e+20').
-* Switch the Lua testing framework to busted.
-}
-\changes{0.5.0}{2022/04/04}{
-* Add possibility to change options globally.
-* New option: standalone_as_true.
-* Add a recursive converter callback / hook to process the parse tree.
-* New option: case_insensitive_keys.
-}
-\changes{0.6.0}{2022/06/09}{
-* New feature: keys now can be defined using the function
- “define(defs, opts)” or “define(kv_string, { defs = { key = { ... } } })”
-* Rename the global options table from “default_options” to “opts”.
-* New option “format_keys”.
-* Remove option “case_insensitive_keys”. Use
- “format_keys = \{ lower \}” to achieve the same effect.
-* The default value of the option “convert_dimension” is now false.
-* The option “standalone_as_true” is renamed to “naked_as_value”.
- The boolean value of the option must be changed to the opposite to.
- produce the previous effect.
-* The function “print()” is now called “debug()”.
-}
-\changes{0.7.0}{2022/07/06}{
-* The project now uses semantic versioning.
-* New definition attribute “pick” to pick standalone values and assign
- them to a key.
-* New function “utils.scan_oarg()” to search for an optional argument,
- that means scan for tokens that are enclosed in square brackets.
-* Extend and improve the documentation.
-}
-\changes{0.8.0}{2022/11/17}{
-* Add 6 new options to change the delimiters: “assignment_operator”,
- “group_begin”, “group_end”, “list_separator”, “quotation_begin”,
- “quotation_end”.
-* Extend the documentation about the option “format_keys”.
-}
-\changes{0.9.0}{2022/11/21}{
-* The definition attibute “pick” accepts a new data type: “any”.
-* The attribute value “true” for the attribute “pick” is deprecated.
-* The attribute “pick” accepts now multiple data types specified in
- a table.
-* Add a new function called “any(value)” in the “is” table that accepts
- any data type.
-}
-\changes{0.10.0}{2022/12/16}{
-* Add support for an invert flat that flips the value of naked keys.
-* Add new options to specify which strings are recognized as Boolean
- values.
-}
-\changes{0.11.0}{2022/12/23}{
-* Add a new function called “get_private_instance()” to load a private
- version of the luakeys module.
-}
-
-\pagebreak
-\PrintChanges
-\pagebreak
-\PrintIndex
-\end{document}
Added: trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf
===================================================================
(Binary files differ)
Index: trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf 2023-01-05 21:18:54 UTC (rev 65468)
Property changes on: trunk/Master/texmf-dist/doc/luatex/luakeys/luakeys.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.sty 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,5 +1,5 @@
%% luakeys-debug.sty
-%% Copyright 2021-2022 Josef Friedrich
+%% Copyright 2021-2023 Josef Friedrich
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
@@ -17,6 +17,6 @@
% luakeys-debug.sty and luakeys-debug.tex.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luakeys-debug}[2022/12/23 0.11.0 Debug package for luakeys.]
+\ProvidesPackage{luakeys-debug}[2023/01/05 v0.12.0 Debug package for luakeys.]
\input luakeys-debug.tex
Modified: trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.tex
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.tex 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys-debug.tex 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,5 +1,5 @@
%% luakeys-debug.tex
-%% Copyright 2021-2022 Josef Friedrich
+%% Copyright 2021-2023 Josef Friedrich
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
@@ -18,7 +18,7 @@
\directlua
{
- luakeys = require('luakeys')
+ luakeys = require('luakeys')()
}
\def\luakeysdebug%
Modified: trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.lua 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,35 +1,33 @@
--- luakeys.lua
--- Copyright 2021-2022 Josef Friedrich
---
--- 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 2008/05/04 or later.
---
--- This work has the LPPL maintenance status `maintained'.
---
--- The Current Maintainer of this work is Josef Friedrich.
---
--- This work consists of the files luakeys.lua, luakeys.sty, luakeys.tex
--- luakeys-debug.sty and luakeys-debug.tex.
---- A key-value parser written with Lpeg.
---
--- @module luakeys
+---luakeys.lua
+---Copyright 2021-2023 Josef Friedrich
+---
+---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 2008/05/04 or later.
+---
+---This work has the LPPL maintenance status `maintained'.
+---
+---The Current Maintainer of this work is Josef Friedrich.
+---
+---This work consists of the files luakeys.lua, luakeys.sty, luakeys.tex
+---luakeys-debug.sty and luakeys-debug.tex.
+----A key-value parser written with Lpeg.
+---
+--- at module luakeys
local lpeg = require('lpeg')
if not tex then
+ ---Dummy functions for the tests.
tex = {
- -- Dummy function for the tests.
sp = function(input)
return 1234567
end,
}
-end
-if not token then
token = {
set_macro = function(csname, content, global)
end,
@@ -36,97 +34,120 @@
}
end
---- Merge two tables in the first specified table.
---- The `merge_tables` function copies all keys from the `source` table
---- to a target table. It returns the modified target table.
----
---- at see https://stackoverflow.com/a/1283608/10193818
----
---- at param target table
---- at param source table
----
---- at return table target The modified target table.
-local function merge_tables(target, source)
- for key, value in pairs(source) do
- if type(value) == 'table' then
- if type(target[key] or false) == 'table' then
- merge_tables(target[key] or {}, source[key] or {})
- elseif target[key] == nil then
+local utils = (function()
+ ---
+ ---Merge two tables into the first specified table.
+ ---The `merge_tables` function copies keys from the `source` table
+ ---to the `target` table. It returns the target table.
+ ---
+ ---https://stackoverflow.com/a/1283608/10193818
+ ---
+ --- at param target table # The target table where all values are copied.
+ --- at param source table # The source table from which all values are copied.
+ --- at param overwrite? boolean # Overwrite the values in the target table if they are present (default true).
+ ---
+ --- at return table target The modified target table.
+ local function merge_tables(target, source, overwrite)
+ if overwrite == nil then
+ overwrite = true
+ end
+ for key, value in pairs(source) do
+ if type(value) == 'table' and type(target[key] or false) ==
+ 'table' then
+ merge_tables(target[key] or {}, source[key] or {}, overwrite)
+ elseif (not overwrite and target[key] == nil) or
+ (overwrite and target[key] ~= value) then
target[key] = value
end
- elseif target[key] == nil then
- target[key] = value
end
+ return target
end
- return target
-end
----Clone a table.
----
---- at see http://lua-users.org/wiki/CopyTable
----
---- at param orig table
----
---- at return table
-local function clone_table(orig)
- local orig_type = type(orig)
- local copy
- if orig_type == 'table' then
- copy = {}
- for orig_key, orig_value in next, orig, nil do
- copy[clone_table(orig_key)] = clone_table(orig_value)
+ ---
+ ---Clone a table, i.e. make a deep copy of the source table.
+ ---
+ ---http://lua-users.org/wiki/CopyTable
+ ---
+ --- at param source table # The source table to be cloned.
+ ---
+ --- at return table # A deep copy of the source table.
+ local function clone_table(source)
+ local copy
+ if type(source) == 'table' then
+ copy = {}
+ for orig_key, orig_value in next, source, nil do
+ copy[clone_table(orig_key)] = clone_table(orig_value)
+ end
+ setmetatable(copy, clone_table(getmetatable(source)))
+ else ---number, string, boolean, etc
+ copy = source
end
- setmetatable(copy, clone_table(getmetatable(orig)))
- else -- number, string, boolean, etc
- copy = orig
+ return copy
end
- return copy
-end
-local utils = {
- --- Get the size of an array like table `{ 'one', 'two', 'three' }` = 3.
---
- --- at param value table # A table or any input.
+ ---Remove an element from a table.
---
+ --- at param source table
+ --- at param value any
+ ---
+ --- at return any|nil
+ local function remove_from_table(source, value)
+ for index, v in pairs(source) do
+ if value == v then
+ source[index] = nil
+ return value
+ end
+ end
+ end
+
+ ---
+ --- at param source table
+ ---
+ --- at return table # An array table with the sorted key names.
+ local function get_table_keys(source)
+ local keys = {}
+ for key in pairs(source) do
+ table.insert(keys, key)
+ end
+ table.sort(keys)
+ return keys
+ end
+
+ ---
+ ---Get the size of a table `{ one = 'one', 'two', 'three' }` = 3.
+ ---
+ --- at param value any # A table or any input.
+ ---
--- at return number # The size of the array like table. 0 if the input is no table or the table is empty.
- get_array_size = function(value)
+ local function get_table_size(value)
local count = 0
if type(value) == 'table' then
- for _ in ipairs(value) do
+ for _ in pairs(value) do
count = count + 1
end
end
return count
- end,
+ end
- ---Get the size of a table `{ one = 'one', 'two', 'three' }` = 3.
---
- --- at param value table|any # A table or any input.
+ ---Get the size of an array like table, for example `{ 'one', 'two',
+ ---'three' }` = 3.
---
+ --- at param value any # A table or any input.
+ ---
--- at return number # The size of the array like table. 0 if the input is no table or the table is empty.
- get_table_size = function(value)
+ local function get_array_size(value)
local count = 0
if type(value) == 'table' then
- for _ in pairs(value) do
+ for _ in ipairs(value) do
count = count + 1
end
end
return count
- end,
+ end
- merge_tables = merge_tables,
-
- clone_table = clone_table,
-
- remove_from_array = function(array, element)
- for index, value in pairs(array) do
- if element == value then
- array[index] = nil
- return value
- end
- end
- end,
-
+ ---
---Scan for an optional argument.
---
--- at param initial_delimiter? string # The character that marks the beginning of an optional argument (by default `[`).
@@ -133,7 +154,8 @@
--- at param end_delimiter? string # The character that marks the end of an optional argument (by default `]`).
---
--- at return string|nil # The string that was enclosed by the delimiters. The delimiters themselves are not returned.
- scan_oarg = function(initial_delimiter, end_delimiter)
+ local function scan_oarg(initial_delimiter,
+ end_delimiter)
if initial_delimiter == nil then
initial_delimiter = '['
end
@@ -167,11 +189,603 @@
else
token.put_next(t)
end
- end,
-}
+ end
+ ---
+ ---Throw a single error message.
+ ---
+ --- at param message string
+ --- at param help? table
+ local function throw_error_message(message, help)
+ if type(tex.error) == 'function' then
+ tex.error(message, help)
+ else
+ error(message)
+ end
+ end
+
+ ---
+ ---Throw an error by specifying an error code.
+ ---
+ --- at param error_messages table
+ --- at param error_code string
+ --- at param args? table
+ local function throw_error_code(error_messages,
+ error_code,
+ args)
+ local template = error_messages[error_code]
+
+ ---
+ --- at param message string
+ --- at param a table
+ ---
+ --- at return string
+ local function replace_args(message, a)
+ for key, value in pairs(a) do
+ if type(value) == 'table' then
+ value = table.concat(value, ', ')
+ end
+ message = message:gsub('@' .. key,
+ '“' .. tostring(value) .. '”')
+ end
+ return message
+ end
+
+ ---
+ --- at param list table
+ --- at param a table
+ ---
+ --- at return table
+ local function replace_args_in_list(list, a)
+ for index, message in ipairs(list) do
+ list[index] = replace_args(message, a)
+ end
+ return list
+ end
+
+ ---
+ --- at type string
+ local message
+ --- at type table
+ local help = {}
+
+ if type(template) == 'table' then
+ message = template[1]
+ if args ~= nil then
+ help = replace_args_in_list(template[2], args)
+ else
+ help = template[2]
+ end
+ else
+ message = template
+ end
+
+ if args ~= nil then
+ message = replace_args(message, args)
+ end
+
+ message = 'luakeys error [' .. error_code .. ']: ' .. message
+
+ for _, help_message in ipairs({
+ 'You may be able to find more help in the documentation:',
+ 'http://mirrors.ctan.org/macros/luatex/generic/luakeys/luakeys-doc.pdf',
+ 'Or ask a question in the issue tracker on Github:',
+ 'https://github.com/Josef-Friedrich/luakeys/issues',
+ }) do
+ table.insert(help, help_message)
+ end
+
+ throw_error_message(message, help)
+ end
+
+ local function visit_tree(tree, callback_func)
+ if type(tree) ~= 'table' then
+ throw_error_message(
+ 'Parameter “tree” has to be a table, got: ' ..
+ tostring(tree))
+ end
+ local function visit_tree_recursive(tree,
+ current,
+ result,
+ depth,
+ callback_func)
+ for key, value in pairs(current) do
+ if type(value) == 'table' then
+ value = visit_tree_recursive(tree, value, {}, depth + 1,
+ callback_func)
+ end
+
+ key, value = callback_func(key, value, depth, current, tree)
+
+ if key ~= nil and value ~= nil then
+ result[key] = value
+ end
+ end
+ if next(result) ~= nil then
+ return result
+ end
+ end
+
+ local result =
+ visit_tree_recursive(tree, tree, {}, 1, callback_func)
+
+ if result == nil then
+ return {}
+ end
+ return result
+ end
+
+ --- at alias ColorName 'black'|'red'|'green'|'yellow'|'blue'|'magenta'|'cyan'|'white'|'reset'
+ --- at alias ColorMode 'bright'|'dim'
+
+ ---
+ ---Small library to surround strings with ANSI color codes.
+ --
+ ---[SGR (Select Graphic Rendition) Parameters](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters)
+ ---
+ ---__attributes__
+ ---
+ ---| color |code|
+ ---|------------|----|
+ ---| reset | 0 |
+ ---| clear | 0 |
+ ---| bright | 1 |
+ ---| dim | 2 |
+ ---| underscore | 4 |
+ ---| blink | 5 |
+ ---| reverse | 7 |
+ ---| hidden | 8 |
+ ---
+ ---__foreground__
+ ---
+ ---| color |code|
+ ---|------------|----|
+ ---| black | 30 |
+ ---| red | 31 |
+ ---| green | 32 |
+ ---| yellow | 33 |
+ ---| blue | 34 |
+ ---| magenta | 35 |
+ ---| cyan | 36 |
+ ---| white | 37 |
+ ---
+ ---__background__
+ ---
+ ---| color |code|
+ ---|------------|----|
+ ---| onblack | 40 |
+ ---| onred | 41 |
+ ---| ongreen | 42 |
+ ---| onyellow | 43 |
+ ---| onblue | 44 |
+ ---| onmagenta | 45 |
+ ---| oncyan | 46 |
+ ---| onwhite | 47 |
+ local ansi_color = (function()
+
+ ---
+ --- at param code integer
+ ---
+ --- at return string
+ local function format_color_code(code)
+ return string.char(27) .. '[' .. tostring(code) .. 'm'
+ end
+
+ ---
+ --- at private
+ ---
+ --- at param color ColorName # A color name.
+ --- at param mode? ColorMode
+ --- at param background? boolean # Colorize the background not the text.
+ ---
+ --- at return string
+ local function get_color_code(color, mode, background)
+ local output = ''
+ local code
+
+ if mode == 'bright' then
+ output = format_color_code(1)
+ elseif mode == 'dim' then
+ output = format_color_code(2)
+ end
+
+ if not background then
+ if color == 'reset' then
+ code = 0
+ elseif color == 'black' then
+ code = 30
+ elseif color == 'red' then
+ code = 31
+ elseif color == 'green' then
+ code = 32
+ elseif color == 'yellow' then
+ code = 33
+ elseif color == 'blue' then
+ code = 34
+ elseif color == 'magenta' then
+ code = 35
+ elseif color == 'cyan' then
+ code = 36
+ elseif color == 'white' then
+ code = 37
+ else
+ code = 37
+ end
+ else
+ if color == 'black' then
+ code = 40
+ elseif color == 'red' then
+ code = 41
+ elseif color == 'green' then
+ code = 42
+ elseif color == 'yellow' then
+ code = 43
+ elseif color == 'blue' then
+ code = 44
+ elseif color == 'magenta' then
+ code = 45
+ elseif color == 'cyan' then
+ code = 46
+ elseif color == 'white' then
+ code = 47
+ else
+ code = 40
+ end
+ end
+ return output .. format_color_code(code)
+ end
+
+ ---
+ --- at param text any
+ --- at param color ColorName # A color name.
+ --- at param mode? ColorMode
+ --- at param background? boolean # Colorize the background not the text.
+ ---
+ --- at return string
+ local function colorize(text, color, mode, background)
+ return string.format('%s%s%s',
+ get_color_code(color, mode, background), text,
+ get_color_code('reset'))
+ end
+
+ return {
+ colorize = colorize,
+
+ ---
+ --- at param text any
+ ---
+ --- at return string
+ red = function(text)
+ return colorize(text, 'red')
+ end,
+
+ ---
+ --- at param text any
+ ---
+ --- at return string
+ green = function(text)
+ return colorize(text, 'green')
+ end,
+
+ --- at return string
+ yellow = function(text)
+ return colorize(text, 'yellow')
+ end,
+
+ ---
+ --- at param text any
+ ---
+ --- at return string
+ blue = function(text)
+ return colorize(text, 'blue')
+ end,
+
+ ---
+ --- at param text any
+ ---
+ --- at return string
+ magenta = function(text)
+ return colorize(text, 'magenta')
+ end,
+
+ ---
+ --- at param text any
+ ---
+ --- at return string
+ cyan = function(text)
+ return colorize(text, 'cyan')
+ end,
+ }
+ end)()
+
+ ---
+ ---A small logging library.
+ ---
+ ---Log levels:
+ ---
+ ---* 0: silent
+ ---* 1: error
+ ---* 2: warn
+ ---* 3: info
+ ---* 4: verbose
+ ---* 5: debug
+ ---
+ local log = (function()
+ --- at private
+ local opts = { level = 0 }
+
+ --- at private
+ local function print_message(message, ...)
+ print(string.format(message, ...))
+ end
+
+ ---
+ ---Set the log level.
+ ---
+ --- at param level 0|'silent'|1|'error'|2|'warn'|3|'info'|4|'verbose'|5|'debug'
+ local function set_log_level(level)
+ if type(level) == 'string' then
+ if level == 'silent' then
+ opts.level = 0
+ elseif level == 'error' then
+ opts.level = 1
+ elseif level == 'warn' then
+ opts.level = 2
+ elseif level == 'info' then
+ opts.level = 3
+ elseif level == 'verbose' then
+ opts.level = 4
+ elseif level == 'debug' then
+ opts.level = 5
+ else
+ throw_error_message(string.format('Unknown log level: %s',
+ level))
+ end
+ else
+ if level > 5 or level < 0 then
+ throw_error_message(string.format(
+ 'Log level out of range 0-5: %s', level))
+ end
+ opts.level = level
+ end
+
+ end
+
+ ---
+ ---Log at level 1 (error).
+ ---
+ ---The other log levels are: 0 (silent), 1 (error), 2 (warn), 3 (info), 4 (verbose), 5 (debug).
+ ---
+ --- at param message string
+ --- at param ... any
+ local function error(message, ...)
+ if opts.level >= 1 then
+ print_message(message, ...)
+ end
+ end
+
+ ---
+ ---Log at level 2 (warn).
+ ---
+ ---The other log levels are: 0 (silent), 1 (error), 2 (warn), 3 (info), 4 (verbose), 5 (debug).
+ ---
+ --- at param message string
+ --- at param ... any
+ local function warn(message, ...)
+ if opts.level >= 2 then
+ print_message(message, ...)
+ end
+ end
+
+ ---
+ ---Log at level 3 (info).
+ ---
+ ---The other log levels are: 0 (silent), 1 (error), 2 (warn), 3 (info), 4 (verbose), 5 (debug).
+ ---
+ --- at param message string
+ --- at param ... any
+ local function info(message, ...)
+ if opts.level >= 3 then
+ print_message(message, ...)
+ end
+ end
+
+ ---
+ ---Log at level 4 (verbose).
+ ---
+ ---The other log levels are: 0 (silent), 1 (error), 2 (warn), 3 (info), 4 (verbose), 5 (debug).
+ ---
+ --- at param message string
+ --- at param ... any
+ local function verbose(message, ...)
+ if opts.level >= 4 then
+ print_message(message, ...)
+ end
+ end
+
+ ---
+ ---Log at level 5 (debug).
+ ---
+ ---The other log levels are: 0 (silent), 1 (error), 2 (warn), 3 (info), 4 (verbose), 5 (debug).
+ ---
+ --- at param message string
+ --- at param ... any
+ local function debug(message, ...)
+ if opts.level >= 5 then
+ print_message(message, ...)
+ end
+ end
+
+ return {
+ set_log_level = set_log_level,
+ error = error,
+ warn = warn,
+ info = info,
+ verbose = verbose,
+ debug = debug,
+ }
+ end)()
+
+ return {
+ merge_tables = merge_tables,
+ clone_table = clone_table,
+ remove_from_table = remove_from_table,
+ get_table_keys = get_table_keys,
+ get_table_size = get_table_size,
+ get_array_size = get_array_size,
+ visit_tree = visit_tree,
+ scan_oarg = scan_oarg,
+ throw_error_message = throw_error_message,
+ throw_error_code = throw_error_code,
+ log = log,
+ ansi_color = ansi_color,
+ }
+end)()
+
+---
+---Convert back to strings
+--- at section
+local visualizers = (function()
+
+ ---
+ ---The function `render(tbl)` reverses the function
+ ---`parse(kv_string)`. It takes a Lua table and converts this table
+ ---into a key-value string. The resulting string usually has a
+ ---different order as the input table. In Lua only tables with
+ ---1-based consecutive integer keys (a.k.a. array tables) can be
+ ---parsed in order.
+ ---
+ --- at param result table # A table to be converted into a key-value string.
+ ---
+ --- at return string # A key-value string that can be passed to a TeX macro.
+ local function render(result)
+ local function render_inner(result)
+ local output = {}
+ local function add(text)
+ table.insert(output, text)
+ end
+ for key, value in pairs(result) do
+ if (key and type(key) == 'string') then
+ if (type(value) == 'table') then
+ if (next(value)) then
+ add(key .. '={')
+ add(render_inner(value))
+ add('},')
+ else
+ add(key .. '={},')
+ end
+ else
+ add(key .. '=' .. tostring(value) .. ',')
+ end
+ else
+ add(tostring(value) .. ',')
+ end
+ end
+ return table.concat(output)
+ end
+ return render_inner(result)
+ end
+
+ ---
+ ---The function `stringify(tbl, for_tex)` converts a Lua table into a
+ ---printable string. Stringify a table means to convert the table into
+ ---a string. This function is used to realize the `debug` function.
+ ---`stringify(tbl, true)` (`for_tex = true`) generates a string which
+ ---can be embeded into TeX documents. The macro `\luakeysdebug{}` uses
+ ---this option. `stringify(tbl, false)` or `stringify(tbl)` generate a
+ ---string suitable for the terminal.
+ ---
+ --- at see https://stackoverflow.com/a/54593224/10193818
+ ---
+ --- at param result table # A table to stringify.
+ --- at param for_tex? boolean # Stringify the table into a text string that can be embeded inside a TeX document via tex.print(). Curly braces and whites spaces are escaped.
+ ---
+ --- at return string
+ local function stringify(result, for_tex)
+ local line_break, start_bracket, end_bracket, indent
+
+ if for_tex then
+ line_break = '\\par'
+ start_bracket = '$\\{$'
+ end_bracket = '$\\}$'
+ indent = '\\ \\ '
+ else
+ line_break = '\n'
+ start_bracket = '{'
+ end_bracket = '}'
+ indent = ' '
+ end
+
+ local function stringify_inner(input, depth)
+ local output = {}
+ depth = depth or 0
+
+ local function add(depth, text)
+ table.insert(output, string.rep(indent, depth) .. text)
+ end
+
+ local function format_key(key)
+ if (type(key) == 'number') then
+ return string.format('[%s]', key)
+ else
+ return string.format('[\'%s\']', key)
+ end
+ end
+
+ if type(input) ~= 'table' then
+ return tostring(input)
+ end
+
+ for key, value in pairs(input) do
+ if (key and type(key) == 'number' or type(key) == 'string') then
+ key = format_key(key)
+
+ if (type(value) == 'table') then
+ if (next(value)) then
+ add(depth, key .. ' = ' .. start_bracket)
+ add(0, stringify_inner(value, depth + 1))
+ add(depth, end_bracket .. ',');
+ else
+ add(depth,
+ key .. ' = ' .. start_bracket .. end_bracket .. ',')
+ end
+ else
+ if (type(value) == 'string') then
+ value = string.format('\'%s\'', value)
+ else
+ value = tostring(value)
+ end
+
+ add(depth, key .. ' = ' .. value .. ',')
+ end
+ end
+ end
+
+ return table.concat(output, line_break)
+ end
+
+ return start_bracket .. line_break .. stringify_inner(result, 1) ..
+ line_break .. end_bracket
+ end
+
+ ---
+ ---The function `debug(result)` pretty prints a Lua table to standard
+ ---output (stdout). It is a utility function that can be used to
+ ---debug and inspect the resulting Lua table of the function
+ ---`parse`. You have to compile your TeX document in a console to
+ ---see the terminal output.
+ ---
+ --- at param result table # A table to be printed to standard output for debugging purposes.
+ local function debug(result)
+ print('\n' .. stringify(result, false))
+ end
+
+ return { render = render, stringify = stringify, debug = debug }
+end)()
+
local namespace = {
opts = {
+ accumulated_result = false,
assignment_operator = '=',
convert_dimensions = false,
debug = false,
@@ -209,6 +823,7 @@
choices = true,
data_type = true,
default = true,
+ description = true,
exclusive_group = true,
l3_tl_set = true,
macro = true,
@@ -220,1151 +835,1116 @@
required = true,
sub_keys = true,
},
-}
---- The default options.
-local default_options = clone_table(namespace.opts)
+ error_messages = {
+ E001 = {
+ 'Unknown parse option: @unknown!',
+ { 'The available options are:', '@opt_names' },
+ },
+ E002 = {
+ 'Unknown hook: @unknown!',
+ { 'The available hooks are:', '@hook_names' },
+ },
+ E003 = 'Duplicate aliases @alias1 and @alias2 for key @key!',
+ E004 = 'The value @value does not exist in the choices: @choices',
+ E005 = 'Unknown data type: @unknown',
+ E006 = 'The value @value of the key @key could not be converted into the data type @data_type!',
+ E007 = 'The key @key belongs to the mutually exclusive group @exclusive_group and another key of the group named @another_key is already present!',
+ E008 = 'def.match has to be a string',
+ E009 = 'The value @value of the key @key does not match @match!',
-local function throw_error(message)
- if type(tex.error) == 'function' then
- tex.error(message)
- else
- error(message)
- end
-end
+ E011 = 'Wrong data type in the “pick” attribute: @unknown. Allowed are: @data_types.',
+ E012 = 'Missing required key @key!',
+ E013 = 'The key definition must be a table! Got @data_type for key @key.',
+ E014 = {
+ 'Unknown definition attribute: @unknown',
+ { 'The available attributes are:', '@attr_names' },
+ },
+ E015 = 'Key name couldn’t be detected!',
+ E017 = 'Unknown style to format keys: @unknown! Allowed styles are: @styles',
+ E018 = 'The option “format_keys” has to be a table not @data_type',
+ E019 = 'Unknown keys: @unknown',
---- Normalize the parse options.
+ ---Input / parsing error
+ E021 = 'Opposite key was specified more than once: @key!',
+ E020 = 'Both opposite keys were given: @true and @false!',
+ ---Config error (wrong configuration of luakeys)
+ E010 = 'Usage: opposite_keys = { "true_key", "false_key" } or { [true] = "true_key", [false] = "false_key" } ',
+ E023 = {
+ 'Don’t use this function from the global luakeys table. Create a new instance using e. g.: local lk = luakeys.new()',
+ {
+ 'This functions should not be used from the global luakeys table:',
+ 'parse()',
+ 'save()',
+ 'get()',
+ },
+ },
+ },
+}
+
---
---- at param opts? table # Options in a raw format. The table may be empty or some keys are not set.
----
---- at return table
-local function normalize_opts(opts)
- if type(opts) ~= 'table' then
- opts = {}
- end
- for key, _ in pairs(opts) do
- if namespace.opts[key] == nil then
- throw_error('Unknown parse option: ' .. tostring(key) .. '!')
- end
- end
- local old_opts = opts
- opts = {}
- for name, _ in pairs(namespace.opts) do
- if old_opts[name] ~= nil then
- opts[name] = old_opts[name]
- else
- opts[name] = default_options[name]
- end
- end
+--- at return table # The public interface of the module.
+local function main()
- for hook in pairs(opts.hooks) do
- if namespace.hooks[hook] == nil then
- throw_error('Unknown hook: ' .. tostring(hook) .. '!')
- end
- end
- return opts
-end
+ ---The default options.
+ local default_opts = utils.clone_table(namespace.opts)
-local l3_code_cctab = 10
+ local error_messages = utils.clone_table(namespace.error_messages)
---- Convert back to strings
--- @section
+ ---
+ --- at param error_code string
+ --- at param args? table
+ local function throw_error(error_code, args)
+ utils.throw_error_code(error_messages, error_code, args)
+ end
---- The function `render(tbl)` reverses the function
---- `parse(kv_string)`. It takes a Lua table and converts this table
---- into a key-value string. The resulting string usually has a
---- different order as the input table. In Lua only tables with
---- 1-based consecutive integer keys (a.k.a. array tables) can be
---- parsed in order.
----
---- at param result table # A table to be converted into a key-value string.
----
---- at return string # A key-value string that can be passed to a TeX macro.
-local function render(result)
- local function render_inner(result)
- local output = {}
- local function add(text)
- table.insert(output, text)
+ ---
+ ---Normalize the parse options.
+ ---
+ --- at param opts? table # Options in a raw format. The table may be empty or some keys are not set.
+ ---
+ --- at return table
+ local function normalize_opts(opts)
+ if type(opts) ~= 'table' then
+ opts = {}
end
- for key, value in pairs(result) do
- if (key and type(key) == 'string') then
- if (type(value) == 'table') then
- if (next(value)) then
- add(key .. '={')
- add(render_inner(value))
- add('},')
- else
- add(key .. '={},')
- end
- else
- add(key .. '=' .. tostring(value) .. ',')
- end
+ for key, _ in pairs(opts) do
+ if namespace.opts[key] == nil then
+ throw_error('E001', {
+ unknown = key,
+ opt_names = utils.get_table_keys(namespace.opts),
+ })
+ end
+ end
+ local old_opts = opts
+ opts = {}
+ for name, _ in pairs(namespace.opts) do
+ if old_opts[name] ~= nil then
+ opts[name] = old_opts[name]
else
- add(tostring(value) .. ',')
+ opts[name] = default_opts[name]
end
end
- return table.concat(output)
- end
- return render_inner(result)
-end
---- The function `stringify(tbl, for_tex)` converts a Lua table into a
---- printable string. Stringify a table means to convert the table into
---- a string. This function is used to realize the `debug` function.
---- `stringify(tbl, true)` (`for_tex = true`) generates a string which
---- can be embeded into TeX documents. The macro `\luakeysdebug{}` uses
---- this option. `stringify(tbl, false)` or `stringify(tbl)` generate a
---- string suitable for the terminal.
----
---- at see https://stackoverflow.com/a/54593224/10193818
----
---- at param result table # A table to stringify.
---- at param for_tex? boolean # Stringify the table into a text string that can be embeded inside a TeX document via tex.print(). Curly braces and whites spaces are escaped.
----
---- at return string
-local function stringify(result, for_tex)
- local line_break, start_bracket, end_bracket, indent
-
- if for_tex then
- line_break = '\\par'
- start_bracket = '$\\{$'
- end_bracket = '$\\}$'
- indent = '\\ \\ '
- else
- line_break = '\n'
- start_bracket = '{'
- end_bracket = '}'
- indent = ' '
+ for hook in pairs(opts.hooks) do
+ if namespace.hooks[hook] == nil then
+ throw_error('E002', {
+ unknown = hook,
+ hook_names = utils.get_table_keys(namespace.hooks),
+ })
+ end
+ end
+ return opts
end
- local function stringify_inner(input, depth)
- local output = {}
- depth = depth or 0
+ local l3_code_cctab = 10
- local function add(depth, text)
- table.insert(output, string.rep(indent, depth) .. text)
- end
+ ---
+ ---Parser / Lpeg related
+ --- at section
- local function format_key(key)
- if (type(key) == 'number') then
- return string.format('[%s]', key)
- else
- return string.format('[\'%s\']', key)
- end
+ ---Generate the PEG parser using Lpeg.
+ ---
+ ---Explanations of some LPeg notation forms:
+ ---
+ ---* `patt ^ 0` = `expression *`
+ ---* `patt ^ 1` = `expression +`
+ ---* `patt ^ -1` = `expression ?`
+ ---* `patt1 * patt2` = `expression1 expression2`: Sequence
+ ---* `patt1 + patt2` = `expression1 / expression2`: Ordered choice
+ ---
+ ---* [TUGboat article: Parsing complex data formats in LuaTEX with LPEG](https://tug.or-g/TUGboat/tb40-2/tb125menke-Patterndf)
+ ---
+ --- at param initial_rule string # The name of the first rule of the grammar table passed to the `lpeg.P(attern)` function (e. g. `list`, `number`).
+ --- at param opts? table # Whether the dimensions should be converted to scaled points (by default `false`).
+ ---
+ --- at return userdata # The parser.
+ local function generate_parser(initial_rule, opts)
+ if type(opts) ~= 'table' then
+ opts = normalize_opts(opts)
end
- if type(input) ~= 'table' then
- return tostring(input)
+ local Variable = lpeg.V
+ local Pattern = lpeg.P
+ local Set = lpeg.S
+ local Range = lpeg.R
+ local CaptureGroup = lpeg.Cg
+ local CaptureFolding = lpeg.Cf
+ local CaptureTable = lpeg.Ct
+ local CaptureConstant = lpeg.Cc
+ local CaptureSimple = lpeg.C
+
+ ---Optional whitespace
+ local white_space = Set(' \t\n\r')
+
+ ---Match literal string surrounded by whitespace
+ local ws = function(match)
+ return white_space ^ 0 * Pattern(match) * white_space ^ 0
end
- for key, value in pairs(input) do
- if (key and type(key) == 'number' or type(key) == 'string') then
- key = format_key(key)
-
- if (type(value) == 'table') then
- if (next(value)) then
- add(depth, key .. ' = ' .. start_bracket)
- add(0, stringify_inner(value, depth + 1))
- add(depth, end_bracket .. ',');
- else
- add(depth,
- key .. ' = ' .. start_bracket .. end_bracket .. ',')
- end
+ local line_up_pattern = function(patterns)
+ local result
+ for _, pattern in ipairs(patterns) do
+ if result == nil then
+ result = Pattern(pattern)
else
- if (type(value) == 'string') then
- value = string.format('\'%s\'', value)
- else
- value = tostring(value)
- end
-
- add(depth, key .. ' = ' .. value .. ',')
+ result = result + Pattern(pattern)
end
end
+ return result
end
- return table.concat(output, line_break)
- end
-
- return start_bracket .. line_break .. stringify_inner(result, 1) ..
- line_break .. end_bracket
-end
-
---- The function `debug(result)` pretty prints a Lua table to standard
--- output (stdout). It is a utility function that can be used to
--- debug and inspect the resulting Lua table of the function
--- `parse`. You have to compile your TeX document in a console to
--- see the terminal output.
---
---- at param result table # A table to be printed to standard output for debugging purposes.
-local function debug(result)
- print('\n' .. stringify(result, false))
-end
-
---- Parser / Lpeg related
--- @section
-
---- Generate the PEG parser using Lpeg.
----
---- Explanations of some LPeg notation forms:
----
---- * `patt ^ 0` = `expression *`
---- * `patt ^ 1` = `expression +`
---- * `patt ^ -1` = `expression ?`
---- * `patt1 * patt2` = `expression1 expression2`: Sequence
---- * `patt1 + patt2` = `expression1 / expression2`: Ordered choice
----
---- * [TUGboat article: Parsing complex data formats in LuaTEX with LPEG](https://tug.or-g/TUGboat/tb40-2/tb125menke-Patterndf)
----
---- at param initial_rule string # The name of the first rule of the grammar table passed to the `lpeg.P(attern)` function (e. g. `list`, `number`).
---- at param opts? table # Whether the dimensions should be converted to scaled points (by default `false`).
----
---- at return userdata # The parser.
-local function generate_parser(initial_rule, opts)
- if type(opts) ~= 'table' then
- opts = normalize_opts(opts)
- end
-
- local Variable = lpeg.V
- local Pattern = lpeg.P
- local Set = lpeg.S
- local Range = lpeg.R
- local CaptureGroup = lpeg.Cg
- local CaptureFolding = lpeg.Cf
- local CaptureTable = lpeg.Ct
- local CaptureConstant = lpeg.Cc
- local CaptureSimple = lpeg.C
-
- -- Optional whitespace
- local white_space = Set(' \t\n\r')
-
- --- Match literal string surrounded by whitespace
- local ws = function(match)
- return white_space ^ 0 * Pattern(match) * white_space ^ 0
- end
-
- local line_up_pattern = function(patterns)
- local result
- for _, pattern in ipairs(patterns) do
- if result == nil then
- result = Pattern(pattern)
+ ---
+ ---Convert a dimension to an normalized dimension string or an
+ ---integer in the scaled points format.
+ ---
+ --- at param input string
+ ---
+ --- at return integer|string # A dimension as an integer or a dimension string.
+ local capture_dimension = function(input)
+ ---Remove all whitespaces
+ input = input:gsub('%s+', '')
+ ---Convert the unit string into lowercase.
+ input = input:lower()
+ if opts.convert_dimensions then
+ return tex.sp(input)
else
- result = result + Pattern(pattern)
+ return input
end
end
- return result
- end
- --- Convert a dimension to an normalized dimension string or an
- --- integer in the scaled points format.
- ---
- --- at param input string
- ---
- --- at return integer|string # A dimension as an integer or a dimension string.
- local capture_dimension = function(input)
- -- Remove all whitespaces
- input = input:gsub('%s+', '')
- -- Convert the unit string into lowercase.
- input = input:lower()
- if opts.convert_dimensions then
- return tex.sp(input)
- else
- return input
+ ---
+ ---Add values to a table in two modes:
+ ---
+ ---Key-value pair:
+ ---
+ ---If `arg1` and `arg2` are not nil, then `arg1` is the key and `arg2` is the
+ ---value of a new table entry.
+ ---
+ ---Indexed value:
+ ---
+ ---If `arg2` is nil, then `arg1` is the value and is added as an indexed
+ ---(by an integer) value.
+ ---
+ --- at param result table # The result table to which an additional key-value pair or value should to be added
+ --- at param arg1 any # The key or the value.
+ --- at param arg2? any # Always the value.
+ ---
+ --- at return table # The result table to which an additional key-value pair or value has been added.
+ local add_to_table = function(result, arg1, arg2)
+ if arg2 == nil then
+ local index = #result + 1
+ return rawset(result, index, arg1)
+ else
+ return rawset(result, arg1, arg2)
+ end
end
- end
- --- Add values to a table in two modes:
- --
- -- Key-value pair:
- --
- -- If `arg1` and `arg2` are not nil, then `arg1` is the key and `arg2` is the
- -- value of a new table entry.
- --
- -- Indexed value:
- --
- -- If `arg2` is nil, then `arg1` is the value and is added as an indexed
- -- (by an integer) value.
- --
- --- at param result table # The result table to which an additional key-value pair or value should to be added
- --- at param arg1 any # The key or the value.
- --- at param arg2? any # Always the value.
- ---
- --- at return table # The result table to which an additional key-value pair or value has been added.
- local add_to_table = function(result, arg1, arg2)
- if arg2 == nil then
- local index = #result + 1
- return rawset(result, index, arg1)
- else
- return rawset(result, arg1, arg2)
- end
- end
+ -- LuaFormatter off
+ return Pattern({
+ [1] = initial_rule,
- -- LuaFormatter off
- return Pattern({
- [1] = initial_rule,
+ ---list_item*
+ list = CaptureFolding(
+ CaptureTable('') * Variable('list_item')^0,
+ add_to_table
+ ),
- -- list_item*
- list = CaptureFolding(
- CaptureTable('') * Variable('list_item')^0,
- add_to_table
- ),
+ ---'{' list '}'
+ list_container =
+ ws(opts.group_begin) * Variable('list') * ws(opts.group_end),
- -- '{' list '}'
- list_container =
- ws(opts.group_begin) * Variable('list') * ws(opts.group_end),
+ ---( list_container / key_value_pair / value ) ','?
+ list_item =
+ CaptureGroup(
+ Variable('list_container') +
+ Variable('key_value_pair') +
+ Variable('value')
+ ) * ws(opts.list_separator)^-1,
- -- ( list_container / key_value_pair / value ) ','?
- list_item =
- CaptureGroup(
- Variable('list_container') +
- Variable('key_value_pair') +
- Variable('value')
- ) * ws(opts.list_separator)^-1,
+ ---key '=' (list_container / value)
+ key_value_pair =
+ (Variable('key') * ws(opts.assignment_operator)) * (Variable('list_container') + Variable('value')),
- -- key '=' (list_container / value)
- key_value_pair =
- (Variable('key') * ws(opts.assignment_operator)) * (Variable('list_container') + Variable('value')),
+ ---number / string_quoted / string_unquoted
+ key =
+ Variable('number') +
+ Variable('string_quoted') +
+ Variable('string_unquoted'),
- -- number / string_quoted / string_unquoted
- key =
- Variable('number') +
- Variable('string_quoted') +
- Variable('string_unquoted'),
+ ---boolean !value / dimension !value / number !value / string_quoted !value / string_unquoted
+ ---!value -> Not-predicate -> * -Variable('value')
+ value =
+ Variable('boolean') * -Variable('value') +
+ Variable('dimension') * -Variable('value') +
+ Variable('number') * -Variable('value') +
+ Variable('string_quoted') * -Variable('value') +
+ Variable('string_unquoted'),
- -- boolean !value / dimension !value / number !value / string_quoted !value / string_unquoted
- -- !value -> Not-predicate -> * -Variable('value')
- value =
- Variable('boolean') * -Variable('value') +
- Variable('dimension') * -Variable('value') +
- Variable('number') * -Variable('value') +
- Variable('string_quoted') * -Variable('value') +
- Variable('string_unquoted'),
+ ---for is.boolean()
+ boolean_only = Variable('boolean') * -1,
- -- for is.boolean()
- boolean_only = Variable('boolean') * -1,
+ ---boolean_true / boolean_false
+ boolean =
+ (
+ Variable('boolean_true') * CaptureConstant(true) +
+ Variable('boolean_false') * CaptureConstant(false)
+ ),
- -- boolean_true / boolean_false
- boolean =
- (
- Variable('boolean_true') * CaptureConstant(true) +
- Variable('boolean_false') * CaptureConstant(false)
- ),
+ boolean_true = line_up_pattern(opts.true_aliases),
- boolean_true = line_up_pattern(opts.true_aliases),
+ boolean_false = line_up_pattern(opts.false_aliases),
- boolean_false = line_up_pattern(opts.false_aliases),
+ ---for is.dimension()
+ dimension_only = Variable('dimension') * -1,
- -- for is.dimension()
- dimension_only = Variable('dimension') * -1,
+ dimension = (
+ Variable('tex_number') * white_space^0 *
+ Variable('unit')
+ ) / capture_dimension,
- dimension = (
- Variable('tex_number') * white_space^0 *
- Variable('unit')
- ) / capture_dimension,
+ ---for is.number()
+ number_only = Variable('number') * -1,
- -- for is.number()
- number_only = Variable('number') * -1,
+ ---capture number
+ number = Variable('tex_number') / tonumber,
- -- capture number
- number = Variable('tex_number') / tonumber,
+ ---sign? white_space? (integer+ fractional? / fractional)
+ tex_number =
+ Variable('sign')^0 * white_space^0 *
+ (Variable('integer')^1 * Variable('fractional')^0) +
+ Variable('fractional'),
- -- sign? white_space? (integer+ fractional? / fractional)
- tex_number =
- Variable('sign')^0 * white_space^0 *
- (Variable('integer')^1 * Variable('fractional')^0) +
- Variable('fractional'),
+ sign = Set('-+'),
- sign = Set('-+'),
+ fractional = Pattern('.') * Variable('integer')^1,
- fractional = Pattern('.') * Variable('integer')^1,
+ integer = Range('09')^1,
- integer = Range('09')^1,
+ ---'bp' / 'BP' / 'cc' / etc.
+ ---https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua
+ ---https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625
+ unit =
+ Pattern('bp') + Pattern('BP') +
+ Pattern('cc') + Pattern('CC') +
+ Pattern('cm') + Pattern('CM') +
+ Pattern('dd') + Pattern('DD') +
+ Pattern('em') + Pattern('EM') +
+ Pattern('ex') + Pattern('EX') +
+ Pattern('in') + Pattern('IN') +
+ Pattern('mm') + Pattern('MM') +
+ Pattern('mu') + Pattern('MU') +
+ Pattern('nc') + Pattern('NC') +
+ Pattern('nd') + Pattern('ND') +
+ Pattern('pc') + Pattern('PC') +
+ Pattern('pt') + Pattern('PT') +
+ Pattern('px') + Pattern('PX') +
+ Pattern('sp') + Pattern('SP'),
- -- 'bp' / 'BP' / 'cc' / etc.
- -- https://raw.githubusercontent.com/latex3/lualibs/master/lualibs-util-dim.lua
- -- https://github.com/TeX-Live/luatex/blob/51db1985f5500dafd2393aa2e403fefa57d3cb76/source/texk/web2c/luatexdir/lua/ltexlib.c#L434-L625
- unit =
- Pattern('bp') + Pattern('BP') +
- Pattern('cc') + Pattern('CC') +
- Pattern('cm') + Pattern('CM') +
- Pattern('dd') + Pattern('DD') +
- Pattern('em') + Pattern('EM') +
- Pattern('ex') + Pattern('EX') +
- Pattern('in') + Pattern('IN') +
- Pattern('mm') + Pattern('MM') +
- Pattern('mu') + Pattern('MU') +
- Pattern('nc') + Pattern('NC') +
- Pattern('nd') + Pattern('ND') +
- Pattern('pc') + Pattern('PC') +
- Pattern('pt') + Pattern('PT') +
- Pattern('px') + Pattern('PX') +
- Pattern('sp') + Pattern('SP'),
+ ---'"' ('\"' / !'"')* '"'
+ string_quoted =
+ white_space^0 * Pattern(opts.quotation_begin) *
+ CaptureSimple((Pattern('\\' .. opts.quotation_end) + 1 - Pattern(opts.quotation_end))^0) *
+ Pattern(opts.quotation_end) * white_space^0,
- -- '"' ('\"' / !'"')* '"'
- string_quoted =
- white_space^0 * Pattern(opts.quotation_begin) *
- CaptureSimple((Pattern('\\' .. opts.quotation_end) + 1 - Pattern(opts.quotation_end))^0) *
- Pattern(opts.quotation_end) * white_space^0,
+ string_unquoted =
+ white_space^0 *
+ CaptureSimple(
+ Variable('word_unquoted')^1 *
+ (Set(' \t')^1 * Variable('word_unquoted')^1)^0) *
+ white_space^0,
- string_unquoted =
- white_space^0 *
- CaptureSimple(
- Variable('word_unquoted')^1 *
- (Set(' \t')^1 * Variable('word_unquoted')^1)^0) *
- white_space^0,
-
- word_unquoted = (1 - white_space - Set(
- opts.group_begin ..
- opts.group_end ..
- opts.assignment_operator ..
- opts.list_separator))^1
- })
+ word_unquoted = (1 - white_space - Set(
+ opts.group_begin ..
+ opts.group_end ..
+ opts.assignment_operator ..
+ opts.list_separator))^1
+ })
-- LuaFormatter on
-end
+ end
-local function visit_tree(tree, callback_func)
- if type(tree) ~= 'table' then
- throw_error('Parameter “tree” has to be a table, got: ' ..
- tostring(tree))
- end
- local function visit_tree_recursive(tree,
- current,
- result,
- depth,
- callback_func)
- for key, value in pairs(current) do
- if type(value) == 'table' then
- value = visit_tree_recursive(tree, value, {}, depth + 1,
- callback_func)
+ local is = {
+ boolean = function(value)
+ if value == nil then
+ return false
end
+ if type(value) == 'boolean' then
+ return true
+ end
+ local parser = generate_parser('boolean_only')
+ local result = parser:match(tostring(value))
+ return result ~= nil
+ end,
- key, value = callback_func(key, value, depth, current, tree)
+ dimension = function(value)
+ if value == nil then
+ return false
+ end
+ local parser = generate_parser('dimension_only')
+ local result = parser:match(tostring(value))
+ return result ~= nil
+ end,
- if key ~= nil and value ~= nil then
- result[key] = value
+ integer = function(value)
+ local n = tonumber(value)
+ if n == nil then
+ return false
end
- end
- if next(result) ~= nil then
- return result
- end
- end
+ return n == math.floor(n)
+ end,
- local result = visit_tree_recursive(tree, tree, {}, 1, callback_func)
+ number = function(value)
+ if value == nil then
+ return false
+ end
+ if type(value) == 'number' then
+ return true
+ end
+ local parser = generate_parser('number_only')
+ local result = parser:match(tostring(value))
+ return result ~= nil
+ end,
- if result == nil then
- return {}
- end
- return result
-end
+ string = function(value)
+ return type(value) == 'string'
+ end,
-local is = {
- boolean = function(value)
- if value == nil then
- return false
- end
- if type(value) == 'boolean' then
+ list = function(value)
+ if type(value) ~= 'table' then
+ return false
+ end
+
+ for k, _ in pairs(value) do
+ if type(k) ~= 'number' then
+ return false
+ end
+ end
return true
- end
- local parser = generate_parser('boolean_only')
- local result = parser:match(tostring(value))
- return result ~= nil
- end,
+ end,
- dimension = function(value)
- if value == nil then
- return false
- end
- local parser = generate_parser('dimension_only')
- local result = parser:match(tostring(value))
- return result ~= nil
- end,
-
- integer = function(value)
- local n = tonumber(value)
- if n == nil then
- return false
- end
- return n == math.floor(n)
- end,
-
- number = function(value)
- if value == nil then
- return false
- end
- if type(value) == 'number' then
+ any = function(value)
return true
- end
- local parser = generate_parser('number_only')
- local result = parser:match(tostring(value))
- return result ~= nil
- end,
+ end,
+ }
- string = function(value)
- return type(value) == 'string'
- end,
+ ---
+ ---Apply the key-value-pair definitions (defs) on an input table in a
+ ---recursive fashion.
+ ---
+ --- at param defs table # A table containing all definitions.
+ --- at param opts table # The parse options table.
+ --- at param input table # The current input table.
+ --- at param output table # The current output table.
+ --- at param unknown table # Always the root unknown table.
+ --- at param key_path table # An array of key names leading to the current
+ --- at param input_root table # The root input table input and output table.
+ local function apply_definitions(defs,
+ opts,
+ input,
+ output,
+ unknown,
+ key_path,
+ input_root)
+ local exclusive_groups = {}
- any = function(value)
- return true
- end,
-}
+ local function add_to_key_path(key_path, key)
+ local new_key_path = {}
---- Apply the key-value-pair definitions (defs) on an input table in a
---- recursive fashion.
----
---- at param defs table # A table containing all definitions.
---- at param opts table # The parse options table.
---- at param input table # The current input table.
---- at param output table # The current output table.
---- at param unknown table # Always the root unknown table.
---- at param key_path table # An array of key names leading to the current
---- at param input_root table # The root input table input and output table.
-local function apply_definitions(defs,
- opts,
- input,
- output,
- unknown,
- key_path,
- input_root)
- local exclusive_groups = {}
+ for index, value in ipairs(key_path) do
+ new_key_path[index] = value
+ end
- local function add_to_key_path(key_path, key)
- local new_key_path = {}
-
- for index, value in ipairs(key_path) do
- new_key_path[index] = value
+ table.insert(new_key_path, key)
+ return new_key_path
end
- table.insert(new_key_path, key)
- return new_key_path
- end
-
- local function get_default_value(def)
- if def.default ~= nil then
- return def.default
- elseif opts ~= nil and opts.default ~= nil then
- return opts.default
+ local function get_default_value(def)
+ if def.default ~= nil then
+ return def.default
+ elseif opts ~= nil and opts.default ~= nil then
+ return opts.default
+ end
+ return true
end
- return true
- end
- local function find_value(search_key, def)
- if input[search_key] ~= nil then
- local value = input[search_key]
- input[search_key] = nil
- return value
- -- naked keys: values with integer keys
- elseif utils.remove_from_array(input, search_key) ~= nil then
- return get_default_value(def)
+ local function find_value(search_key, def)
+ if input[search_key] ~= nil then
+ local value = input[search_key]
+ input[search_key] = nil
+ return value
+ ---naked keys: values with integer keys
+ elseif utils.remove_from_table(input, search_key) ~= nil then
+ return get_default_value(def)
+ end
end
- end
- local apply = {
- alias = function(value, key, def)
- if type(def.alias) == 'string' then
- def.alias = { def.alias }
- end
- local alias_value
- local used_alias_key
- -- To get an error if the key and an alias is present
- if value ~= nil then
- alias_value = value
- used_alias_key = key
- end
- for _, alias in ipairs(def.alias) do
- local v = find_value(alias, def)
- if v ~= nil then
- if alias_value ~= nil then
- throw_error(string.format(
- 'Duplicate aliases “%s” and “%s” for key “%s”!',
- used_alias_key, alias, key))
+ local apply = {
+ alias = function(value, key, def)
+ if type(def.alias) == 'string' then
+ def.alias = { def.alias }
+ end
+ local alias_value
+ local used_alias_key
+ ---To get an error if the key and an alias is present
+ if value ~= nil then
+ alias_value = value
+ used_alias_key = key
+ end
+ for _, alias in ipairs(def.alias) do
+ local v = find_value(alias, def)
+ if v ~= nil then
+ if alias_value ~= nil then
+ throw_error('E003', {
+ alias1 = used_alias_key,
+ alias2 = alias,
+ key = key,
+ })
+ end
+ used_alias_key = alias
+ alias_value = v
end
- used_alias_key = alias
- alias_value = v
end
- end
- if alias_value ~= nil then
- return alias_value
- end
- end,
+ if alias_value ~= nil then
+ return alias_value
+ end
+ end,
- always_present = function(value, key, def)
- if value == nil and def.always_present then
- return get_default_value(def)
- end
- end,
+ always_present = function(value, key, def)
+ if value == nil and def.always_present then
+ return get_default_value(def)
+ end
+ end,
- choices = function(value, key, def)
- if value == nil then
- return
- end
- if def.choices ~= nil and type(def.choices) == 'table' then
- local is_in_choices = false
- for _, choice in ipairs(def.choices) do
- if value == choice then
- is_in_choices = true
+ choices = function(value, key, def)
+ if value == nil then
+ return
+ end
+ if def.choices ~= nil and type(def.choices) == 'table' then
+ local is_in_choices = false
+ for _, choice in ipairs(def.choices) do
+ if value == choice then
+ is_in_choices = true
+ end
end
+ if not is_in_choices then
+ throw_error('E004', { value = value, choices = def.choices })
+ end
end
- if not is_in_choices then
- throw_error('The value “' .. value ..
- '” does not exist in the choices: ' ..
- table.concat(def.choices, ', ') .. '!')
+ end,
+
+ data_type = function(value, key, def)
+ if value == nil then
+ return
end
- end
- end,
-
- data_type = function(value, key, def)
- if value == nil then
- return
- end
- if def.data_type ~= nil then
- local converted
- -- boolean
- if def.data_type == 'boolean' then
- if value == 0 or value == '' or not value then
- converted = false
+ if def.data_type ~= nil then
+ local converted
+ ---boolean
+ if def.data_type == 'boolean' then
+ if value == 0 or value == '' or not value then
+ converted = false
+ else
+ converted = true
+ end
+ ---dimension
+ elseif def.data_type == 'dimension' then
+ if is.dimension(value) then
+ converted = value
+ end
+ ---integer
+ elseif def.data_type == 'integer' then
+ if is.number(value) then
+ local n = tonumber(value)
+ if type(n) == 'number' and n ~= nil then
+ converted = math.floor(n)
+ end
+ end
+ ---number
+ elseif def.data_type == 'number' then
+ if is.number(value) then
+ converted = tonumber(value)
+ end
+ ---string
+ elseif def.data_type == 'string' then
+ converted = tostring(value)
+ ---list
+ elseif def.data_type == 'list' then
+ if is.list(value) then
+ converted = value
+ end
else
- converted = true
+ throw_error('E005', { data_type = def.data_type })
end
- -- dimension
- elseif def.data_type == 'dimension' then
- if is.dimension(value) then
- converted = value
+ if converted == nil then
+ throw_error('E006', {
+ value = value,
+ key = key,
+ data_type = def.data_type,
+ })
+ else
+ return converted
end
- -- integer
- elseif def.data_type == 'integer' then
- if is.number(value) then
- local n = tonumber(value)
- if type(n) == 'number' and n ~= nil then
- converted = math.floor(n)
- end
+ end
+ end,
+
+ exclusive_group = function(value, key, def)
+ if value == nil then
+ return
+ end
+ if def.exclusive_group ~= nil then
+ if exclusive_groups[def.exclusive_group] ~= nil then
+ throw_error('E007', {
+ key = key,
+ exclusive_group = def.exclusive_group,
+ another_key = exclusive_groups[def.exclusive_group],
+ })
+ else
+ exclusive_groups[def.exclusive_group] = key
end
- -- number
- elseif def.data_type == 'number' then
- if is.number(value) then
- converted = tonumber(value)
- end
- -- string
- elseif def.data_type == 'string' then
- converted = tostring(value)
- else
- throw_error('Unknown data type: ' .. def.data_type)
end
- if converted == nil then
- throw_error(
- 'The value “' .. value .. '” of the key “' .. key ..
- '” could not be converted into the data type “' ..
- def.data_type .. '”!')
- else
- return converted
- end
- end
- end,
+ end,
- exclusive_group = function(value, key, def)
- if value == nil then
- return
- end
- if def.exclusive_group ~= nil then
- if exclusive_groups[def.exclusive_group] ~= nil then
- throw_error('The key “' .. key ..
- '” belongs to a mutually exclusive group “' ..
- def.exclusive_group .. '” and the key “' ..
- exclusive_groups[def.exclusive_group] ..
- '” is already present!')
- else
- exclusive_groups[def.exclusive_group] = key
+ l3_tl_set = function(value, key, def)
+ if value == nil then
+ return
end
- end
- end,
+ if def.l3_tl_set ~= nil then
+ tex.print(l3_code_cctab,
+ '\\tl_set:Nn \\g_' .. def.l3_tl_set .. '_tl')
+ tex.print('{' .. value .. '}')
+ end
+ end,
- l3_tl_set = function(value, key, def)
- if value == nil then
- return
- end
- if def.l3_tl_set ~= nil then
- tex.print(l3_code_cctab,
- '\\tl_set:Nn \\g_' .. def.l3_tl_set .. '_tl')
- tex.print('{' .. value .. '}')
- end
- end,
-
- macro = function(value, key, def)
- if value == nil then
- return
- end
- if def.macro ~= nil then
- token.set_macro(def.macro, value, 'global')
- end
- end,
-
- match = function(value, key, def)
- if value == nil then
- return
- end
- if def.match ~= nil then
- if type(def.match) ~= 'string' then
- throw_error('def.match has to be a string')
+ macro = function(value, key, def)
+ if value == nil then
+ return
end
- local match = string.match(value, def.match)
- if match == nil then
- throw_error(
- 'The value “' .. value .. '” of the key “' .. key ..
- '” does not match “' .. def.match .. '”!')
- else
- return match
+ if def.macro ~= nil then
+ token.set_macro(def.macro, value, 'global')
end
- end
- end,
+ end,
- opposite_keys = function(value, key, def)
- if def.opposite_keys ~= nil then
- local true_value = def.opposite_keys[true]
- local false_value = def.opposite_keys[false]
- if true_value == nil or false_value == nil then
- throw_error(
- 'Usage opposite_keys = { [true] = "...", [false] = "..." }')
+ match = function(value, key, def)
+ if value == nil then
+ return
end
- if utils.remove_from_array(input, true_value) ~= nil then
- return true
- elseif utils.remove_from_array(input, false_value) ~= nil then
- return false
+ if def.match ~= nil then
+ if type(def.match) ~= 'string' then
+ throw_error('E008')
+ end
+ local match = string.match(value, def.match)
+ if match == nil then
+ throw_error('E009', {
+ value = value,
+ key = key,
+ match = def.match:gsub('%%', '%%%%'),
+ })
+ else
+ return match
+ end
end
- end
- end,
+ end,
- process = function(value, key, def)
- if value == nil then
- return
- end
- if def.process ~= nil and type(def.process) == 'function' then
- return def.process(value, input_root, output, unknown)
- end
- end,
+ opposite_keys = function(value, key, def)
+ if def.opposite_keys ~= nil then
+ local function get_value(key1, key2)
+ local opposite_name
+ if def.opposite_keys[key1] ~= nil then
+ opposite_name = def.opposite_keys[key1]
+ elseif def.opposite_keys[key2] ~= nil then
+ opposite_name = def.opposite_keys[key2]
+ end
+ return opposite_name
+ end
+ local true_key = get_value(true, 1)
+ local false_key = get_value(false, 2)
+ if true_key == nil or false_key == nil then
+ throw_error('E010')
+ end
- pick = function(value, key, def)
- if def.pick then
- local pick_types
+ --- at param value string
+ local function remove_values(value)
+ local count = 0
+ while utils.remove_from_table(input, value) do
+ count = count + 1
+ end
+ return count
+ end
- -- Allow old deprecated attribut pick = true
- if def.pick == true then
- pick_types = { 'any' }
- elseif type(def.pick) == 'table' then
- pick_types = def.pick
- else
- pick_types = { def.pick }
- end
+ local true_count = remove_values(true_key)
+ local false_count = remove_values(false_key)
- -- Check if the pick attribute is valid
- for _, pick_type in ipairs(pick_types) do
- if type(pick_type) == 'string' and is[pick_type] == nil then
- throw_error(
- 'Wrong data type in the “pick” attribute: ' ..
- tostring(pick_type) ..
- '. Allowed are: any, boolean, dimension, integer, number, string.')
+ if true_count > 1 then
+ throw_error('E021', { key = true_key })
end
+
+ if false_count > 1 then
+ throw_error('E021', { key = false_key })
+ end
+
+ if true_count > 0 and false_count > 0 then
+ throw_error('E020',
+ { ['true'] = true_key, ['false'] = false_key })
+ end
+
+ return true_count == 1 or false_count == 0
end
+ end,
- -- The key has already a value. We leave the function at this
- -- point to be able to check the pick attribute for errors
- -- beforehand.
- if value ~= nil then
- return value
+ process = function(value, key, def)
+ if value == nil then
+ return
end
+ if def.process ~= nil and type(def.process) == 'function' then
+ return def.process(value, input_root, output, unknown)
+ end
+ end,
- for _, pick_type in ipairs(pick_types) do
- for i, v in pairs(input) do
- -- We can not use ipairs here. `ipairs(t)` iterates up to the
- -- first absent index. Values are deleted from the `input`
- -- table.
- if type(i) == 'number' then
- local picked_value = nil
- if is[pick_type](v) then
- picked_value = v
- end
+ pick = function(value, key, def)
+ if def.pick then
+ local pick_types
- if picked_value ~= nil then
- input[i] = nil
- return picked_value
+ ---Allow old deprecated attribut pick = true
+ if def.pick == true then
+ pick_types = { 'any' }
+ elseif type(def.pick) == 'table' then
+ pick_types = def.pick
+ else
+ pick_types = { def.pick }
+ end
+
+ ---Check if the pick attribute is valid
+ for _, pick_type in ipairs(pick_types) do
+ if type(pick_type) == 'string' and is[pick_type] == nil then
+ throw_error('E011', {
+ unknown = tostring(pick_type),
+ data_types = {
+ 'any',
+ 'boolean',
+ 'dimension',
+ 'integer',
+ 'number',
+ 'string',
+ },
+ })
+ end
+ end
+
+ ---The key has already a value. We leave the function at this
+ ---point to be able to check the pick attribute for errors
+ ---beforehand.
+ if value ~= nil then
+ return value
+ end
+
+ for _, pick_type in ipairs(pick_types) do
+ for i, v in pairs(input) do
+ ---We can not use ipairs here. `ipairs(t)` iterates up to the
+ ---first absent index. Values are deleted from the `input`
+ ---table.
+ if type(i) == 'number' then
+ local picked_value = nil
+ if is[pick_type](v) then
+ picked_value = v
+ end
+
+ if picked_value ~= nil then
+ input[i] = nil
+ return picked_value
+ end
end
end
end
end
+ end,
+
+ required = function(value, key, def)
+ if def.required ~= nil and def.required and value == nil then
+ throw_error('E012', { key = key })
+ end
+ end,
+
+ sub_keys = function(value, key, def)
+ if def.sub_keys ~= nil then
+ local v
+ ---To get keys defined with always_present
+ if value == nil then
+ v = {}
+ elseif type(value) == 'string' then
+ v = { value }
+ elseif type(value) == 'table' then
+ v = value
+ end
+ v = apply_definitions(def.sub_keys, opts, v, output[key],
+ unknown, add_to_key_path(key_path, key), input_root)
+ if utils.get_table_size(v) > 0 then
+ return v
+ end
+ end
+ end,
+ }
+
+ ---standalone values are removed.
+ ---For some callbacks and the third return value of parse, we
+ ---need an unchanged raw result from the parse function.
+ input = utils.clone_table(input)
+ if output == nil then
+ output = {}
+ end
+ if unknown == nil then
+ unknown = {}
+ end
+ if key_path == nil then
+ key_path = {}
+ end
+
+ for index, def in pairs(defs) do
+ ---Find key and def
+ local key
+ ---`{ key1 = { }, key2 = { } }`
+ if type(def) == 'table' and def.name == nil and type(index) ==
+ 'string' then
+ key = index
+ ---`{ { name = 'key1' }, { name = 'key2' } }`
+ elseif type(def) == 'table' and def.name ~= nil then
+ key = def.name
+ ---Definitions as strings in an array: `{ 'key1', 'key2' }`
+ elseif type(index) == 'number' and type(def) == 'string' then
+ key = def
+ def = { default = get_default_value({}) }
end
- end,
- required = function(value, key, def)
- if def.required ~= nil and def.required and value == nil then
- throw_error(string.format('Missing required key “%s”!', key))
+ if type(def) ~= 'table' then
+ throw_error('E013', { data_type = tostring(def), key = index }) ---key is nil
end
- end,
- sub_keys = function(value, key, def)
- if def.sub_keys ~= nil then
- local v
- -- To get keys defined with always_present
- if value == nil then
- v = {}
- elseif type(value) == 'string' then
- v = { value }
- elseif type(value) == 'table' then
- v = value
+ for attr, _ in pairs(def) do
+ if namespace.attrs[attr] == nil then
+ throw_error('E014', {
+ unknown = attr,
+ attr_names = utils.get_table_keys(namespace.attrs),
+ })
end
- v = apply_definitions(def.sub_keys, opts, v, output[key],
- unknown, add_to_key_path(key_path, key), input_root)
- if utils.get_table_size(v) > 0 then
- return v
- end
end
- end,
- }
- --- standalone values are removed.
- -- For some callbacks and the third return value of parse, we
- -- need an unchanged raw result from the parse function.
- input = clone_table(input)
- if output == nil then
- output = {}
- end
- if unknown == nil then
- unknown = {}
- end
- if key_path == nil then
- key_path = {}
- end
+ if key == nil then
+ throw_error('E015')
+ end
- for index, def in pairs(defs) do
- -- Find key and def
- local key
- -- `{ key1 = { }, key2 = { } }`
- if type(def) == 'table' and def.name == nil and type(index) ==
- 'string' then
- key = index
- -- `{ { name = 'key1' }, { name = 'key2' } }`
- elseif type(def) == 'table' and def.name ~= nil then
- key = def.name
- -- Definitions as strings in an array: `{ 'key1', 'key2' }`
- elseif type(index) == 'number' and type(def) == 'string' then
- key = def
- def = { default = get_default_value({}) }
- end
+ local value = find_value(key, def)
- if type(def) ~= 'table' then
- throw_error('Key definition must be a table!')
- end
-
- for attr, _ in pairs(def) do
- if namespace.attrs[attr] == nil then
- throw_error('Unknown definition attribute: ' .. tostring(attr))
+ for _, def_opt in ipairs({
+ 'alias',
+ 'opposite_keys',
+ 'pick',
+ 'always_present',
+ 'required',
+ 'data_type',
+ 'choices',
+ 'match',
+ 'exclusive_group',
+ 'macro',
+ 'l3_tl_set',
+ 'process',
+ 'sub_keys',
+ }) do
+ if def[def_opt] ~= nil then
+ local tmp_value = apply[def_opt](value, key, def)
+ if tmp_value ~= nil then
+ value = tmp_value
+ end
+ end
end
- end
- if key == nil then
- throw_error('Key name couldn’t be detected!')
+ output[key] = value
end
- local value = find_value(key, def)
-
- for _, def_opt in ipairs({
- 'alias',
- 'opposite_keys',
- 'pick',
- 'always_present',
- 'required',
- 'data_type',
- 'choices',
- 'match',
- 'exclusive_group',
- 'macro',
- 'l3_tl_set',
- 'process',
- 'sub_keys',
- }) do
- if def[def_opt] ~= nil then
- local tmp_value = apply[def_opt](value, key, def)
- if tmp_value ~= nil then
- value = tmp_value
+ if utils.get_table_size(input) > 0 then
+ ---Move to the current unknown table.
+ local current_unknown = unknown
+ for _, key in ipairs(key_path) do
+ if current_unknown[key] == nil then
+ current_unknown[key] = {}
end
+ current_unknown = current_unknown[key]
end
- end
- output[key] = value
- end
-
- if utils.get_table_size(input) > 0 then
- -- Move to the current unknown table.
- local current_unknown = unknown
- for _, key in ipairs(key_path) do
- if current_unknown[key] == nil then
- current_unknown[key] = {}
+ ---Copy all unknown key-value-pairs to the current unknown table.
+ for key, value in pairs(input) do
+ current_unknown[key] = value
end
- current_unknown = current_unknown[key]
end
- -- Copy all unknown key-value-pairs to the current unknown table.
- for key, value in pairs(input) do
- current_unknown[key] = value
- end
+ return output, unknown
end
- return output, unknown
-end
+ ---
+ ---Parse a LaTeX/TeX style key-value string into a Lua table.
+ ---
+ --- at param kv_string string # A string in the TeX/LaTeX style key-value format as described above.
+ --- at param opts? table # A table containing options.
+ ---
+ --- at return table result # The final result of all individual parsing and normalization steps.
+ --- at return table unknown # A table with unknown, undefinied key-value pairs.
+ --- at return table raw # The unprocessed, raw result of the LPeg parser.
+ local function parse(kv_string, opts)
+ if kv_string == nil then
+ return {}, {}, {}
+ end
---- Parse a LaTeX/TeX style key-value string into a Lua table.
----
---- at param kv_string string # A string in the TeX/LaTeX style key-value format as described above.
---- at param opts? table # A table containing the settings:
---- `convert_dimensions`, `unpack`, `naked_as_value`, `converter`,
---- `debug`, `preprocess`, `postprocess`.
---
---- at return table result # The final result of all individual parsing and normalization steps.
---- at return table unknown # A table with unknown, undefinied key-value pairs.
---- at return table raw # The unprocessed, raw result of the LPeg parser.
-local function parse(kv_string, opts)
- if kv_string == nil then
- return {}, {}, {}
- end
+ opts = normalize_opts(opts)
- opts = normalize_opts(opts)
+ if type(opts.hooks.kv_string) == 'function' then
+ kv_string = opts.hooks.kv_string(kv_string)
+ end
- if type(opts.hooks.kv_string) == 'function' then
- kv_string = opts.hooks.kv_string(kv_string)
- end
+ local result = generate_parser('list', opts):match(kv_string)
+ local raw = utils.clone_table(result)
- local result = generate_parser('list', opts):match(kv_string)
- local raw = clone_table(result)
+ local function apply_hook(name)
+ if type(opts.hooks[name]) == 'function' then
+ if name:match('^keys') then
+ result = utils.visit_tree(result, opts.hooks[name])
+ else
+ opts.hooks[name](result)
+ end
- local function apply_hook(name)
- if type(opts.hooks[name]) == 'function' then
- if name:match('^keys') then
- result = visit_tree(result, opts.hooks[name])
- else
- opts.hooks[name](result)
+ if opts.debug then
+ print('After the execution of the hook: ' .. name)
+ visualizers.debug(result)
+ end
end
+ end
- if opts.debug then
- print('After the execution of the hook: ' .. name)
- debug(result)
+ local function apply_hooks(at)
+ if at ~= nil then
+ at = '_' .. at
+ else
+ at = ''
end
+ apply_hook('keys' .. at)
+ apply_hook('result' .. at)
end
- end
- local function apply_hooks(at)
- if at ~= nil then
- at = '_' .. at
- else
- at = ''
- end
- apply_hook('keys' .. at)
- apply_hook('result' .. at)
- end
+ apply_hooks('before_opts')
- apply_hooks('before_opts')
+ ---
+ ---Normalize the result table of the LPeg parser. This normalization
+ ---tasks are performed on the raw input table coming directly from
+ ---the PEG parser:
+ --
+ --- at param result table # The raw input table coming directly from the PEG parser
+ --- at param opts table # Some options.
+ local function apply_opts(result, opts)
+ local callbacks = {
+ unpack = function(key, value)
+ if type(value) == 'table' and utils.get_array_size(value) == 1 and
+ utils.get_table_size(value) == 1 and type(value[1]) ~=
+ 'table' then
+ return key, value[1]
+ end
+ return key, value
+ end,
- --- Normalize the result table of the LPeg parser. This normalization
- -- tasks are performed on the raw input table coming directly from
- -- the PEG parser:
- --
- --- at param result table # The raw input table coming directly from the PEG parser
- --- at param opts table # Some options.
- local function apply_opts(result, opts)
- local callbacks = {
- unpack = function(key, value)
- if type(value) == 'table' and utils.get_array_size(value) == 1 and
- utils.get_table_size(value) == 1 and type(value[1]) ~= 'table' then
- return key, value[1]
- end
- return key, value
- end,
+ process_naked = function(key, value)
+ if type(key) == 'number' and type(value) == 'string' then
+ return value, opts.default
+ end
+ return key, value
+ end,
- process_naked = function(key, value)
- if type(key) == 'number' and type(value) == 'string' then
- return value, opts.default
- end
- return key, value
- end,
-
- format_key = function(key, value)
- if type(key) == 'string' then
- for _, style in ipairs(opts.format_keys) do
- if style == 'lower' then
- key = key:lower()
- elseif style == 'snake' then
- key = key:gsub('[^%w]+', '_')
- elseif style == 'upper' then
- key = key:upper()
- else
- throw_error('Unknown style to format keys: ' ..
- tostring(style) ..
- ' Allowed styles are: lower, snake, upper')
+ format_key = function(key, value)
+ if type(key) == 'string' then
+ for _, style in ipairs(opts.format_keys) do
+ if style == 'lower' then
+ key = key:lower()
+ elseif style == 'snake' then
+ key = key:gsub('[^%w]+', '_')
+ elseif style == 'upper' then
+ key = key:upper()
+ else
+ throw_error('E017', {
+ unknown = style,
+ styles = { 'lower', 'snake', 'upper' },
+ })
+ end
end
end
- end
- return key, value
- end,
+ return key, value
+ end,
- apply_invert_flag = function(key, value)
- if type(key) == 'string' and key:find(opts.invert_flag) then
- return key:gsub(opts.invert_flag, ''), not value
+ apply_invert_flag = function(key, value)
+ if type(key) == 'string' and key:find(opts.invert_flag) then
+ return key:gsub(opts.invert_flag, ''), not value
+ end
+ return key, value
+ end,
+ }
+
+ if opts.unpack then
+ result = utils.visit_tree(result, callbacks.unpack)
+ end
+
+ if not opts.naked_as_value and opts.defs == false then
+ result = utils.visit_tree(result, callbacks.process_naked)
+ end
+
+ if opts.format_keys then
+ if type(opts.format_keys) ~= 'table' then
+ throw_error('E018', { data_type = type(opts.format_keys) })
end
- return key, value
- end,
- }
+ result = utils.visit_tree(result, callbacks.format_key)
+ end
- if opts.unpack then
- result = visit_tree(result, callbacks.unpack)
+ if opts.invert_flag then
+ result = utils.visit_tree(result, callbacks.apply_invert_flag)
+ end
+
+ return result
end
+ result = apply_opts(result, opts)
- if not opts.naked_as_value and opts.defs == false then
- result = visit_tree(result, callbacks.process_naked)
+ ---All unknown keys are stored in this table
+ local unknown = nil
+ if type(opts.defs) == 'table' then
+ apply_hooks('before_defs')
+ result, unknown = apply_definitions(opts.defs, opts, result, {},
+ {}, {}, utils.clone_table(result))
end
- if opts.format_keys then
- if type(opts.format_keys) ~= 'table' then
- throw_error(
- 'The option “format_keys” has to be a table not ' ..
- type(opts.format_keys))
- end
- result = visit_tree(result, callbacks.format_key)
+ apply_hooks()
+
+ if opts.defaults ~= nil and type(opts.defaults) == 'table' then
+ utils.merge_tables(result, opts.defaults, false)
end
- if opts.invert_flag then
- result = visit_tree(result, callbacks.apply_invert_flag)
+ if opts.debug then
+ visualizers.debug(result)
end
- return result
- end
- result = apply_opts(result, opts)
+ if opts.accumulated_result ~= nil and type(opts.accumulated_result) ==
+ 'table' then
+ utils.merge_tables(opts.accumulated_result, result, true)
+ end
- -- All unknown keys are stored in this table
- local unknown = nil
- if type(opts.defs) == 'table' then
- apply_hooks('before_defs')
- result, unknown = apply_definitions(opts.defs, opts, result, {}, {},
- {}, clone_table(result))
+ ---no_error
+ if not opts.no_error and type(unknown) == 'table' and
+ utils.get_table_size(unknown) > 0 then
+ throw_error('E019', { unknown = visualizers.render(unknown) })
+ end
+ return result, unknown, raw
end
- apply_hooks()
+ ---
+ ---A table to store parsed key-value results.
+ local result_store = {}
- if opts.defaults ~= nil and type(opts.defaults) == 'table' then
- merge_tables(result, opts.defaults)
- end
+ return {
+ new = main,
- if opts.debug then
- debug(result)
- end
+ version = { 0, 12, 0 },
- -- no_error
- if not opts.no_error and type(unknown) == 'table' and
- utils.get_table_size(unknown) > 0 then
- throw_error('Unknown keys: ' .. render(unknown))
- end
- return result, unknown, raw
-end
+ --- at see parse
+ parse = parse,
---- Store results
--- @section
+ define = function(defs, opts)
+ return function(kv_string, inner_opts)
+ local options
---- A table to store parsed key-value results.
-local result_store = {}
+ if inner_opts ~= nil and opts ~= nil then
+ options = utils.merge_tables(opts, inner_opts)
+ elseif inner_opts ~= nil then
+ options = inner_opts
+ elseif opts ~= nil then
+ options = opts
+ end
---- Exports
--- @section
+ if options == nil then
+ options = {}
+ end
-local export = {
- version = { 0, 11, 0 },
+ options.defs = defs
- ---Get a new instance of the luakeys module.
- ---
- --- at return table # A new instance of the luakeys module.
- get_private_instance = function()
- package.loaded.luakeys = nil
- local luakeys = require('luakeys')
- package.loaded.luakeys = nil
- return luakeys
- end,
+ return parse(kv_string, options)
+ end
+ end,
- namespace = namespace,
+ --- at see default_opts
+ opts = default_opts,
- ---This function is used in the documentation.
- ---
- --- at param from string # A key in the namespace table, either `opts`, `hook` or `attrs`.
- print_names = function(from)
- local names = {}
- for name in pairs(namespace[from]) do
- table.insert(names, name)
- end
- table.sort(names)
- tex.print(table.concat(names, ', '))
- end,
+ error_messages = error_messages,
- print_default = function(from, name)
- tex.print(tostring(namespace[from][name]))
- end,
+ --- at see visualizers.render
+ render = visualizers.render,
- --- @see default_options
- opts = default_options,
+ --- at see visualizers.stringify
+ stringify = visualizers.stringify,
- --- @see stringify
- stringify = stringify,
+ --- at see visualizers.debug
+ debug = visualizers.debug,
- --- @see parse
- parse = parse,
+ ---
+ ---The function `save(identifier, result): void` saves a result (a
+ ---table from a previous run of `parse`) under an identifier.
+ ---Therefore, it is not necessary to pollute the global namespace to
+ ---store results for the later usage.
+ ---
+ --- at param identifier string # The identifier under which the result is saved.
+ ---
+ --- at param result table # A result to be stored and that was created by the key-value parser.
+ save = function(identifier, result)
+ result_store[identifier] = result
+ end,
- define = function(defs, opts)
- return function(kv_string, inner_opts)
- local options
+ ---The function `get(identifier): table` retrieves a saved result
+ ---from the result store.
+ ---
+ --- at param identifier string # The identifier under which the result was saved.
+ ---
+ --- at return table
+ get = function(identifier)
+ ---if result_store[identifier] == nil then
+ --- throw_error('No stored result was found for the identifier \'' .. identifier .. '\'')
+ ---end
+ return result_store[identifier]
+ end,
- if inner_opts ~= nil and opts ~= nil then
- options = merge_tables(opts, inner_opts)
- elseif inner_opts ~= nil then
- options = inner_opts
- elseif opts ~= nil then
- options = opts
- end
+ is = is,
- if options == nil then
- options = {}
- end
+ utils = utils,
- options.defs = defs
+ ---
+ ---Exported but intentionally undocumented functions
+ ---
- return parse(kv_string, options)
- end
- end,
+ namespace = utils.clone_table(namespace),
- --- @see render
- render = render,
+ ---
+ ---This function is used in the documentation.
+ ---
+ --- at param from string # A key in the namespace table, either `opts`, `hook` or `attrs`.
+ print_names = function(from)
+ local names = utils.get_table_keys(namespace[from])
+ tex.print(table.concat(names, ', '))
+ end,
- --- @see debug
- debug = debug,
+ print_default = function(from, name)
+ tex.print(tostring(namespace[from][name]))
+ end,
- --- The function `save(identifier, result): void` saves a result (a
- -- table from a previous run of `parse`) under an identifier.
- -- Therefore, it is not necessary to pollute the global namespace to
- -- store results for the later usage.
- --
- --- at param identifier string # The identifier under which the result is saved.
- --
- --- at param result table # A result to be stored and that was created by the key-value parser.
- save = function(identifier, result)
- result_store[identifier] = result
- end,
+ ---
+ --- at param exported_table table
+ depublish_functions = function(exported_table)
+ local function warn_global_import()
+ throw_error('E023')
+ end
- --- The function `get(identifier): table` retrieves a saved result
- -- from the result store.
- --
- --- at param identifier string # The identifier under which the result was saved.
- ---
- --- at return table
- get = function(identifier)
- -- if result_store[identifier] == nil then
- -- throw_error('No stored result was found for the identifier \'' .. identifier .. '\'')
- -- end
- return result_store[identifier]
- end,
+ exported_table.parse = warn_global_import
+ exported_table.define = warn_global_import
+ exported_table.save = warn_global_import
+ exported_table.get = warn_global_import
+ end,
+ }
- is = is,
+end
- utils = utils,
-}
-
-return export
+return main
Modified: trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.sty 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,5 +1,5 @@
%% luakeys.sty
-%% Copyright 2021-2022 Josef Friedrich
+%% Copyright 2021-2023 Josef Friedrich
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
@@ -17,5 +17,14 @@
% luakeys-debug.sty and luakeys-debug.tex.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luakeys}[2022/12/23 0.11.0 Parsing key-value options using Lua.]
-\directlua{luakeys = require('luakeys')}
+\ProvidesPackage{luakeys}[2023/01/05 v0.12.0 Parsing key-value options using Lua.]
+\directlua{
+ if luakeys == nil then
+ luakeys = require('luakeys')()
+ luakeys.depublish_functions(luakeys)
+ end
+}
+
+\def\LuakeysGetPackageOptions{\luaescapestring{\@ptionlist{\@currname.\@currext}}}
+
+\def\LuakeysGetClassOptions{\luaescapestring{\@raw at classoptionslist}}
Modified: trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.tex
===================================================================
--- trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.tex 2023-01-05 00:50:44 UTC (rev 65467)
+++ trunk/Master/texmf-dist/tex/luatex/luakeys/luakeys.tex 2023-01-05 21:18:54 UTC (rev 65468)
@@ -1,5 +1,5 @@
%% luakeys.tex
-%% Copyright 2021-2022 Josef Friedrich
+%% Copyright 2021-2023 Josef Friedrich
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
@@ -16,4 +16,9 @@
% This work consists of the files luakeys.lua, luakeys.sty, luakeys.tex
% luakeys-debug.sty and luakeys-debug.tex.
-\directlua{luakeys = require('luakeys')}
+\directlua{
+ if luakeys == nil then
+ luakeys = require('luakeys')()
+ luakeys.depublish_functions(luakeys)
+ end
+}
More information about the tex-live-commits
mailing list.