From 4d7993d55cbb38c06a220e7ce46c92d8a3f234b4 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 27 Feb 2020 22:05:11 +0000 Subject: expkv (27feb20) git-svn-id: svn://tug.org/texlive/trunk@53939 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/expkv/README.md | 6 +- Master/texmf-dist/doc/latex/expkv/expkv.pdf | Bin 340584 -> 356549 bytes Master/texmf-dist/source/latex/expkv/expkv.dtx | 157 ++++++++++++++++++++----- Master/texmf-dist/tex/generic/expkv/expkv.tex | 37 +++--- 4 files changed, 154 insertions(+), 46 deletions(-) diff --git a/Master/texmf-dist/doc/latex/expkv/README.md b/Master/texmf-dist/doc/latex/expkv/README.md index 854846ee33b..5700d7ef051 100644 --- a/Master/texmf-dist/doc/latex/expkv/README.md +++ b/Master/texmf-dist/doc/latex/expkv/README.md @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------- # expkv -- an expandable key=val implementation -Version 2020-02-22 v0.4 +Version 2020-02-27 v0.5a Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt @@ -29,3 +29,7 @@ not the fastest key=val implementation available. It is generic code and completely self-contained. There is a LaTeX package `expkv.sty` included to play nice on LaTeX's package loading system, but that package is not needed and does not provide more functionality than the generic code in `expkv.tex`. + +A key-defining interface that is not as rudimentary as the macros provided in +this package is contained in expkv-def: +https://github.com/Skillmon/tex_expkv-def diff --git a/Master/texmf-dist/doc/latex/expkv/expkv.pdf b/Master/texmf-dist/doc/latex/expkv/expkv.pdf index 2a26383dffa..77441304dfa 100644 Binary files a/Master/texmf-dist/doc/latex/expkv/expkv.pdf and b/Master/texmf-dist/doc/latex/expkv/expkv.pdf differ diff --git a/Master/texmf-dist/source/latex/expkv/expkv.dtx b/Master/texmf-dist/source/latex/expkv/expkv.dtx index fc889e7d429..0f0491164e6 100644 --- a/Master/texmf-dist/source/latex/expkv/expkv.dtx +++ b/Master/texmf-dist/source/latex/expkv/expkv.dtx @@ -85,7 +85,7 @@ and the derived files expkv.pdf \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,^^A \ekvset,\ekvparse,\ekvVersion,\ekvDate,\ekvifdefined,^^A \ekvifdefinedNoVal,\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak,^^A - \ekvsneak,\ekvsneakPre + \ekvsneak,\ekvsneakPre,\ekvchangeset } ,morecomment=[l]\% ,commentstyle=\color[gray]{0.4} @@ -108,16 +108,40 @@ and the derived files expkv.pdf \mbox {^^A \BeginAccSupp{ActualText=expkv}^^A + \href{https://github.com/Skillmon/tex_expkv} + {^^A + \rmfamily + \bfseries + {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A + \lower.493ex + \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A + \kern-.18em{\color{expkvred}v}^^A + }^^A + \EndAccSupp{}^^A + }^^A + } + {expkv}^^A + } +\newcommand*\expkvd + {^^A + \texorpdfstring + {^^A + \mbox + {^^A + \BeginAccSupp{ActualText=expkv-def}^^A \rmfamily \bfseries {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A \lower.493ex \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A \kern-.18em{\color{expkvred}v}^^A + {\color{expkvgrey}^^A + \kern.05em\rule[-.1ex]{.08em}{1.2ex}\kern.05em\textsc{def}^^A + }^^A \EndAccSupp{}^^A }^^A } - {expkv}^^A + {expkv-def}^^A } \newcommand\kv{\meta{key}=\meta{value}} \newcommand\key{\meta{key}} @@ -149,9 +173,7 @@ and the derived files expkv.pdf {^^A \texorpdfstring {^^A - \huge - \href{https://github.com/Skillmon/tex_expkv} - {\expkv}^^A + \huge\expkv \\[\medskipamount] \Large an expandable \kv\ implementation^^A }{expkv - an expandable = implementation}^^A @@ -199,6 +221,12 @@ and the derived files expkv.pdf % |\ProvidesFile|. % % \subsection{Setting up Keys}\label{sec:define} +% \expkv\ provides a rather simple approach to setting up keys, similar to +% \pkg{keyval}. However there is an auxiliary package named +% \href{https://github.com/Skillmon/tex_expkv-def}{\expkvd} (the files use +% \file{expkv-def} instead because \string| isn't allowed in package names by +% CTAN) which provides a more sophisticated interface, similar to well +% established packages like \pkg{pgfkeys} or \pkg{l3keys}. % % Keys in \expkv\ (as in almost all other \kv\ implementations) belong to a % \emph{set} such that different sets can contain keys of the same name. Unlike @@ -292,11 +320,11 @@ and the derived files expkv.pdf % If you need control over the necessary steps of expansion you % can use |\expanded| around it. % -% |\ekvbreak| and |\ekvsneak| and their relatives don't work in |\ekvparse|. -% It is analogue to \pkg{expl3}'s |\keyval_parse:NNn|, but not with the same -% parsing rules -- |\keyval_parse:NNn| throws an error on multiple equal -% signs per \kv\ pair and on empty \key\ names in a \kv\ pair, both of which -% |\ekvparse| doesn't deal with. +% |\ekvbreak|, |\ekvsneak|, and |\ekvchangeset| and their relatives don't work +% in |\ekvparse|. It is analogue to \pkg{expl3}'s |\keyval_parse:NNn|, but +% not with the same parsing rules -- |\keyval_parse:NNn| throws an error on +% multiple equal signs per \kv\ pair and on empty \key\ names in a \kv\ pair, +% both of which |\ekvparse| doesn't deal with. % % As a small example: % \begin{lstlisting} @@ -372,6 +400,17 @@ and the derived files expkv.pdf % \autoref{sec:sneakex}. % \end{function} % +% \begin{function}{\ekvchangeset} +% \begin{syntax} +% \cs{ekvchangeset}\marg{new-set} +% \end{syntax} +% Replaces the current set with \meta{new-set}, so for the rest of the current +% |\ekvset| call, that call behaves as if it was called with +% \texttt{\cs[no-index]{ekvset}\marg{new-set}}. Just like |\ekvsneak| this +% reads and reinserts the remainder of the current |\ekvset| macro to do its +% job. It is comparable to using \texttt{\meta{key}/.cd} in \pkg{pgfkeys}. +% \end{function} +% % \bigskip % % \begin{function}{\ekv@name,\ekv@name@set,\ekv@name@key} @@ -606,6 +645,22 @@ and the derived files expkv.pdf % \ourmacro{width=5pt}\par % \end{minipage} % +% \paragraph{The same key using \protect\expkvd} +% Using \expkvd\ we can set up the equivalent key using a \kv\ interface, after +% the following we could use |\ourmacro| in the same way as above. \expkvd\ will +% allocate and initialise |\ourdim| and define the |width| key |\protected| for +% us, so the result will be exactly the same -- with the exception that the +% default will use |\ourdim=.9\hsize\relax| instead. +% \begin{lstlisting} +% \input expkv-def % or \usepackage{expkv-def} +% \ekvdefinekeys{our} +% { +% dimen width = \ourdim, +% qdefault width = .9\hsize, +% initial width = 150pt +% } +% \end{lstlisting} +% % \subsubsection{An Expandable \kv\ Macro Using \cs[no-index]{ekvsneak}} % \label{sec:sneakex} % @@ -794,7 +849,7 @@ and the derived files expkv.pdf % \begin{lstlisting} % ! Missing \endcsname inserted. % -% \ekv( +% \! expkv Error: Set `' undefined. % \end{lstlisting} % % \subsection{License} @@ -866,8 +921,8 @@ and the derived files expkv.pdf % \begin{macro}{\ekvVersion,\ekvDate} % We're on our first input, so lets store the version and date in a macro. % \begin{macrocode} -\def\ekvVersion{0.4} -\def\ekvDate{2020-02-22} +\def\ekvVersion{0.5a} +\def\ekvDate{2020-02-27} % \end{macrocode} % \end{macro} % @@ -893,7 +948,7 @@ and the derived files expkv.pdf % \begin{macro}[internal] % { % \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo, -% \ekv@gobbletostop,\ekv@fi@gobble,\ekv@fi@secondoftwo +% \ekv@gobbleto@stop,\ekv@fi@secondoftwo,\ekv@gobble@mark % } % Since branching tests are often more versatile than |\if...\else...\fi| % constructs, we define helpers that are branching pretty fast. Also here are @@ -904,12 +959,12 @@ and the derived files expkv.pdf \long\def\@firstofone#1{#1} \long\def\@firstoftwo#1#2{#1} \long\def\@secondoftwo#1#2{#2} -\long\def\ekv@gobbletostop#1\ekv@stop{} -\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi} \long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2} +\long\def\ekv@gobbleto@stop#1\ekv@stop{} +\def\ekv@gobble@mark\ekv@mark{} % \end{macrocode} % \end{macro} -% As you can see |\ekv@gobbletostop| uses a special marker |\ekv@stop|. The +% As you can see |\ekv@gobbleto@stop| uses a special marker |\ekv@stop|. The % package will use three such markers, the one you've seen already, |\ekv@mark| % and |\ekv@nil|. Contrarily to how for instance \pkg{expl3} does things, we % don't define them, as we don't need them to have an actual meaning. This has @@ -1021,6 +1076,18 @@ and the derived files expkv.pdf \def\ekv@name@key#1{#1)} % \end{macrocode} % \end{macro} +% \begin{macro}[internal]{\ekv@undefined@set} +% We can misuse the macro name we use to expandably store the set-name in a +% single token -- since this increases performance drastically, especially for +% long set-names -- to throw a more meaningful error message in case a set isn't +% defined. The name of |\ekv@undefined@set| is a little bit misleading, as it is +% called in either case inside of |\csname|, but the result will be a control +% sequence with meaning |\relax| if the set is undefined, hence will break the +% |\csname| building the key-macro which will throw the error message. +% \begin{macrocode} +\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.} +% \end{macrocode} +% \end{macro} % \begin{macro}[internal]{\ekv@checkvalid} % We place some restrictions on the allowed names, though, namely sets and % keys are not allowed to be empty -- blanks are fine (meaning \mbox{set- @@ -1116,7 +1183,7 @@ and the derived files expkv.pdf % \begin{macrocode} \protected\def\ekv@defset#1% {% - \expandafter\edef\csname\ekv@name@set{#1}\endcsname##1% + \expandafter\edef\csname\ekv@undefined@set{#1}\endcsname##1% {\ekv@name@set{#1}\ekv@name@key{##1}}% } % \end{macrocode} @@ -1134,7 +1201,7 @@ and the derived files expkv.pdf \endgroup \long\def\ekvset##1##2% {% - \expandafter\ekv@set\csname\ekv@name@set{##1}\endcsname + \expandafter\ekv@set\csname\ekv@undefined@set{##1}\endcsname \ekv@mark##2#1\ekv@stop#1{}% } % \end{macrocode} @@ -1148,7 +1215,7 @@ and the derived files expkv.pdf % \end{macrocode} % Test whether we're at the end, if so invoke |\ekv@endset|, % \begin{macrocode} - \ekv@ifstop##2\ekv@endset\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##2\ekv@endset\ekv@mark\ekv@stop % \end{macrocode} % else go on with other commas, % \begin{macrocode} @@ -1179,7 +1246,7 @@ and the derived files expkv.pdf % \begin{macrocode} \long\def\ekv@set@other##1##2,% {% - \ekv@ifstop##2\ekv@endset@other\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##2\ekv@endset@other\ekv@mark\ekv@stop \ekv@ifhas@eq@other##2=\ekv@ifempty@B\ekv@ifempty@false \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo {\ekv@set@eq@other##1##2\ekv@stop}% @@ -1278,7 +1345,7 @@ and the derived files expkv.pdf % \begin{macrocode} \long\def\ekv@parse##1##2##3#1% {% - \ekv@ifstop##3\ekv@endparse\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##3\ekv@endparse\ekv@mark\ekv@stop \ekv@parse@other##1##2##3,\ekv@stop,% \ekv@parse##1##2\ekv@mark } @@ -1295,7 +1362,7 @@ and the derived files expkv.pdf % \begin{macrocode} \long\def\ekv@parse@other##1##2##3,% {% - \ekv@ifstop##3\ekv@endparse@other\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##3\ekv@endparse@other\ekv@mark\ekv@stop \ekv@ifhas@eq@other##3=\ekv@ifempty@B\ekv@ifempty@false \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo {\ekv@parse@eq@other##3\ekv@stop##2}% @@ -1373,12 +1440,40 @@ and the derived files expkv.pdf \ekvset,= % \end{macrocode} % -% \begin{macro}[internal]{\ekv@ifstop} -% The |\ekv@ifstop| test works similar to our if-empty test, but instead of -% using tokens which are used nowhere else (|\ekv@ifempty@A| and -% |\ekv@ifempty@B|) we use |\ekv@mark| and |\ekv@stop|. +% \begin{macro}{\ekvchangeset} +% Provide a macro that is able to switch out the current \set\ in |\ekvset|. +% This operation is slow (by comparison, it should be slightly faster than +% |\ekvsneak|), but allows for something similar to \pkg{pgfkeys}'s +% \texttt{\meta{key}/.cd} mechanism. However this operation is more expensive +% than |/.cd| as we can't just redefine some token to reflect this, but have to +% switch out the set expandably, so this works similar to the |\ekvsneak| macros +% reading and reinserting the remainder of the \kv\ list. +% \begin{macrocode} +\def\ekvchangeset#1% + {% + \expandafter\ekv@changeset\csname\ekv@undefined@set{#1}\endcsname\ekv@mark + } +% \end{macrocode} +% \end{macro} +% \begin{macro}[internal]{\ekv@changeset} +% This macro does the real change-out of |\ekvchangeset|. We introduced an +% |\ekv@mark| to not accidentally remove some braces which we have to remove +% again. +% \begin{macrocode} +\long\def\ekv@changeset#1#2\ekv@set@other#3#4\ekv@set#5% + {% + \ekv@gobble@mark#2\ekv@set@other#1#4\ekv@set#1% + } +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}[internal]{\ekv@gobbleto@markstop} +% The |\ekv@gobbleto@markstop| can be used to test for |\ekv@stop| similar to +% our if-empty test, but instead of using tokens which are used nowhere else +% (|\ekv@ifempty@A| and |\ekv@ifempty@B|) it uses |\ekv@mark| and |\ekv@stop|. % \begin{macrocode} -\long\def\ekv@ifstop#1\ekv@mark\ekv@stop{} +\long\def\ekv@gobbleto@markstop#1\ekv@mark\ekv@stop{} % \end{macrocode} % \end{macro} % @@ -1400,7 +1495,7 @@ and the derived files expkv.pdf \ekv@err@noarg \ekv@err@unknown #2{#1}% - \ekv@gobbletostop + \ekv@gobbleto@stop }% } % \end{macrocode} @@ -1452,7 +1547,7 @@ and the derived files expkv.pdf }% } \ekv@err -\def\ekv@err@{\expandafter\ekv@gobbletostop} +\def\ekv@err@{\expandafter\ekv@gobbleto@stop} % \end{macrocode} % \end{macro} % \begin{macro}[internal] @@ -1464,7 +1559,7 @@ and the derived files expkv.pdf % use those instead of the full strings. % \begin{macrocode} \long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}} -\long\def\ekv@err@common@#1#2#3#4#5(#6#7{\ekv@err{#6 (`#7', set `#5')}} +\long\def\ekv@err@common@#1`#2' #3.#4#5{\ekv@err{#4 (`#5', set `#2')}} \long\def\ekv@err@unknown#1#2{\ekv@err@common{unknown key}#1{#2}} \long\def\ekv@err@noarg #1#2{\ekv@err@common{value forbidden}#1{#2}} \long\def\ekv@err@reqval #1#2{\ekv@err@common{value required}#1{#2}} diff --git a/Master/texmf-dist/tex/generic/expkv/expkv.tex b/Master/texmf-dist/tex/generic/expkv/expkv.tex index aed5e127177..fc64fb4fac2 100644 --- a/Master/texmf-dist/tex/generic/expkv/expkv.tex +++ b/Master/texmf-dist/tex/generic/expkv/expkv.tex @@ -39,8 +39,8 @@ \else \expandafter\endinput \fi -\def\ekvVersion{0.4} -\def\ekvDate{2020-02-22} +\def\ekvVersion{0.5a} +\def\ekvDate{2020-02-27} \csname ekv@tmp\endcsname \expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@ \catcode`\@=11 @@ -48,9 +48,9 @@ \long\def\@firstofone#1{#1} \long\def\@firstoftwo#1#2{#1} \long\def\@secondoftwo#1#2{#2} -\long\def\ekv@gobbletostop#1\ekv@stop{} -\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi} \long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2} +\long\def\ekv@gobbleto@stop#1\ekv@stop{} +\def\ekv@gobble@mark\ekv@mark{} \long\def\ekv@ifempty#1% {% \ekv@ifempty@\ekv@ifempty@A#1\ekv@ifempty@B\ekv@ifempty@true @@ -110,6 +110,7 @@ \def\ekv@name#1#2{\ekv@name@set{#1}\ekv@name@key{#2}} \def\ekv@name@set#1{ekv#1(} \def\ekv@name@key#1{#1)} +\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.} \protected\def\ekv@checkvalid#1#2% {% \ekv@ifempty{#1}% @@ -181,19 +182,19 @@ } \protected\def\ekv@defset#1% {% - \expandafter\edef\csname\ekv@name@set{#1}\endcsname##1% + \expandafter\edef\csname\ekv@undefined@set{#1}\endcsname##1% {\ekv@name@set{#1}\ekv@name@key{##1}}% } \def\ekvset#1#2{% \endgroup \long\def\ekvset##1##2% {% - \expandafter\ekv@set\csname\ekv@name@set{##1}\endcsname + \expandafter\ekv@set\csname\ekv@undefined@set{##1}\endcsname \ekv@mark##2#1\ekv@stop#1{}% } \long\def\ekv@set##1##2#1% {% - \ekv@ifstop##2\ekv@endset\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##2\ekv@endset\ekv@mark\ekv@stop \ekv@set@other##1##2,\ekv@stop,% \ekv@set##1\ekv@mark } @@ -203,7 +204,7 @@ {##3} \long\def\ekv@set@other##1##2,% {% - \ekv@ifstop##2\ekv@endset@other\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##2\ekv@endset@other\ekv@mark\ekv@stop \ekv@ifhas@eq@other##2=\ekv@ifempty@B\ekv@ifempty@false \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo {\ekv@set@eq@other##1##2\ekv@stop}% @@ -256,7 +257,7 @@ } \long\def\ekv@parse##1##2##3#1% {% - \ekv@ifstop##3\ekv@endparse\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##3\ekv@endparse\ekv@mark\ekv@stop \ekv@parse@other##1##2##3,\ekv@stop,% \ekv@parse##1##2\ekv@mark } @@ -265,7 +266,7 @@ {} \long\def\ekv@parse@other##1##2##3,% {% - \ekv@ifstop##3\ekv@endparse@other\ekv@mark\ekv@stop + \ekv@gobbleto@markstop##3\ekv@endparse@other\ekv@mark\ekv@stop \ekv@ifhas@eq@other##3=\ekv@ifempty@B\ekv@ifempty@false \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo {\ekv@parse@eq@other##3\ekv@stop##2}% @@ -316,7 +317,15 @@ \catcode`\,=13 \catcode`\==13 \ekvset,= -\long\def\ekv@ifstop#1\ekv@mark\ekv@stop{} +\def\ekvchangeset#1% + {% + \expandafter\ekv@changeset\csname\ekv@undefined@set{#1}\endcsname\ekv@mark + } +\long\def\ekv@changeset#1#2\ekv@set@other#3#4\ekv@set#5% + {% + \ekv@gobble@mark#2\ekv@set@other#1#4\ekv@set#1% + } +\long\def\ekv@gobbleto@markstop#1\ekv@mark\ekv@stop{} \long\def\ekv@set@pair#1#2% {% \ekv@ifdefined@pair#2{#1}% @@ -325,7 +334,7 @@ \ekv@err@noarg \ekv@err@unknown #2{#1}% - \ekv@gobbletostop + \ekv@gobbleto@stop }% } \long\def\ekv@set@pair@#1#2\ekv@stop @@ -354,9 +363,9 @@ }% } \ekv@err -\def\ekv@err@{\expandafter\ekv@gobbletostop} +\def\ekv@err@{\expandafter\ekv@gobbleto@stop} \long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}} -\long\def\ekv@err@common@#1#2#3#4#5(#6#7{\ekv@err{#6 (`#7', set `#5')}} +\long\def\ekv@err@common@#1`#2' #3.#4#5{\ekv@err{#4 (`#5', set `#2')}} \long\def\ekv@err@unknown#1#2{\ekv@err@common{unknown key}#1{#2}} \long\def\ekv@err@noarg #1#2{\ekv@err@common{value forbidden}#1{#2}} \long\def\ekv@err@reqval #1#2{\ekv@err@common{value required}#1{#2}} -- cgit v1.2.3