summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3prop.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3prop.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3prop.dtx92
1 files changed, 90 insertions, 2 deletions
diff --git a/macros/latex/contrib/l3kernel/l3prop.dtx b/macros/latex/contrib/l3kernel/l3prop.dtx
index 55d962b292..16db6a427b 100644
--- a/macros/latex/contrib/l3kernel/l3prop.dtx
+++ b/macros/latex/contrib/l3kernel/l3prop.dtx
@@ -2,7 +2,7 @@
%
%% File: l3prop.dtx
%
-% Copyright (C) 1990-2021 The LaTeX Project
+% Copyright (C) 1990-2022 The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2021-11-22}
+% \date{Released 2022-01-12}
%
% \maketitle
%
@@ -311,6 +311,21 @@
% the input stream as an \meta{integer denotation}.
% \end{function}
%
+% \begin{function}[EXP]{\prop_to_keyval:N}
+% \begin{syntax}
+% \cs{prop_to_keyval:N} \meta{property list}
+% \end{syntax}
+% Expands to the \meta{property list} in a key--value notation. Keep in mind
+% that a \meta{property list} is \emph{unordered}, while key--value interfaces
+% don't necessarily are, so this can't be used for arbitrary interfaces.
+% \begin{texnote}
+% The result is returned within the \tn{unexpanded} primitive
+% (\cs{exp_not:n}), which means that the key--value list does not expand
+% further when appearing in an \texttt{x}-type argument expansion.
+% It also needs exactly two steps of expansion.
+% \end{texnote}
+% \end{function}
+%
% \section{Modifying property lists}
%
% \begin{function}[added = 2012-05-12]
@@ -1055,6 +1070,79 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}[EXP]{\prop_to_keyval:N}
+% \begin{macro}[EXP]
+% {\@@_to_keyval_exp_after:wN, \@@_to_keyval:nn, \@@_to_keyval:nnw}
+% Each property name and value pair will be returned in the form
+% \verb*| |\marg{name}\verb*|= |\marg{value}. As one of the main use cases for
+% this macro is to pass the \meta{property list} on to a key--value parser, we
+% have to make sure that the behaviour is as good as possible. Using a space
+% before the opening brace we get the correct brace stripping behaviour for
+% most of the key--value parsers available in \LaTeX.
+% If \cs{tex_expanded:D} is available this function makes use of it, so there
+% are two different implementations here. They both start with
+% \cs{__kernel_exp_not:w} to start the expansion context to expand in two
+% steps. If the \meta{property list} is empty they just leave an empty set of
+% braces in the input stream for \cs{__kernel_exp_not:w}.
+% \begin{macrocode}
+\cs_if_exist:NTF \tex_expanded:D
+ {
+% \end{macrocode}
+% The variant using \cs{tex_expanded:D} can just iterate over the
+% \meta{property list} and remove the leading comma afterwards. Only the value
+% has to be protected in \cs{__kernel_exp_not:w} as the property name is
+% always a string. After the loop the leading comma is removed by
+% \cs{use_none:n} and afterwards \cs{__kernel_exp_not:w} eventually finds the
+% opening brace of its argument.
+% \begin{macrocode}
+ \cs_new:Npn \prop_to_keyval:N #1
+ {
+ \__kernel_exp_not:w
+ \prop_if_empty:NTF #1
+ { {} }
+ {
+ \exp_after:wN \exp_after:wN \exp_after:wN
+ {
+ \tex_expanded:D
+ {
+ \__kernel_exp_not:w { \use_none:n }
+ \prop_map_function:NN #1 \@@_to_keyval:nn
+ }
+ }
+ }
+ }
+ \cs_new:Npn \@@_to_keyval:nn #1#2
+ { , ~ {#1} =~ { \__kernel_exp_not:w {#2} } }
+ }
+% \end{macrocode}
+% The other variant will iterate over the \meta{property list} and has to
+% output the result in a group after the marker
+% \cs{@@_to_keyval_exp_after:wN}. As a result this is considerably slower than
+% the \cs{tex_expanded:D} using variant as it has to read the entire contents
+% of the \meta{property list} for each item. Since the marker is just
+% \cs{exp_after:wN} with another name, after the loop the leading comma is
+% gobbled by \cs{use_none:n}, leaving the result as the argument to
+% \cs{__kernel_exp_not:w}.
+% \begin{macrocode}
+ {
+ \cs_new:Npn \prop_to_keyval:N #1
+ {
+ \__kernel_exp_not:w
+ \prop_if_empty:NTF #1
+ { {} }
+ {
+ \prop_map_function:NN #1 \@@_to_keyval:nnw
+ \@@_to_keyval_exp_after:wN { \use_none:n }
+ }
+ }
+ \cs_new_eq:NN \@@_to_keyval_exp_after:wN \exp_after:wN
+ \cs_new:Npn \@@_to_keyval:nnw #1#2#3 \@@_to_keyval_exp_after:wN #4
+ { #3 \@@_to_keyval_exp_after:wN { #4 , ~ {#1} =~ {#2} } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[TF, tested = m3prop004]
% {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:NnN, \prop_gpop:cnN}
% Popping an item from a property list, keeping track of whether