texlive[59655] Master/texmf-dist: expkv-cs (20jun21)
commits+karl at tug.org
commits+karl at tug.org
Sun Jun 20 21:56:27 CEST 2021
Revision: 59655
http://tug.org/svn/texlive?view=revision&revision=59655
Author: karl
Date: 2021-06-20 21:56:27 +0200 (Sun, 20 Jun 2021)
Log Message:
-----------
expkv-cs (20jun21)
Modified Paths:
--------------
trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md
trunk/Master/texmf-dist/doc/latex/expkv-cs/expkv-cs.pdf
trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx
trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex
Modified: trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md 2021-06-20 19:56:11 UTC (rev 59654)
+++ trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md 2021-06-20 19:56:27 UTC (rev 59655)
@@ -1,7 +1,7 @@
-------------------------------------------------------------------------------
# expkv-cs -- define expandable key=val macros using expkv
-Version 2021-06-03 v0.10
+Version 2021-06-20 v1.0
Released under the LaTeX Project Public License v1.3c or later
See http://www.latex-project.org/lppl.txt
Modified: trunk/Master/texmf-dist/doc/latex/expkv-cs/expkv-cs.pdf
===================================================================
(Binary files differ)
Modified: trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx 2021-06-20 19:56:11 UTC (rev 59654)
+++ trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx 2021-06-20 19:56:27 UTC (rev 59655)
@@ -86,7 +86,7 @@
\RequirePackage{caption}
\RequirePackage{microtype}
\RequirePackage{accsupp}
-\lstdefinelanguage{expkvd}[primitive]{TeX}
+\lstdefinelanguage{expkvc}[primitive]{TeX}
{
,moretexcs=[4]^^A e-TeX
{
@@ -124,6 +124,7 @@
ekvcHash,ekvcHashAndForward,ekvcHashAndUse,
ekvcValue,ekvcValueFast,ekvcValueSplit,ekvcValueSplitFast,
ekvcSecondaryKeys,
+ ekvcChange,
ekvcFlagNew,
ekvcFlagHeight,
ekvcFlagRaise,
@@ -130,7 +131,8 @@
ekvcFlagSetTrue,ekvcFlagSetFalse,
ekvcFlagIf,ekvcFlagIfRaised,
ekvcFlagReset,
- ekvcFlagGetHeight,ekvcFlagGetHeights
+ ekvcFlagGetHeight,ekvcFlagGetHeights,
+ ekvcPass
}
,moretexcs=[3]^^A expkv-pkg macros
{
@@ -157,7 +159,7 @@
\def\mylstwd{.55em}
\lstset
{
- ,language=expkvd
+ ,language=expkvc
,flexiblecolumns=false
,basewidth=\mylstwd
,gobble=2
@@ -214,6 +216,7 @@
\definecolor{expkvred}{HTML}{9F393D}
\colorlet{expkvgrey}{black!75}
\makeatletter
+\newcommand*\example{\par\smallskip\noindent\textit{Example:} \ignorespaces}
\newcommand*\expkv
{^^A
\texorpdfstring
@@ -282,9 +285,11 @@
\DoNotIndex{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space,\advance}
\DoNotIndex{\@,\unexpanded,\string,\expanded,\dimexpr,\global,\glueexpr,\hbox}
\DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef,\gdef,\newcount}
-\DoNotIndex{\^,\@firstofone,\@firstoftwo,\@gobble}
+\DoNotIndex{\number,\detokenize,\meaning}
+\DoNotIndex{\^,\@firstofone,\@firstoftwo,\@gobble,\@secondoftwo}
\DoNotIndex{\ifcsname}
\DoNotIndex{\ifx}
+\DoNotIndex{\ifodd}
\DoNotIndex{\ifnum}
\DoNotIndex{\ifdefined}
\DoNotIndex{\iffalse}
@@ -296,6 +301,7 @@
\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi
\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi
\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi
+\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi
\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}}
\makeatother
\begin{document}
@@ -357,12 +363,14 @@
% has its own set of primary and secondary keys.
%
% A word of advice you should consider: If your macro doesn't have to be
-% expandable (and often it doesn't) don't use \expkvc. The interface has some
-% overhead (though it still can be considered fast -- check \autoref{sec:speed})
-% and the approach has its limits in versatility. If you don't need to be
+% expandable (and often it doesn't) consider not using \expkvc. The interface
+% has some overhead (though it still is fast -- check \autoref{sec:speed}) and
+% the approach has its limits in versatility. If you don't need to be
% expandable, you should consider either defining your keys manually using
% \expkv\ or using \expkvd\ for convenience. Or you resort to another \kv\
-% interface.
+% interface. Nevertheless setting up macros with \expkvc, especially with
+% |\ekvcSplit|, is very convenient in my opinion, so if you just want to define
+% a single macro with just a few keys this might be the way to go.
%
% \expkvc\ is usable as generic code and as a \LaTeX\ package. It'll
% automatically load \expkv\ in the same mode as well. To use it, just use one
@@ -373,13 +381,14 @@
% \end{lstlisting}
%
%
-% \subsection{Define Macros and Primary Keys}
+% \subsection{Define Macros and Primary Keys}\label{sec:define}
%
% All macros defined with \expkvc\ have to be previously undefined or have the
-% |\meaning| of |\relax|. This is necessary as there is no way to undefine keys
-% once they are set up (neither \expkv\ nor \expkvc\ keep track of defined
-% keys) -- so to make sure there are no conflicts only new definitions are
-% allowed (that's not the case for individual keys, only for frontend macros).
+% |\meaning| of |\relax|. This is necessary as there is no way to automatically
+% undefine keys once they are set up (neither \expkv\ nor \expkvc\ keep track of
+% defined keys) -- so to make sure there are no conflicts only new definitions
+% are allowed (that's not the case for individual keys, only for frontend
+% macros).
%
%
% \subsubsection{Primary Keys}\label{sec:primaries}
@@ -389,12 +398,37 @@
% primary key and \val\ the associated initial value. By default all keys are
% defined short, but you can define long keys by prefixing \key\ with |long|
% (\emph{e.g.}, \texttt{long name=Jonathan P. Spratte}). You only need |long| if
-% the key should be able to take a |\par| token. Note however that |long| keys
-% are a microscopic grain faster (due to some internals of \expkvc). Only if at
-% least one of the keys was |long| the \meta{cs} in the following defining
-% macros will be |\long|. For obvious reasons there is no possibility to define
-% a macro or key as |\protected|.
+% the key should be able to take an explicit |\par| token. Note however that
+% |long| keys are a microscopic grain faster (due to some internals of \expkvc).
+% Only if at least one of the keys was |long| the \meta{cs} in the following
+% defining macros will be |\long|. For obvious reasons there is no possibility
+% to define a macro or key as |\protected|.
%
+% To allow keys not defined |long| which key names should start with |long|, you
+% can also use the prefix |short| (|short| and |long| are mutually exclusive,
+% which ever comes first defines the behaviour, the latter is considered part of
+% the key name). Note that this is the only reason for |short|'s existance,
+% essentially it does nothing.
+%
+% The consequence culminates in the following:
+% \begin{lstlisting}
+% \ekvcSplit\foo
+% {
+% long short = abc\par
+% ,short long = def
+% }
+% {#1#2}
+% \end{lstlisting}
+% will define a macro |\foo| that knows two primary keys, the first one is
+% called |short|, and accepts explicit |\par| tokens inside its values, the
+% second one is called |long| and will not accept |\par| tokens (leading to a
+% low level \TeX\ error). A description of |\ekvcSplit| follows shortly.
+%
+% There is one exception to these syntax rules of \meta{primary keys}: One can
+% include a key named |...| without a value. If this is found the \meta{cs} will
+% be defined |\long|. Any unknown keys found at use time will end up in a list
+% at this spot. See some examples in \autoref{sec:unknown}.
+%
% At the moment \expkvc\ doesn't require any internal keys, but I can't foresee
% whether this will be the case in the future as well, as it might turn out that
% some features I deem useful can't be implemented without such internal keys.
@@ -420,6 +454,20 @@
% key defined first). With |\ekvcSplit| you can define macros using at most
% nine primary keys.
% \end{function}
+% \example The following defines a macro |\foo| that takes the keys |a| and |b|
+% and outputs their values in a textual form:\\
+% \begin{minipage}{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+% \foo{}
+% \foo{b=e}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+% \foo{}
+% \foo{b=e}
+% \end{exresult}
%
% \begin{function}{\ekvcSplitAndForward}
% \begin{syntax}
@@ -439,6 +487,9 @@
% \ekvcSplitAndForward\foo{\foo at aux{more args}}{keyA = A, keyB = B}
% \end{lstlisting}
% \end{function}
+% \noindent
+% In the first case |\foo at aux| should take at least two arguments (|keyA| and
+% |keyB|), in the second case at least three (|more args|, |keyA|, and |keyB|).
%
% \begin{function}{\ekvcSplitAndUse}
% \begin{syntax}
@@ -448,20 +499,23 @@
% specifying what will be used after splitting the keys, \meta{cs} will use
% what follows the \kv\ list. So its syntax will be
% \end{function}
-% \begin{syntax}
-% \meta{cs}\{\key=\val, \ldots\}\marg{after}
-% \end{syntax}
+% \begin{quote}
+% \ttfamily
+% \meta{cs}\{\key=\val, \ldots\}\marg{after}
+% \end{quote}
+% and the code in |after| should expect at least as many arguments as the number
+% of keys defined for \meta{cs}.
%
% \subsubsection{Hash}
%
% The hash variants will provide the key values as a single argument in which
% you can access specific values using a special macro. The implementation might
-% be more convenient and scale better, \emph{but} it is much slower (for a
-% primitive macro with a single key benchmarking was almost $1.7$ times slower,
-% the root of which being the key access with |\ekvcValue|, not the parsing, and
-% for a key access using |\ekvcValueFast| it was still about $1.2$ times
-% slower). So if your macro uses less than ten primary keys, you should most
-% likely use the split approach.
+% be more convenient and scale better, \emph{but} it is slower (for a
+% rudimentary macro with a single key benchmarking was almost $1.7$ times
+% slower, the root of which being the key access with |\ekvcValue|, not the
+% parsing, and for a key access using |\ekvcValueFast| it was still about $1.2$
+% times slower). So if your macro uses less than ten primary keys, you should
+% consider using the split approach.
%
% \begin{function}{\ekvcHash}
% \begin{syntax}
@@ -474,6 +528,22 @@
% \meta{definition}, in which you can access the \val\ of a \key\ by using
% \texttt{\cs[no-index]{ekvcValue}\{\key\}\{\#1\}}.
% \end{function}
+% \example This defines an equivalent macro to the |\foo| defined with
+% |\ekvcSplit| earlier:\\
+% \begin{minipage}{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcHash\foo{a=a,b=b}{a is \ekvcValue{a}{#1}.\par
+% b is \ekvcValue{b}{#1}.\par}
+% \foo{}
+% \foo{b=e}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \ekvcHash\foo{a=a,b=b}{a is \ekvcValue{a}{#1}.\par
+% b is \ekvcValue{b}{#1}.\par}
+% \foo{}
+% \foo{b=e}
+% \end{exresult}
%
% \begin{function}{\ekvcHashAndForward}
% \begin{syntax}
@@ -489,6 +559,13 @@
% \texttt{\cs[no-index]{ekvcValue}\{\key\}\{\#1\}} (or whichever argument the
% hashed \kv\ list will be).
% \end{function}
+% \example This defines a macro |\foo| processing two keys, and passing the
+% result to |\foobar|:
+% \begin{lstlisting}
+% \ekvcHashAndForward\foo\foobar{a=a,b=b}
+% \newcommand*\foobar[1]{a is \ekvcValue{a}{#1}.\par
+% b is \ekvcValue{b}{#1}.\par}
+% \end{lstlisting}
%
% \begin{function}{\ekvcHashAndUse}
% \begin{syntax}
@@ -495,12 +572,13 @@
% \cs{ekvcHashAndUse}\meta{cs}\marg{primary keys}
% \end{syntax}
% This will roughly do the same as |\ekvcHashAndForward|, but instead of
-% specifying what will be used after hashing the keys, \meta{cs} will use what
-% follows the \kv\ list. So its syntax will be
+% specifying what will be used after hashing the keys at install time,
+% \meta{cs} will use what follows the \kv\ list. So its syntax will be
% \end{function}
-% \begin{syntax}
-% \meta{cs}\{\key=\val, \ldots\}\marg{after}
-% \end{syntax}
+% \begin{quote}
+% \ttfamily
+% \meta{cs}\{\key=\val, \ldots\}\marg{after}
+% \end{quote}
%
% \begin{function}{\ekvcValue}
% \begin{syntax}
@@ -525,9 +603,9 @@
% a result this is about $1.4$ times faster \emph{but} will throw low level
% \TeX\ errors eventually if the hash function isn't defined or the \key\
% isn't part of the \meta{key list} (\emph{e.g.}, because it was defined as a
-% key for another macro -- all macros share the same hash function per \key).
-% Use it if you know what you're doing. This macro needs exactly three steps
-% of expansion in the no-errors case.
+% key for another macro -- all macros share the same hash function per \key\
+% name). Use it if you know what you're doing. This macro needs exactly three
+% steps of expansion in the no-errors case.
% \end{function}
%
% \begin{function}{\ekvcValueSplit}
@@ -537,13 +615,34 @@
% If you need a specific \key\ from a \meta{key list} more than once, it'll
% be a good idea to only extract it once and from then on keep it as a
% separate argument. Hence the macro \cs{ekvcValueSplit} will extract one
-% specific \key's value from the list and forward the remainder of the list
-% as the first and the \key's value as the second argument to \meta{next}, so
-% the result of this will be \meta{next}\marg{key list'}\marg{value} with
-% \meta{key list'} the remaining list. This is almost as fast as |\ekvcValue|
-% and runs the same tests. Keep in mind that you can't fetch for the same
-% \key\ again from \meta{key list'} as it got removed.
+% specific \key's value from the list and forward it as an argument to
+% \meta{next}, so the result
+% of this will be \meta{next}\marg{value}. This is roughly as fast as
+% |\ekvcValue| and runs the same tests.
% \end{function}
+% \example The following defines a macro |\foo| which will take three keys.
+% Since the next parsing step will need the value of one of the keys multiple
+% times we split that key off the list (in this example the next step doesn't
+% use the key multiple times for simplicity though), and the entire list is
+% forwarded as the second argument:\\
+% \begin{minipage}{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcHash\foo{a=a,b=b,c=c}
+% {\ekvcValueSplit{a}{#1}\foobar{#1}}
+% \newcommand*\foobar[2]{a is #1.\par
+% b is \ekvcValue{b}{#2}.\par
+% c is \ekvcValue{c}{#2}.\par}
+% \foo{}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \ekvcHash\foo{a=a,b=b,c=c}
+% {\ekvcValueSplit{a}{#1}\foobar{#1}}
+% \newcommand*\foobar[2]{a is #1.\par
+% b is \ekvcValue{b}{#2}.\par
+% c is \ekvcValue{c}{#2}.\par}
+% \foo{}
+% \end{exresult}
%
% \begin{function}{\ekvcValueSplitFast}
% \begin{syntax}
@@ -555,7 +654,7 @@
% \end{function}
%
%
-% \subsection{Secondary Keys}
+% \subsection{Secondary Keys}\label{sec:secondaries}
%
% To remove some of the limitations with the approach that each primary key
% matches an argument or hash entry, you can define secondary keys. Those have
@@ -641,8 +740,8 @@
% If \key\ is a defined value taking key, you can define a |NoVal| version
% with this that will behave as if \key\ was given \meta{default} as its
% \val. Note that this doesn't change the initial values of primary keys set
-% at definition time in |\ekvcSplit| and friends. \key\ can be a primary or
-% secondary key.
+% at definition time in |\ekvcSplit| and friends (see |\ekvcChange| in
+% \autoref{sec:change} for this). \key\ can be a primary or secondary key.
% \end{function}
%
% \begin{function}{flag-bool}
@@ -681,6 +780,167 @@
% \end{function}
%
%
+% \subsection{Changing the Initial Values}\label{sec:change}
+%
+% \begin{function}{\ekvcChange}
+% \begin{syntax}
+% \cs{ekvcChange}\meta{cs}\{\kv,\ldots\}
+% \end{syntax}
+% This processes the \kv\ list for the macro \meta{cs} to set new defaults for
+% it (meaning the values used if you don't provide anything at use time, not
+% those specified with the |default| secondary key). \meta{cs} should be
+% defined with \expkvc\ (so with any of the methods in \autoref{sec:define}).
+% Inside the \kv\ list both primary and secondary keys can be used. If
+% \meta{cs} was defined |\long| earlier it will still be |\long|, every other
+% \TeX\ prefix will be stripped (but \expkvc\ doesn't support them anywhere
+% else so that should be fine). The resulting new defaults will be stored
+% inside the \meta{cs} locally (just as the original defaults were). If there
+% was an unknown key forwarding added to \meta{cs} (see \autoref{sec:unknown})
+% any unknown key will be stored inside the list of unknown keys as well.
+% |\ekvcChange| is not expandable!
+% \end{function}
+%
+% Consider the following example:\\
+% \begin{minipage}[c]{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+% \begingroup
+% \ekvcChange\foo{b=B}
+% \foo{} % new defaults
+% \ekvcSecondaryKeys\foo{meta c={a={#1},b={#1}}}
+% \ekvcChange\foo{c=c}
+% \foo{} % newer defaults
+% \endgroup
+% \foo{} % initial defaults
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+% \begingroup
+% \ekvcChange\foo{b=B}
+% \foo{}
+% \ekvcSecondaryKeys\foo{meta c={a={#1},b={#1}}}
+% \ekvcChange\foo{c=c}
+% \foo{}
+% \endgroup
+% \foo{}
+% \end{exresult}
+%
+% As a result with this the typical setup macro could be implemented:
+% \begin{lstlisting}
+% \ekvcHashAndUse\foo{key=a,key=b}
+% \newcommand*\foosetup{\ekvcChange\foo}
+% \end{lstlisting}
+% Of course the usage is limited to a single macro |\foo|, hence this might not
+% be as powerful as similar macros used with other \kv\ interfaces. But at least
+% a few similar macros could be grouped using the same key parsing macro
+% internally.
+%
+%
+% \subsection{Handling Unknown Keys}\label{sec:unknown}
+%
+% If your macro should handle unknown keys without directly throwing an error
+% you can use the special |...| marker in the \meta{primary keys} list. Since
+% those keys will be processed once by \expkv\ they will be forwarded
+% normalised: The key name will be the result of one |\detokenize|, the value
+% will be forwarded as \verb*| {|\meta{value}\verb*|} |, so with spaces around
+% one set of braces (this way, most other \kv\ implementations should parse the
+% correct input).
+%
+% The exact behaviour differs slightly between the two variants (as all keys
+% do). The behaviour inside the split variants will be similar to normal primary
+% keys, the $n$-th argument (corresponding to the position of |...| inside the
+% primary keys list) will contain any unknown key encountered while parsing the
+% argument. And inside the split variant you can use a primary key named |...|
+% at the same time.
+%
+% \example The following will forward any unknown key to |\includegraphics| to
+% control the appearance while processing its own keys:\\
+% \begin{minipage}{.6\linewidth}
+% \begin{lstlisting}
+% \newcommand*\foo{\ekvoptarg\fooKV{}}
+% \ekvcSplitAndForward\fooKV\fooOUT
+% {
+% a=a
+% ,...
+% ,b=b
+% ,...={}
+% }
+% \newcommand\fooOUT[5]
+% {%
+% a is #1 and b is #3.\par
+% \includegraphics[{#2}]{#5}\par
+% \texttt{...} is #4.\par
+% }
+% \foo[width=.5\linewidth, b=c,
+% ...={a stupid key name, but works}]
+% {example-image-duck}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.4\linewidth}
+% \newcommand*\foo{\ekvoptarg\fooKV{}}
+% \ekvcSplitAndForward\fooKV\fooOUT
+% {
+% a=a
+% ,...
+% ,b=b
+% ,...={}
+% }
+% \newcommand\fooOUT[5]
+% {%
+% a is #1 and b is #3.\par
+% \includegraphics[{#2}]{#5}\par
+% \texttt{...} is #4.\par
+% }
+% \foo[width=.5\linewidth, b=c,
+% ...={a stupid key name, but works}]
+% {example-image-duck}
+% \end{exresult}
+%
+% Inside the hash variants the unknown keys list will be put inside the hash
+% named |...| (we have to use some name, so why not this). As a consequence a
+% primary key named |...| would clash with the unknown key handler. If you still
+% used such a key it would remove any unknown key stored there until that point
+% and replace the list with its value.
+%
+% \example The following is more or less equivalent to the example above, but
+% with the hash variant, and it will not contain the primary |...| key. We have
+% to make sure that |\includegraphics| sees the \kv\ list, so need to expand
+% |\ekvcValue{...}{#1}| before |\includegraphics| parses it.\\
+% \begin{minipage}{.76\linewidth}
+% \begin{lstlisting}
+% \newcommand*\foo{\ekvoptarg\fooKV{}}
+% \ekvcHashAndForward\fooKV\fooOUT
+% {a=a, b=b, ...}
+% \newcommand\fooOUT[2]
+% {%
+% a is \ekvcValue{a}{#1} and
+% b is \ekvcValue{b}{#1}.\par
+% \expanded{\noexpand\includegraphics
+% [{\ekvcValue{...}{#1}}]}
+% {#2}\par
+% }
+% \foo[width=\linewidth, b=c]
+% {example-image-duck-portrait}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.24\linewidth}
+% \newcommand*\foo{\ekvoptarg\fooKV{}}
+% \ekvcHashAndForward\fooKV\fooOUT
+% {a=a, b=b, ...}
+% \newcommand\fooOUT[2]
+% {%
+% a is \ekvcValue{a}{#1} and
+% b is \ekvcValue{b}{#1}.\par
+% \expanded{\noexpand\includegraphics
+% [{\ekvcValue{...}{#1}}]}
+% {#2}\par
+% }
+% \foo[width=\linewidth, b=c]
+% {example-image-duck-portrait}
+% \end{exresult}
+%
+%
% \subsection{Flags}\label{sec:flags}
%
% The idea of flags is taken from \pkg{expl3}. They provide a way to store
@@ -693,7 +953,8 @@
%
% The state of flags is always changed locally to the current group, but not to
% the current macro, so if you're using one of the |t|-types involving flags
-% bear in mind that they can affect other macros at the current group level!
+% bear in mind that they can affect other macros using the same flags at the
+% current group level!
%
% \expkvc\ provides some macros to access, alter, and use flags. Flags of
% \expkvc\ don't share a name space with the flags of \pkg{expl3}.
@@ -706,7 +967,7 @@
% whether the macro \meta{flag} is currently undefined. A \meta{flag} will
% expand to the flag's current height with a trailing space (so you can use it
% directly with |\ifnum| for example and it will terminate the number scanning
-% itself).
+% on its own).
% \end{function}
%
% All other macros dealing with flags take as a parameter a macro defined as a
@@ -791,26 +1052,26 @@
% \end{function}
%
%
-% \subsection{Example}
+% \subsection{Further Examples}\label{sec:examples}
%
-% How could a documentation be a good documentation without some basic examples?
-% Say we want to define a small macro expanding to some character description
-% (who knows why this has to be expandable?). A character description will not
-% have too many items to it, so we use |\ekvcSplit|.
+% How could a documentation be a good documentation without enough basic
+% examples? Say we want to define a small macro expanding to some character
+% description (who knows why this has to be expandable?). A character
+% description will not have too many items to it, so we use |\ekvcSplit| (the
+% comments with the parameter numbers are of course not necessary and just ease
+% reading the example).
% \begin{lstlisting}
% \ekvcSplit\character
% {
-% name=John Doe,
-% age=any,
-% nationality=the Universe,
-% hobby=to exist,
-% type=Mister,
-% pronoun=He,
-% possessive=his,
+% name=John Doe, % #1
+% age=any, % #2
+% nationality=the Universe, % #3
+% hobby=to exist, % #4
+% type=Mister, % #5
+% pronoun=He, % #6
+% possessive=his, % #7
% }
-% {%
-% #1 is a #5 from #3. #6 is of #2 age and #7 hobby is #4.\par
-% }
+% {#1 is a #5 from #3. #6 is of #2 age and #7 hobby is #4.\par}
% \end{lstlisting}
% Also we want to give some short cuts so that it's easier to describe several
% persons.
@@ -854,7 +1115,7 @@
% As one might see, the |lady| key could actually have been an |nmeta| key as
% well, as all that is done with the argument is using it as a \kv\ list.
%
-% The result of all the first two usages would be:
+% The result of only the first two usages would be:
% \begin{exresult}{\linewidth}
% \ekvcSplit\character
% {
@@ -898,7 +1159,9 @@
% and mandatory arguments as well. A small nonsense example (which should
% perhaps use |\ekvcSplitAndForward| instead of |\ekvcHashAndForward| since it
% only uses four keys and one other argument -- and isn't expandable since it
-% uses a \env{tabular} environment):
+% uses a \env{tabular} environment, so it would've been better to use a more
+% feature rich \kv\ interface most likely, \emph{e.g.}, the one provided by
+% \expkvd):
% \begin{lstlisting}
% \makeatletter
% \newcommand*\nonsense{\ekvoptarg\nonsense at a{}}
@@ -957,6 +1220,70 @@
% \end{exresult}
%
%
+% \subsection{Freedom for Keys!}
+%
+% If this was the \TeX book this subsection would have a double bend sign. Not
+% because it is overly complicated, but because it shows things which could
+% break \expkvc's expandability and its alignment safety. This is for
+% experienced users wanting to get the most flexibility and knowing what they
+% are doing.
+%
+% In case you're wondering, it is possible to define other keys than the
+% primaries and the secondary types listed in \autoref{sec:secondaries} for a
+% macro defined with \expkvc\ by using the low-level interface of \expkv\ or
+% even the interface provided by \expkvd. The set name used for \expkvc's keys
+% is the macro name, including the leading backslash, or more precisely
+% |\string|\meta{cs} is used. This can be exploited to define additional keys
+% with arbitrary code. Consider the following \emph{bad} example:
+% \begin{lstlisting}
+% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2\par}
+% \protected\ekvdef{\string\foo}{c}{\def\fooC{#1}}
+% \end{lstlisting}
+% This would define a key named |c| that will store its value inside a macro.
+% The issue with this is that this can't be done expandably. As a result, the
+% macro |\foo| isn't always expandable any more (not that bad if this was never
+% required; killjoy if it was) and as soon as the key |c| is used, it is also no
+% longer alignment safe\footnote{This means that the \kv-list can't contain
+% alignment markers that are not inside an additional set of braces if used
+% inside a \TeX\ alignment.}
+% (might be bad depending on the usage).
+%
+% So why do I show you this? Because we could as well do something useful like
+% create a key that pre-parses the input and after that passes the parsed value
+% on. This parsing would have to be completely expandable though. For the
+% pass-on part we can use the following function:
+%
+% \begin{function}{\ekvcPass}
+% \begin{syntax}
+% \cs{ekvcPass}\meta{cs}\marg{key}\marg{value}
+% \end{syntax}
+% This passes \meta{value} on to \meta{key} for the \expkvc-macro \meta{cs}.
+% It should be used inside the key parsing of a macro defined with \expkvc,
+% else this most likely results in a low level \TeX\ error. You can't forward
+% anything to the special unknown key handler |...| as that is no defined key.
+% \end{function}
+%
+% With this we could for example split the value of a key at a hyphen and pass
+% the parts to different keys:\\
+% \begin{minipage}[c]{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
+% \ekvdef{\string\foo}{c}{\fooSplit#1\par}
+% \def\fooSplit#1-#2\par
+% {\ekvcPass\foo{a}{#1}\ekvcPass\foo{b}{#2}}
+% \foo{}
+% \foo{c=1-2}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
+% \ekvdef{\string\foo}{c}{\fooSplit#1\par}
+% \def\fooSplit#1-#2\par{\ekvcPass\foo{a}{#1}\ekvcPass\foo{b}{#2}}
+% \foo{}
+% \foo{c=1-2}
+% \end{exresult}
+%
+%
% \subsection{Speed Considerations}\label{sec:speed}
%
% As already mentioned in the introduction there are some speed considerations
@@ -965,13 +1292,13 @@
% use case. The key-parsing is still faster than with most other \kv\ packages
% (see the ``Comparisons'' subsection in the \expkv\ documentation).
%
-% The speed considerations in this subsection use the first example in this
-% documentation as the benchmark. So we have seven keys and a short sentence
-% which should be typeset. For comparisons I use the following equivalent
-% \expkvd\ definitions. Each result is the average between changing no keys from
-% their initial values and altering four. Furthermore I'll compare three
-% variants of \expkvc\ with the \expkvd\ definitions, namely the split example
-% from above, a hash variant using |\ekvcValue| and a hash variant using
+% The speed considerations in this subsection use the first example of
+% \autoref{sec:examples} as the benchmark. So we have seven keys and a short
+% sentence which should be typeset. For comparisons I use the following
+% equivalent \expkvd\ definitions. Each result is the average between changing
+% no keys from their initial values and altering four. Furthermore I'll compare
+% three variants of \expkvc\ with the \expkvd\ definitions, namely the split
+% example from above, a hash variant using |\ekvcValue| and a hash variant using
% |\ekvcValueFast|.
% \begin{lstlisting}
% \usepackage{expkv-def}
@@ -996,8 +1323,9 @@
% {%
% \begingroup
% \ekvset{keys}{#1}%
-% \KEYSname\ is a \KEYStype\ from \KEYSnationality. \KEYSpronoun\ is
-% of \KEYSage\ age and \KEYSpossessive\ hobby is \KEYShobby.%
+% \KEYSname\ is a \KEYStype\ from \KEYSnationality.
+% \KEYSpronoun\ is of \KEYSage\ age and
+% \KEYSpossessive\ hobby is \KEYShobby.%
% \endgroup
% }
% \end{lstlisting}
@@ -1021,14 +1349,16 @@
% parsing part and only $1.5$ to $2.8$ times faster if the typesetting part is
% factored in. So the real choke isn't the parsing.
%
-% So to summarize this, if you have a reasonable use case for expandable \kv\
-% parsing macros you should go on and define them using \expkvc. If you have a
-% reasonable use case for \kv\ parsing macros but defining them expandable isn't
-% necessary for your use you should take advantage of the greater flexibility of
-% non-expandable \kv\ setups (but if you're after maximum speed there aren't
-% that many \kv\ parsers beating \expkvc). And if you are after maximum
-% performance maybe ditching the \kv\ interface altogether is a good idea, but
-% depending on the number of arguments your interface might get convoluted.
+% So to summarise this, if you have a use case for expandable \kv\
+% parsing macros you should go on and define them using \expkvc. If you just
+% want to define a simple macro with a few keys |\ekvcSplit| might be the
+% easiest interface there is. If you have a reasonable use case for \kv\ parsing
+% macros but defining them expandable isn't necessary for your use you should
+% take advantage of the greater flexibility of non-expandable \kv\ setups (but
+% if you're after maximum speed there aren't that many \kv\ parsers beating
+% \expkvc). And if you are after maximum performance maybe ditching the \kv\
+% interface altogether is a good idea, but depending on the number of arguments
+% your interface might get convoluted.
%
%
% \subsection{Useless Macros}
@@ -1127,8 +1457,8 @@
% \begin{macro}{\ekvcVersion,\ekvcDate}
% We're on our first input, so lets store the version and date in a macro.
% \begin{macrocode}
-\def\ekvcVersion{0.10}
-\def\ekvcDate{2021-06-03}
+\def\ekvcVersion{1.0}
+\def\ekvcDate{2021-06-20}
% \end{macrocode}
% \end{macro}
%
@@ -1148,6 +1478,14 @@
% |\ekvc at tmp| will be reused later, but we don't need it to ever store
% information long-term after \expkvc\ was initialized.
%
+% \begin{macro}[internal]{\ekvc at tripledots}
+% This macro just serves as a marker for a comparison to allow the syntax
+% for the unknown key handlers.
+% \begin{macrocode}
+\def\ekvc at tripledots{...}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[internal]{\ekvc at keycount}
% We'll need to keep count how many keys must be defined for each macro in the
% |split| variants.
@@ -1334,7 +1672,8 @@
% \begin{macro}[internal]
% {
% \ekvc at SetupSplitKeys, \ekvc at SetupSplitKeys@a, \ekvc at SetupSplitKeys@b,
-% \ekvc at SetupSplitKeys@c
+% \ekvc at SetupSplitKeys@c,
+% \ekvc at SetupSplitKeys@check at unknown,\ekvc at SetupSplitKeys@unknown
% }
% These macros parse the list of keys and set up the key macros. First we need
% to initialise some macros and start |\ekvparse|.
@@ -1344,7 +1683,7 @@
\ekvc at keycount=0
\let\ekvc at any@long\ekv at empty
\let\ekvc at initials\ekv at empty
- \ekvparse\ekvc at err@value at required\ekvc at SetupSplitKeys@a
+ \ekvparse\ekvc at SetupSplitKeys@check at unknown\ekvc at SetupSplitKeys@a
}
% \end{macrocode}
% Then we need to step the key counter for each key. Also we have to check
@@ -1421,6 +1760,47 @@
{}%
}
% \end{macrocode}
+% If no value was provided this could either be an error, or the unknown key
+% forwarding. We have to check this (comparing against |...| inside
+% |\ekvc at tripledots|) and if this is the unknown key list type, set it up
+% accordingly (advancing the key count and setting up the unknown handlers of
+% \expkv). Else we simply throw an error and ignore the incident.
+% \begin{macrocode}
+\protected\long\def\ekvc at SetupSplitKeys@check at unknown#1%
+ {%
+ \begingroup
+ \edef\ekvc at tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc at tripledots\ekvc at tmp
+ \advance\ekvc at keycount1
+% \end{macrocode}
+% The |\begingroup\expandafter\endgroup| ensures that the split mark isn't
+% actually defined (even if it just were with meaning |\relax|).
+% \begin{macrocode}
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc at SetupSplitKeys@unknown
+ \csname ekvc at splitmark@\the\ekvc at keycount\endcsname
+ \let\ekvc at any@long\long
+ \else
+ \ekvc at err@value at required{#1}%
+ \fi
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\protected\long\def\ekvc at SetupSplitKeys@unknown#1%
+ {%
+ \long\expandafter\def\csname\ekv at name\ekvc at set{}u\endcsname##1##2##3#1##4%
+ {##3#1{##4,##2= {##1} }}%
+ \long\expandafter\def\csname\ekv at name\ekvc at set{}uN\endcsname##1##2#1##3%
+ {##2#1{##3,##1}}%
+ \edef\ekvc at initials{\unexpanded\expandafter{\ekvc at initials#1{}}}%
+ \ekvc at helpers@needed
+ {\expandafter\ekvc at setup@splitmacro\expandafter{\the\ekvc at keycount}}%
+ {}%
+ }
+% \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekvc at split@p at long}
@@ -1436,6 +1816,14 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[internal]{\ekvc at split@p at short}
+% The |short| prefix does essentially nothing, it is only provided to allow
+% key names starting with |long| that aren't |\long|.
+% \begin{macrocode}
+\def\ekvc at split@p at short{\ekvc at SetupSplitKeys@c}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[internal]{\ekvc at defarggobbler}
% This is needed to define a macro with 1-9 parameters programmatically.
% \LaTeX's \cs[no-index]{newcommand} does something similar for example.
@@ -1623,7 +2011,11 @@
% \end{macro}
%
% \begin{macro}[internal]
-% {\ekvc at SetupHashKeys,\ekvc at SetupHashKeys@a,\ekvc at SetupHashKeys@b}
+% {%
+% \ekvc at SetupHashKeys,\ekvc at SetupHashKeys@a,\ekvc at SetupHashKeys@b,
+% \ekvc at SetupHashKeys@c,
+% \ekvc at SetupHashKeys@check at unknown,\ekvc at SetupHashKeys@unknown
+% }
% This should look awfully familiar as well, since it's just the same as for
% the split keys with a few other names here and there.
% \begin{macrocode}
@@ -1631,7 +2023,7 @@
{%
\let\ekvc at any@long\ekv at empty
\let\ekvc at initials\ekv at empty
- \ekvparse\ekvc at err@value at required\ekvc at SetupHashKeys@a{#1}%
+ \ekvparse\ekvc at SetupHashKeys@check at unknown\ekvc at SetupHashKeys@a{#1}%
}
\protected\def\ekvc at SetupHashKeys@a#1%
{%
@@ -1685,6 +2077,39 @@
\ekvc at setup@hashmacro{#1}%
}
% \end{macrocode}
+% \begin{macrocode}
+\protected\long\def\ekvc at SetupHashKeys@check at unknown#1%
+ {%
+ \begingroup
+ \edef\ekvc at tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc at tripledots\ekvc at tmp
+ \ekvc at SetupHashKeys@unknown
+ \let\ekvc at any@long\long
+ \else
+ \ekvc at err@value at required{#1}%
+ \fi
+ }
+% \end{macrocode}
+% \begin{macrocode}
+\def\ekvc at SetupHashKeys@unknown#1%
+ {%
+ \protected\def\ekvc at SetupHashKeys@unknown
+ {%
+ \expandafter
+ \let\csname\ekv at name\ekvc at set{}u\endcsname\ekvc at hash@unknown at kv
+ \expandafter
+ \let\csname\ekv at name\ekvc at set{}uN\endcsname\ekvc at hash@unknown at k
+ \edef\ekvc at initials{\unexpanded\expandafter{\ekvc at initials#1{}}}%
+ \ekvc at setup@hashmacro{...}%
+ }%
+ \long\def\ekvc at hash@unknown at kv##1##2##3#1##4{##3#1{##4,##2= {##1} }}%
+ \long\def\ekvc at hash@unknown at k##1##2#1##3{##2#1{##3,##1}}%
+ }
+\expandafter\ekvc at SetupHashKeys@unknown
+ \csname ekvc at hashmark@\ekvc at tripledots\endcsname
+% \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekvc at hash@p at long}
@@ -1699,6 +2124,14 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[internal]{\ekvc at hash@p at short}
+% The |short| prefix does essentially nothing, it is only provided to allow
+% key names starting with |long| that aren't |\long|.
+% \begin{macrocode}
+\def\ekvc at hash@p at short{\ekvc at SetupHashKeys@c}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[internal]{\ekvc at setup@hashmacro}
% The safe hash macros will be executed inside of an |\unexpanded| expansion
% context, so they have to insert braces for that once they are done.
@@ -1748,7 +2181,7 @@
\unexpanded\expandafter{\csname ekvc at hashmark@#1\endcsname}%
####2####3\unexpanded{\ekvc at stop}####4%
{%
- ####4{####1####3}{####2}%
+ ####4{####2}%
}%
\long\gdef\unexpanded\expandafter
{\csname ekvc at safesplithash@#1\endcsname}####1%
@@ -1755,11 +2188,12 @@
{%
\unexpanded\expandafter
{\csname ekvc@@safesplithash@#1\endcsname}%
- ####1\unexpanded{\ekvc at mark\ekvc at safe@found at hash}%
+ ####1\unexpanded{\ekvc at mark\ekvc at safe@after at hash}%
\unexpanded\expandafter
{%
\csname ekvc at hashmark@#1\endcsname{}%
- \ekvc at mark{\ekvc at err@missing at hash{#1}\ekvc at safe@no at hash}%
+ \ekvc at mark
+ {\ekvc at err@missing at hash{#1}\ekvc at safe@after at hash}%
\ekvc at stop
}%
}%
@@ -1770,7 +2204,7 @@
####2####3\unexpanded{\ekvc at mark}####4####5%
\unexpanded{\ekvc at stop}%
{%
- ####4{####2}####1####3\unexpanded{\ekvc at stop}%
+ ####4{####2}%
}%
}%
\ekvc at tmp
@@ -1812,23 +2246,16 @@
{\csname ekvc at safesplithash@#1\endcsname}%
{\ekvc at err@unknown at hash{#1}\ekvcValueSplit at recover}%
}
-\long\def\ekvcValueSplit at recover#1#2%
- {%
- #2{#1}{}%
- }
+\long\def\ekvcValueSplit at recover#1#2{#2{}}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[internal]{\ekvc at safe@found at hash, \ekvc at safe@no at hash}
+% \begin{macro}[internal]{\ekvc at safe@after at hash}
% \begin{macrocode}
-\long\def\ekvc at safe@found at hash#1#2\ekvc at stop#3%
+\long\def\ekvc at safe@after at hash#1#2%
{%
- #3{#2}{#1}%
+ #2{#1}%
}
-\long\def\ekvc at safe@no at hash#1#2\ekvc at mark\ekvc at safe@found at hash\ekvc at stop#3%
- {%
- #3{#2}{}%
- }
% \end{macrocode}
% \end{macro}
%
@@ -1839,9 +2266,7 @@
% sequence.
% \begin{macrocode}
\long\def\ekvcValueSplitFast#1#2%
- {%
- \csname ekvc at fastsplithash@#1\endcsname#2\ekvc at stop
- }
+ {\csname ekvc at fastsplithash@#1\endcsname#2\ekvc at stop}
% \end{macrocode}
% \end{macro}
%
@@ -1858,8 +2283,8 @@
% \begin{macrocode}
\long\def\ekvc at safehash@#1{\ekvc at err@empty at hash{}}
\long\def\ekvc at fasthash@#1\ekvc at stop{\ekvc at err@empty at hash}
-\long\def\ekvc at safesplithash@#1#2{\ekvc at err@empty at hash#2{#1}{}}
-\long\def\ekvc at fastsplithash@#1\ekvc at stop#2{\ekvc at err@empty at hash#2{#1}{}}
+\long\def\ekvc at safesplithash@#1#2{\ekvc at err@empty at hash#2{}}
+\long\def\ekvc at fastsplithash@#1\ekvc at stop#2{\ekvc at err@empty at hash#2{}}
% \end{macrocode}
% \end{macro}
%
@@ -1894,7 +2319,117 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\ekvcChange}
+% This can be used to change the defaults of an \expkvc\ defined macro. It
+% checks whether there is a set with the correct name and that the macro is
+% defined. If both is true the real work is done by |\ekvc at change|.
+% \begin{macrocode}
+\protected\long\def\ekvcChange#1%
+ {%
+ \ekvifdefinedset{\string#1}%
+ {%
+ \ekvc at ifdefined#1%
+ {\ekvc at change#1}%
+ {\ekvc at err@no at key@macro#1\@gobble}%
+ }%
+ {\ekvc at err@no at key@macro#1\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
%
+% \begin{macro}[internal]
+% {\ekvc at change,\ekvc at change@a,\ekvc at change@b,\ekvc at change@c}
+% First we need to see whether the macro is currently |\long|. For this we get
+% the meaning and will parse it. |#1| is the macro name in which we want to
+% change the defaults.
+% \begin{macrocode}
+\protected\def\ekvc at change#1%
+ {\expandafter\ekvc at change@a\meaning#1\ekv at stop#1}
+% \end{macrocode}
+% A temporary definition to get the stringified |macro:|. |##1| will be the
+% list of prefixes, we don't care for the exact contents of |##2| and |##3|.
+% \begin{macrocode}
+\def\ekvc at change@a#1%
+ {%
+ \protected\def\ekvc at change@a##1#1##2->##3\ekv at stop
+ {%
+ \ekvc at change@iflong{##1}%
+ {\ekvc at change@b{}}%
+ {\ekvc at change@b{\long}}%
+ }%
+ }
+\expandafter\ekvc at change@a\expandafter{\detokenize{macro:}}
+% \end{macrocode}
+% Next we expand the macro once to get its contents (including the current
+% default values with their markers). |#1| is either |\long| or empty, |#2| is
+% the macro.
+% \begin{macrocode}
+\protected\def\ekvc at change@b#1#2%
+ {\expandafter\ekvc at change@c\expandafter{#2{##1}}{#1}#2}
+% \end{macrocode}
+% Here we place an unbalanced closing brace after the expansion of the macro.
+% Then we just parse the \kv-list with |\ekvset|, that will exchange the
+% values behind the markers. Once those are changed we give control to
+% |\ekvc at change@d|. The |\ekvset| step might horribly fail if the user defined
+% some keys that don't behave nice. |#1| is the expansion of the macro, |#2|
+% is either |\long| or empty, |#3| is the macro, and |#4| is the \kv-list
+% containing the new defaults.
+% \begin{macrocode}
+\ekv at exparg{\protected\long\def\ekvc at change@c#1#2#3#4}%
+ {%
+ \expandafter\iffalse\expandafter{\expandafter\fi
+ \ekvset{\string#3}{#4}%
+ \ekvc at change@d{#2}{#3}%
+ #1%
+ }%
+ }
+% \end{macrocode}
+% The final step needs to put an unbalanced opening brace after |\def|. We do
+% that with the help of a temporary macro which stores everything necessary
+% for |\def| and expand an |\iffalse}\fi| construct to leave a single
+% opening brace. |#1| will be either empty or |\long| and |#2| is the macro.
+% Each of the macros defined with \expkvc\ takes exactly one parameter, so we
+% put that here as |####1|.
+% \begin{macrocode}
+\protected\def\ekvc at change@d#1#2%
+ {%
+ \def\ekvc at tmp{#1\def#2####1}%
+ \expandafter\ekvc at tmp\expandafter{\iffalse}\fi
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc at change@iflong,\ekvc at change@iflong@}
+% Checking whether a string contains the string representation of |\long| can
+% be done by gobbling everything up to the first |\long| and checking whether
+% the result is completely empty. We need a temporary macro to get the result
+% of |\string\long| inside the definitions.
+% \begin{macrocode}
+\def\ekvc at change@iflong#1%
+ {%
+ \protected\def\ekvc at change@iflong##1%
+ {\expandafter\ekv at ifempty\expandafter{\ekvc at change@iflong@##1#1}}%
+ \def\ekvc at change@iflong@##1#1{}
+ }
+\expandafter\ekvc at change@iflong\expandafter{\string\long}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcPass}
+% This macro can be used to pass a value to a key of some macro (this way
+% more complicated key codes are possible that in the end pass processed
+% values on to some macro). The implemantation is pretty straight forward.
+% \begin{macrocode}
+\long\def\ekvcPass#1#2%
+ {%
+ \ekvifdefined{\string#1}{#2}%
+ {\csname\ekv at name{\string#1}{#2}\endcsname}%
+ {\ekvc at err@unknown at key@or at macro{#1}{#2}\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
% \subsubsection{Secondary Key Types}
%
% \begin{macro}[internal]{\ekvc at p@long,\ekvc at after@ptype}
@@ -2287,7 +2822,7 @@
% \begin{macro}[internal]
% {
% \ekvc at err@toomany,\ekvc at err@value at required,\ekvc at err@missing at type,
-% \ekvc at err@already at defined
+% \ekvc at err@already at defined,\ekvc at err@no at key@macro
% }
% Boring unexpandable error messages.
% \begin{macrocode}
@@ -2322,6 +2857,8 @@
\errmessage
{expkv-cs Error: Unknown key `\unexpanded{#1}' for macro `\ekvc at set'}%
}
+\long\def\ekvc at err@no at key@macro#1%
+ {\errmessage{expkv-cs Error: \string#1 is no key=val macro}}
% \end{macrocode}
% \end{macro}
%
@@ -2343,6 +2880,8 @@
\long\def\ekvc at err@missing at hash#1{\ekvc at err{hash `#1' not found}}
\long\def\ekvc at err@empty at hash{\ekvc at err{empty hash}}
\def\ekvc at err@invalid at bool#1{\ekvc at err{invalid boolean value `#1'}}
+\long\def\ekvc at err@unknown at key@or at macro#1#2%
+ {\ekvc at err{unknown key `#2' for macro #1}}
% \end{macrocode}
% \end{macro}
%
Modified: trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex 2021-06-20 19:56:11 UTC (rev 59654)
+++ trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex 2021-06-20 19:56:27 UTC (rev 59655)
@@ -35,11 +35,12 @@
\else
\expandafter\endinput
\fi
-\def\ekvcVersion{0.10}
-\def\ekvcDate{2021-06-03}
+\def\ekvcVersion{1.0}
+\def\ekvcDate{2021-06-20}
\csname ekvc at tmp\endcsname
\expandafter\chardef\csname ekvc at tmp\endcsname=\catcode`\@
\catcode`\@=11
+\def\ekvc at tripledots{...}
\newcount\ekvc at keycount
\let\ekvc at long\ekv at empty
\let\ekvc at any@long\ekv at empty
@@ -150,7 +151,7 @@
\ekvc at keycount=0
\let\ekvc at any@long\ekv at empty
\let\ekvc at initials\ekv at empty
- \ekvparse\ekvc at err@value at required\ekvc at SetupSplitKeys@a
+ \ekvparse\ekvc at SetupSplitKeys@check at unknown\ekvc at SetupSplitKeys@a
}
\protected\def\ekvc at SetupSplitKeys@a#1%
{%
@@ -202,6 +203,33 @@
{\expandafter\ekvc at setup@splitmacro\expandafter{\the\ekvc at keycount}}%
{}%
}
+\protected\long\def\ekvc at SetupSplitKeys@check at unknown#1%
+ {%
+ \begingroup
+ \edef\ekvc at tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc at tripledots\ekvc at tmp
+ \advance\ekvc at keycount1
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc at SetupSplitKeys@unknown
+ \csname ekvc at splitmark@\the\ekvc at keycount\endcsname
+ \let\ekvc at any@long\long
+ \else
+ \ekvc at err@value at required{#1}%
+ \fi
+ }
+\protected\long\def\ekvc at SetupSplitKeys@unknown#1%
+ {%
+ \long\expandafter\def\csname\ekv at name\ekvc at set{}u\endcsname##1##2##3#1##4%
+ {##3#1{##4,##2= {##1} }}%
+ \long\expandafter\def\csname\ekv at name\ekvc at set{}uN\endcsname##1##2#1##3%
+ {##2#1{##3,##1}}%
+ \edef\ekvc at initials{\unexpanded\expandafter{\ekvc at initials#1{}}}%
+ \ekvc at helpers@needed
+ {\expandafter\ekvc at setup@splitmacro\expandafter{\the\ekvc at keycount}}%
+ {}%
+ }
\protected\def\ekvc at split@p at long
{%
\let\ekvc at long\long
@@ -208,6 +236,7 @@
\let\ekvc at any@long\long
\ekvc at SetupSplitKeys@c
}
+\def\ekvc at split@p at short{\ekvc at SetupSplitKeys@c}
\protected\def\ekvc at defarggobbler#1{\def\ekvc at tmp##1#1##2##{##1#1}}
\begingroup
\edef\ekvc at tmp
@@ -340,7 +369,7 @@
{%
\let\ekvc at any@long\ekv at empty
\let\ekvc at initials\ekv at empty
- \ekvparse\ekvc at err@value at required\ekvc at SetupHashKeys@a{#1}%
+ \ekvparse\ekvc at SetupHashKeys@check at unknown\ekvc at SetupHashKeys@a{#1}%
}
\protected\def\ekvc at SetupHashKeys@a#1%
{%
@@ -386,6 +415,35 @@
\ekvlet\ekvc at set{#1}\ekvc at tmp
\ekvc at setup@hashmacro{#1}%
}
+\protected\long\def\ekvc at SetupHashKeys@check at unknown#1%
+ {%
+ \begingroup
+ \edef\ekvc at tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc at tripledots\ekvc at tmp
+ \ekvc at SetupHashKeys@unknown
+ \let\ekvc at any@long\long
+ \else
+ \ekvc at err@value at required{#1}%
+ \fi
+ }
+\def\ekvc at SetupHashKeys@unknown#1%
+ {%
+ \protected\def\ekvc at SetupHashKeys@unknown
+ {%
+ \expandafter
+ \let\csname\ekv at name\ekvc at set{}u\endcsname\ekvc at hash@unknown at kv
+ \expandafter
+ \let\csname\ekv at name\ekvc at set{}uN\endcsname\ekvc at hash@unknown at k
+ \edef\ekvc at initials{\unexpanded\expandafter{\ekvc at initials#1{}}}%
+ \ekvc at setup@hashmacro{...}%
+ }%
+ \long\def\ekvc at hash@unknown at kv##1##2##3#1##4{##3#1{##4,##2= {##1} }}%
+ \long\def\ekvc at hash@unknown at k##1##2#1##3{##2#1{##3,##1}}%
+ }
+\expandafter\ekvc at SetupHashKeys@unknown
+ \csname ekvc at hashmark@\ekvc at tripledots\endcsname
\protected\def\ekvc at hash@p at long
{%
\let\ekvc at long\long
@@ -392,6 +450,7 @@
\let\ekvc at any@long\long
\ekvc at SetupHashKeys@c
}
+\def\ekvc at hash@p at short{\ekvc at SetupHashKeys@c}
\protected\def\ekvc at setup@hashmacro#1%
{%
\ekv at ifdefined{ekvc at fasthash@#1}{}%
@@ -432,7 +491,7 @@
\unexpanded\expandafter{\csname ekvc at hashmark@#1\endcsname}%
####2####3\unexpanded{\ekvc at stop}####4%
{%
- ####4{####1####3}{####2}%
+ ####4{####2}%
}%
\long\gdef\unexpanded\expandafter
{\csname ekvc at safesplithash@#1\endcsname}####1%
@@ -439,11 +498,12 @@
{%
\unexpanded\expandafter
{\csname ekvc@@safesplithash@#1\endcsname}%
- ####1\unexpanded{\ekvc at mark\ekvc at safe@found at hash}%
+ ####1\unexpanded{\ekvc at mark\ekvc at safe@after at hash}%
\unexpanded\expandafter
{%
\csname ekvc at hashmark@#1\endcsname{}%
- \ekvc at mark{\ekvc at err@missing at hash{#1}\ekvc at safe@no at hash}%
+ \ekvc at mark
+ {\ekvc at err@missing at hash{#1}\ekvc at safe@after at hash}%
\ekvc at stop
}%
}%
@@ -454,7 +514,7 @@
####2####3\unexpanded{\ekvc at mark}####4####5%
\unexpanded{\ekvc at stop}%
{%
- ####4{####2}####1####3\unexpanded{\ekvc at stop}%
+ ####4{####2}%
}%
}%
\ekvc at tmp
@@ -475,26 +535,17 @@
{\csname ekvc at safesplithash@#1\endcsname}%
{\ekvc at err@unknown at hash{#1}\ekvcValueSplit at recover}%
}
-\long\def\ekvcValueSplit at recover#1#2%
+\long\def\ekvcValueSplit at recover#1#2{#2{}}
+\long\def\ekvc at safe@after at hash#1#2%
{%
- #2{#1}{}%
+ #2{#1}%
}
-\long\def\ekvc at safe@found at hash#1#2\ekvc at stop#3%
- {%
- #3{#2}{#1}%
- }
-\long\def\ekvc at safe@no at hash#1#2\ekvc at mark\ekvc at safe@found at hash\ekvc at stop#3%
- {%
- #3{#2}{}%
- }
\long\def\ekvcValueSplitFast#1#2%
- {%
- \csname ekvc at fastsplithash@#1\endcsname#2\ekvc at stop
- }
+ {\csname ekvc at fastsplithash@#1\endcsname#2\ekvc at stop}
\long\def\ekvc at safehash@#1{\ekvc at err@empty at hash{}}
\long\def\ekvc at fasthash@#1\ekvc at stop{\ekvc at err@empty at hash}
-\long\def\ekvc at safesplithash@#1#2{\ekvc at err@empty at hash#2{#1}{}}
-\long\def\ekvc at fastsplithash@#1\ekvc at stop#2{\ekvc at err@empty at hash#2{#1}{}}
+\long\def\ekvc at safesplithash@#1#2{\ekvc at err@empty at hash#2{}}
+\long\def\ekvc at fastsplithash@#1\ekvc at stop#2{\ekvc at err@empty at hash#2{}}
\protected\long\def\ekvcSecondaryKeys#1#2%
{%
\edef\ekvc at set{\string#1}%
@@ -518,6 +569,56 @@
}%
{#2}%
}
+\protected\long\def\ekvcChange#1%
+ {%
+ \ekvifdefinedset{\string#1}%
+ {%
+ \ekvc at ifdefined#1%
+ {\ekvc at change#1}%
+ {\ekvc at err@no at key@macro#1\@gobble}%
+ }%
+ {\ekvc at err@no at key@macro#1\@gobble}%
+ }
+\protected\def\ekvc at change#1%
+ {\expandafter\ekvc at change@a\meaning#1\ekv at stop#1}
+\def\ekvc at change@a#1%
+ {%
+ \protected\def\ekvc at change@a##1#1##2->##3\ekv at stop
+ {%
+ \ekvc at change@iflong{##1}%
+ {\ekvc at change@b{}}%
+ {\ekvc at change@b{\long}}%
+ }%
+ }
+\expandafter\ekvc at change@a\expandafter{\detokenize{macro:}}
+\protected\def\ekvc at change@b#1#2%
+ {\expandafter\ekvc at change@c\expandafter{#2{##1}}{#1}#2}
+\ekv at exparg{\protected\long\def\ekvc at change@c#1#2#3#4}%
+ {%
+ \expandafter\iffalse\expandafter{\expandafter\fi
+ \ekvset{\string#3}{#4}%
+ \ekvc at change@d{#2}{#3}%
+ #1%
+ }%
+ }
+\protected\def\ekvc at change@d#1#2%
+ {%
+ \def\ekvc at tmp{#1\def#2####1}%
+ \expandafter\ekvc at tmp\expandafter{\iffalse}\fi
+ }
+\def\ekvc at change@iflong#1%
+ {%
+ \protected\def\ekvc at change@iflong##1%
+ {\expandafter\ekv at ifempty\expandafter{\ekvc at change@iflong@##1#1}}%
+ \def\ekvc at change@iflong@##1#1{}
+ }
+\expandafter\ekvc at change@iflong\expandafter{\string\long}
+\long\def\ekvcPass#1#2%
+ {%
+ \ekvifdefined{\string#1}{#2}%
+ {\csname\ekv at name{\string#1}{#2}\endcsname}%
+ {\ekvc at err@unknown at key@or at macro{#1}{#2}\@gobble}%
+ }
\protected\def\ekvc at p@long#1%
{%
\ekvc at ifspace{#1}%
@@ -762,11 +863,15 @@
\errmessage
{expkv-cs Error: Unknown key `\unexpanded{#1}' for macro `\ekvc at set'}%
}
+\long\def\ekvc at err@no at key@macro#1%
+ {\errmessage{expkv-cs Error: \string#1 is no key=val macro}}
\ekv at exparg{\long\def\ekvc at err#1}{\ekverr{expkv-cs}{#1}}
\long\def\ekvc at err@unknown at hash#1{\ekvc at err{unknown hash `#1'}}
\long\def\ekvc at err@missing at hash#1{\ekvc at err{hash `#1' not found}}
\long\def\ekvc at err@empty at hash{\ekvc at err{empty hash}}
\def\ekvc at err@invalid at bool#1{\ekvc at err{invalid boolean value `#1'}}
+\long\def\ekvc at err@unknown at key@or at macro#1#2%
+ {\ekvc at err{unknown key `#2' for macro #1}}
\catcode`\@=\ekvc at tmp
%%
%%
More information about the tex-live-commits
mailing list.