Skip to content

Commit

Permalink
implement SplitKeyval
Browse files Browse the repository at this point in the history
  • Loading branch information
Skillmon committed May 19, 2024
1 parent bc83216 commit d8423ed
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 3 deletions.
22 changes: 22 additions & 0 deletions base/doc/usrguide.tex
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,28 @@ \subsection{Argument processors}
the input in cases where these have been included such that the standard
\TeX{} conversion of multiple spaces to a single space does not apply.

\begin{decl}
|\SplitKeyval| \arg{key-declarations}
\end{decl}
This processor splits the argument into items wrapped in braces inside |#1|
based on keys. Inside the \meta{key-declarations} the available keys and their
initial values are specified in the form \meta{key}|=|\meta{initial}. If you
omit the equals sign and initial value the |-NoValue-| marker will be used. The
order of the items in |#1| is solely dependent on the order the keys were
declared. If one of the keys is used without a value the corresponding item in
|#1| will be empty. For instance after
\begin{verbatim}
\NewDocumentCommand\foo {>{\SplitKeyval{keyA=A,keyB,keyC=C}} m}
{\FunctionOfThree#1}
\end{verbatim}
the following usages and their results would be possible:
\begin{verbatim}
\foo{keyB=b,keyA=a} ==> \FunctionOfThree{a}{b}{C}
\foo{} ==> \FunctionOfThree{A}{-NoValue-}{C}
\foo{keyC=c,keyB} ==> \FunctionOfThree{A}{}{c}
\end{verbatim}
Note that this is only useful on simple |key=value| setups with few keys.

\subsection{Body of an environment}
\label{sec:cmd:body}

Expand Down
111 changes: 108 additions & 3 deletions base/ltcmd.dtx
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
%%% From File: ltcmd.dtx
%
% \begin{macrocode}
\def\ltcmdversion{v1.2e}
\def\ltcmddate{2024-04-17}
\def\ltcmdversion{v1.2f}
\def\ltcmddate{2024-05-19}
% \end{macrocode}
%
%<*driver>
Expand Down Expand Up @@ -4179,6 +4179,93 @@
% \end{macro}
% \end{variable}
%
% \begin{macro}{\@@_split_keyval:nn}
% The |key=value| splitting processor stores all known keys and the
% corresponding arguments in form of numbered token list variables inside a
% |prop|, which is done during \cs{@@_split_keyval_setup:n}. The individual
% keys are stored in those token lists during \cs{@@_split_keyval_do:n}, and
% their values are later retrieved from a full expansion of \cs{l_@@_tmpa_tl}.
% \begin{macrocode}
\cs_new_protected:Npn \@@_split_keyval:nn #1#2
{
\group_begin:
\@@_split_keyval_setup:n {#1}
\int_compare:nNnT \l_@@_split_keyval_item_int = \c_zero_int
{ \msg_error:nn { cmd } { no-keys } {#2} }
\@@_split_keyval_do:n {#2}
\exp_args:NNNe
\group_end:
\tl_set:Nn \ProcessedArgument { \l_@@_split_keyval_args_tl }
}
% \end{macrocode}
% \begin{variable}{\l_@@_split_keyval_item_int,\l_@@_split_keyval_args_tl}
% Count the current list element during setup and collect the individual key
% value holding token lists.
% \begin{macrocode}
\int_new:N \l_@@_split_keyval_item_int
\tl_new:N \l_@@_split_keyval_args_tl
% \end{macrocode}
% \end{variable}
% \begin{macro}
% {
% \@@_split_keyval_setup:n, \@@_split_keyval_setup_k:n,
% \@@_split_keyval_setup_kv:nn, \@@_split_keyval_setup_kv:no,
% \@@_split_keyval_setup_kv:Nnn, \@@_split_keyval_setup_kv:cnn
% }
% \begin{macrocode}
\cs_new_protected:Npn \@@_split_keyval_setup:n
{
\int_zero:N \l_@@_split_keyval_item_int
\tl_clear:N \l_@@_split_keyval_args_tl
\keyval_parse:NNn \@@_split_keyval_setup_k:n \@@_split_keyval_setup_kv:nn
}
\cs_new_protected:Npn \@@_split_keyval_setup_k:n #1
{ \@@_split_keyval_setup_kv:no {#1} \c_novalue_tl }
\cs_new_protected:Npn \@@_split_keyval_setup_kv:nn
{
\int_incr:N \l_@@_split_keyval_item_int
\@@_split_keyval_setup_kv:cnn
{ l_@@_split_keyval_arg_ \int_use:N \l_@@_split_keyval_item_int _tl }
}
\cs_new_protected:Npn \@@_split_keyval_setup_kv:Nnn #1#2#3
{
\tl_clear_new:N #1
\prop_put:Nnn \l_@@_tmp_prop {#2} {#1}
\tl_set:Nn #1 {#3}
\tl_put_right:Nn \l_@@_split_keyval_args_tl { { \exp_not:o #1 } }
}
\cs_generate_variant:Nn \@@_split_keyval_setup_kv:nn { no }
\cs_generate_variant:Nn \@@_split_keyval_setup_kv:Nnn { cnn }
% \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_split_keyval_do:n}
% \begin{macrocode}
\cs_new_protected:Npn \@@_split_keyval_do:n #1
{
\tl_set:Nn \l_@@_tmpb_tl {#1}
\keyval_parse:NNn \@@_split_keyval_do_key:n \@@_split_keyval_do_pair:nn {#1}
}
\cs_new_protected:Npn \@@_split_keyval_do_key:n #1
{ \@@_split_keyval_do_pair:nn {#1} {} }
\cs_new_protected:Npn \@@_split_keyval_do_pair:nn #1#2
{
\prop_get:NnNTF \l_@@_tmp_prop {#1} \l_@@_tmpa_tl
{ \exp_after:wN \tl_set:Nn \l_@@_tmpa_tl {#2} }
{
\msg_error:nnnee { cmd } { unknown-key }
{#1}
{ \exp_not:V \l_@@_tmpb_tl }
{
\exp_last_unbraced:Ne \use_none:n
{ \prop_map_tokens:Nn \l_@@_tmp_prop { ,~ \use_i:nn } }
\prg_do_nothing:
}
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_split_argument:nnn}
% \begin{macro}{\@@_split_argument_aux:nnnn}
% \begin{macro}[EXP]{\@@_split_argument_aux:n}
Expand Down Expand Up @@ -4889,6 +4976,22 @@
at~each~occurrence~of~the~separator~'#1'~into~#2~parts.~
Too~many~separators~were~found.
}
\msg_new:nnnn { cmd } { unknown-key }
{ Unknown~key~'#1'~in~argument. }
{
LaTeX~was~asked~to~split~the~input~'#2'~as~a~key=value~list,~
and~the~encountered~key~'#1'~wasn't~defined.
\\ \\
Maybe~you~just~misspelled~it.~The~following~keys~are~defined:
\\
#3
}
\msg_new:nnnn { cmd } { no-keys }
{ No~keys~specified. }
{
LaTeX~was~asked~to~split~the~input~'#1'~as~a~key=value~list,~
but~no~keys~were~declared.
}
\msg_new:nnnn { cmd } { verbatim-nl }
{ Verbatim-like~#1~ended~by~end~of~line. }
{
Expand Down Expand Up @@ -5189,13 +5292,15 @@
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ReverseBoolean, \SplitArgument, \SplitList, \TrimSpaces}
% \begin{macro}
% {\ReverseBoolean, \SplitArgument, \SplitList, \TrimSpaces, \SplitKeyval}
% Simple copies.
% \begin{macrocode}
\cs_new_eq:NN \ReverseBoolean \@@_bool_reverse:N
\cs_new_eq:NN \SplitArgument \@@_split_argument:nnn
\cs_new_eq:NN \SplitList \@@_split_list:nn
\cs_new_eq:NN \TrimSpaces \@@_trim_spaces:n
\cs_new_eq:NN \SplitKeyval \@@_split_keyval:nn
% \end{macrocode}
% \end{macro}
%
Expand Down
9 changes: 9 additions & 0 deletions base/testfiles-ltcmd/ltcmd004.luatex.tlg
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,12 @@ TEST 31: Processor depending on other argument
|{a}{bcd;e}|1|
|{a,bcd}{e}|1|
============================================================
============================================================
TEST 32: SplitKeyval
============================================================
Defining \l__cmd_split_keyval_arg_1_tl on line ...
Defining \l__cmd_split_keyval_arg_2_tl on line ...
|{-NoValue-}{B}|
|{}{c}|
|{A}{}|
============================================================
9 changes: 9 additions & 0 deletions base/testfiles-ltcmd/ltcmd004.lvt
Original file line number Diff line number Diff line change
Expand Up @@ -518,4 +518,13 @@
\foo { a , bcd ; e } [;]
}
\TEST { SplitKeyval }
{
\DeclareDocumentCommand { \foo } { >{\SplitKeyval{a,b=B}} O{} }
{ \TYPE { \tl_to_str:n { |#1| } } }
\foo
\foo [b=c,a]
\foo [b,a=A]
}
\END
9 changes: 9 additions & 0 deletions base/testfiles-ltcmd/ltcmd004.tlg
Original file line number Diff line number Diff line change
Expand Up @@ -674,3 +674,12 @@ TEST 31: Processor depending on other argument
|{a}{bcd;e}|1|
|{a,bcd}{e}|1|
============================================================
============================================================
TEST 32: SplitKeyval
============================================================
Defining \l__cmd_split_keyval_arg_1_tl on line ...
Defining \l__cmd_split_keyval_arg_2_tl on line ...
|{-NoValue-}{B}|
|{}{c}|
|{A}{}|
============================================================
24 changes: 24 additions & 0 deletions base/testfiles-ltcmd/ltcmd005.luatex.tlg
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,30 @@ point.
Expect further (low-level) errors.
-NoValue-
+
! LaTeX cmd Error: No keys specified.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input '' as a key=value list, but no keys were
declared.
Defining \l__cmd_split_keyval_arg_1_tl on line ...
Defining \l__cmd_split_keyval_arg_2_tl on line ...
! LaTeX cmd Error: Unknown key 'c' in argument.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input 'c,d=e' as a key=value list, and the
encountered key 'c' wasn't defined.
Maybe you just misspelled it. The following keys are defined:
a, b
! LaTeX cmd Error: Unknown key 'd' in argument.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input 'c,d=e' as a key=value list, and the
encountered key 'd' wasn't defined.
Maybe you just misspelled it. The following keys are defined:
a, b
============================================================
! LaTeX cmd Error: Verbatim-like command '\testG' ended by end of line.
For immediate help type H <return>.
Expand Down
4 changes: 4 additions & 0 deletions base/testfiles-ltcmd/ltcmd005.lvt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@
\NewDocumentEnvironment { testF } { v } { \TYPE {#1} } { }
\begin{testF}+\TYPE+
\end{testF}
\NewDocumentCommand { \testG } { >{\SplitKeyval{}} m } { }
\testG{}
\NewDocumentCommand { \testH } { >{\SplitKeyval{a,b}} m } { }
\testH{c,d=e}
}
\ExplSyntaxOff
\NewDocumentCommand { \testG } { v } { \TYPE {#1} }
Expand Down
24 changes: 24 additions & 0 deletions base/testfiles-ltcmd/ltcmd005.tlg
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,30 @@ point.
Expect further (low-level) errors.
-NoValue-
+
! LaTeX cmd Error: No keys specified.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input '' as a key=value list, but no keys were
declared.
Defining \l__cmd_split_keyval_arg_1_tl on line ...
Defining \l__cmd_split_keyval_arg_2_tl on line ...
! LaTeX cmd Error: Unknown key 'c' in argument.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input 'c,d=e' as a key=value list, and the
encountered key 'c' wasn't defined.
Maybe you just misspelled it. The following keys are defined:
a, b
! LaTeX cmd Error: Unknown key 'd' in argument.
For immediate help type H <return>.
...
l. ... }
LaTeX was asked to split the input 'c,d=e' as a key=value list, and the
encountered key 'd' wasn't defined.
Maybe you just misspelled it. The following keys are defined:
a, b
============================================================
! LaTeX cmd Error: Verbatim-like command '\testG' ended by end of line.
For immediate help type H <return>.
Expand Down

0 comments on commit d8423ed

Please sign in to comment.