summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3keys.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3keys.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3keys.dtx3649
1 files changed, 0 insertions, 3649 deletions
diff --git a/macros/latex/contrib/l3kernel/l3keys.dtx b/macros/latex/contrib/l3kernel/l3keys.dtx
deleted file mode 100644
index 5ea436176f..0000000000
--- a/macros/latex/contrib/l3kernel/l3keys.dtx
+++ /dev/null
@@ -1,3649 +0,0 @@
-% \iffalse meta-comment
-%
-%% File: l3keys.dtx
-%
-% Copyright (C) 2006-2024 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
-% license or (at your option) any later version. The latest version
-% of this license is in the file
-%
-% https://www.latex-project.org/lppl.txt
-%
-% This file is part of the "l3kernel bundle" (The Work in LPPL)
-% and all files in that bundle must be distributed together.
-%
-% -----------------------------------------------------------------------
-%
-% The development version of the bundle can be found at
-%
-% https://github.com/latex3/latex3
-%
-% for those people who are interested.
-%
-%<*driver>
-\documentclass[full,kernel]{l3doc}
-\begin{document}
- \DocInput{\jobname.dtx}
-\end{document}
-%</driver>
-% \fi
-%
-% \title{^^A
-% The \pkg{l3keys} module\\ Key--value interfaces^^A
-% }
-%
-% \author{^^A
-% The \LaTeX{} Project\thanks
-% {^^A
-% E-mail:
-% \href{mailto:latex-team@latex-project.org}
-% {latex-team@latex-project.org}^^A
-% }^^A
-% }
-%
-% \date{Released 2024-03-14}
-%
-% \maketitle
-%
-% \begin{documentation}
-%
-% The key--value method is a popular system for creating large numbers
-% of settings for controlling function or package behaviour. The
-% system normally results in input of the form
-% \begin{verbatim}
-% \MyModuleSetup{
-% key-one = value one,
-% key-two = value two
-% }
-% \end{verbatim}
-% or
-% \begin{verbatim}
-% \MyModuleMacro[
-% key-one = value one,
-% key-two = value two
-% ]{argument}
-% \end{verbatim}
-% for the user.
-%
-% The high level functions here are intended as a method to create
-% key--value controls. Keys are themselves created using a key--value
-% interface, minimising the number of functions and arguments
-% required. Each key is created by setting one or more \emph{properties}
-% of the key:
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key-one .code:n = code including parameter #1,
-% key-two .tl_set:N = \l_mymodule_store_tl
-% }
-% \end{verbatim}
-% These values can then be set as with other key--value approaches:
-% \begin{verbatim}
-% \keys_set:nn { mymodule }
-% {
-% key-one = value one,
-% key-two = value two
-% }
-% \end{verbatim}
-% As illustrated, keys are created inside a \meta{module}: a set of related
-% keys, typically those for a single module/\LaTeXe{} package. See
-% Section~\ref{sec:l3keys:subdivision} for suggestions on how to divide
-% large numbers of keys for a single module.
-%
-% At a document level, \cs{keys_set:nn} is used within a
-% document function, for example
-% \begin{verbatim}
-% \DeclareDocumentCommand \MyModuleSetup { m }
-% { \keys_set:nn { mymodule } { #1 } }
-% \DeclareDocumentCommand \MyModuleMacro { o m }
-% {
-% \group_begin:
-% \keys_set:nn { mymodule } { #1 }
-% % Main code for \MyModuleMacro
-% \group_end:
-% }
-% \end{verbatim}
-%
-% Key names may contain any tokens, as they are handled internally
-% using \cs{tl_to_str:n}. As discussed in
-% section~\ref{sec:l3keys:subdivision}, it is suggested that the character
-% |/| is reserved for sub-division of keys into different subsets.
-% Functions and variables are \emph{not} expanded when creating
-% key names, and so
-% \begin{verbatim}
-% \tl_set:Nn \l_mymodule_tmp_tl { key }
-% \keys_define:nn { mymodule }
-% {
-% \l_mymodule_tmp_tl .code:n = code
-% }
-% \end{verbatim}
-% creates a key called |\l_mymodule_tmp_tl|, and not one called
-% \texttt{key}.
-%
-% \section{Creating keys}
-%
-% \begin{function}[updated = 2017-11-14]
-% {\keys_define:nn, \keys_define:ne}
-% \begin{syntax}
-% \cs{keys_define:nn} \Arg{module} \Arg{keyval list}
-% \end{syntax}
-% Parses the \meta{keyval list} and defines the keys listed there for
-% \meta{module}. The \meta{module} name is treated as a string.
-% In practice the
-% \meta{module} should be chosen to be unique to the module in question
-% (unless deliberately adding keys to an existing module).
-%
-% The \meta{keyval list} should consist of one or more key names along
-% with an associated key \emph{property}. The properties of a key
-% determine how it acts. The individual properties are described
-% in the following text; a typical use of \cs{keys_define:nn} might
-% read
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% keyname .code:n = Some~code~using~#1,
-% keyname .value_required:n = true
-% }
-% \end{verbatim}
-% where the properties of the key begin from the |.| after the key
-% name.
-% \end{function}
-%
-% The various properties available take either no arguments at
-% all, or require one or more arguments. This is indicated in the
-% name of the property using an argument specification. In the following
-% discussion, each property is illustrated attached to an
-% arbitrary \meta{key}, which when used may be supplied with a
-% \meta{value}. All key \emph{definitions} are local.
-%
-% Key properties are applied in the reading order and so the ordering
-% is significant. Key properties which define \enquote{actions}, such
-% as |.code:n|, |.tl_set:N|, \emph{etc.}, override one another.
-% Some other properties are mutually exclusive, notably |.value_required:n|
-% and |.value_forbidden:n|, and so they replace one another. However,
-% properties covering non-exclusive behaviours may be given in any order. Thus
-% for example the following definitions are equivalent.
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% keyname .code:n = Some~code~using~#1,
-% keyname .value_required:n = true
-% }
-% \keys_define:nn { mymodule }
-% {
-% keyname .value_required:n = true,
-% keyname .code:n = Some~code~using~#1
-% }
-% \end{verbatim}
-% Note that all key properties define the key within the current \TeX{} group,
-% with an exception that the special |.undefine:| property \emph{undefines} the
-% key within the current \TeX{} group.
-%
-% \begin{function}[updated = 2013-07-08]
-% {.bool_set:N, .bool_set:c, .bool_gset:N, .bool_gset:c}
-% \begin{syntax}
-% \meta{key} .bool_set:N = \meta{boolean variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{boolean variable} to \meta{value} (which
-% must be either \enquote{\texttt{true}} or \enquote{\texttt{false}}). If the variable
-% does not exist, it will be created globally at the point that
-% the key is set up.
-% \end{function}
-%
-% \begin{function}[added = 2011-08-28, updated = 2013-07-08]
-% {
-% .bool_set_inverse:N, .bool_set_inverse:c,
-% .bool_gset_inverse:N, .bool_gset_inverse:c
-% }
-% \begin{syntax}
-% \meta{key} .bool_set_inverse:N = \meta{boolean variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{boolean variable} to the logical
-% inverse of \meta{value} (which must be either \enquote{\texttt{true}} or
-% \enquote{\texttt{false}}).
-% If the \meta{boolean variable} does not exist, it will be created globally
-% at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}{.choice:}
-% \begin{syntax}
-% \meta{key} .choice:
-% \end{syntax}
-% Sets \meta{key} to act as a choice key. Each valid choice
-% for \meta{key} must then be created, as discussed in
-% section~\ref{sec:l3keys:choice}.
-% \end{function}
-%
-% \begin{function}[added = 2011-08-21, updated = 2013-07-10]
-% {.choices:nn, .choices:Vn, .choices:en, .choices:on}
-% \begin{syntax}
-% \meta{key} .choices:nn = \Arg{choices} \Arg{code}
-% \end{syntax}
-% Sets \meta{key} to act as a choice key, and defines a series \meta{choices}
-% which are implemented using the \meta{code}. Inside \meta{code},
-% \cs{l_keys_choice_tl} will be the name of the choice made, and
-% \cs{l_keys_choice_int} will be the position of the choice in the list
-% of \meta{choices} (indexed from~$1$).
-% Choices are discussed in detail in section~\ref{sec:l3keys:choice}.
-% \end{function}
-%
-% \begin{function}[added = 2011-09-11]
-% {.clist_set:N, .clist_set:c, .clist_gset:N, .clist_gset:c}
-% \begin{syntax}
-% \meta{key} .clist_set:N = \meta{comma list variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{comma list variable} to \meta{value}.
-% Spaces around commas and empty items will be stripped.
-% If the variable does not exist, it
-% is created globally at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}[updated = 2013-07-10]{.code:n}
-% \begin{syntax}
-% \meta{key} .code:n = \Arg{code}
-% \end{syntax}
-% Stores the \meta{code} for execution when \meta{key} is used.
-% The \meta{code} can include one parameter (|#1|), which will be the
-% \meta{value} given for the \meta{key}.
-% \end{function}
-%
-% \begin{function}[added = 2020-01-11]
-% {
-% .cs_set:Np, .cs_set:cp,
-% .cs_set_protected:Np, .cs_set_protected:cp,
-% .cs_gset:Np, .cs_gset:cp,
-% .cs_gset_protected:Np, .cs_gset_protected:cp,
-% }
-% \begin{syntax}
-% \meta{key} .cs_set:Np = \meta{control sequence} \meta{arg.~spec.}
-% \end{syntax}
-% Defines \meta{key} to set \meta{control sequence} to have \meta{arg.~spec.}
-% and replacement text \meta{value}.
-% \end{function}
-%
-% \begin{function}[updated = 2013-07-09]
-% {.default:n, .default:V, .default:e, .default:o}
-% \begin{syntax}
-% \meta{key} .default:n = \Arg{default}
-% \end{syntax}
-% Creates a \meta{default} value for \meta{key}, which is used if no
-% value is given. This will be used if only the key name is given,
-% but not if a blank \meta{value} is given:
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .code:n = Hello~#1,
-% key .default:n = World
-% }
-% \keys_set:nn { mymodule }
-% {
-% key = Fred, % Prints 'Hello Fred'
-% key, % Prints 'Hello World'
-% key = , % Prints 'Hello '
-% }
-% \end{verbatim}
-% The default does not affect keys where values are required or
-% forbidden. Thus a required value cannot be supplied by a default
-% value, and giving a default value for a key which cannot take a value
-% does not trigger an error.
-%
-% When no value is given for a key as part of \cs{keys_set:nn}, the
-% \texttt{.default:n} value provides the value before key properties are
-% considered. The only exception is when the \texttt{.value_required:n}
-% property is active: a required value cannot be supplied by the default,
-% and must be explicitly given as part of \cs{keys_set:nn}.
-% \end{function}
-%
-% \begin{function}[updated = 2020-01-17]
-% {.dim_set:N, .dim_set:c, .dim_gset:N, .dim_gset:c}
-% \begin{syntax}
-% \meta{key} .dim_set:N = \meta{dimension}
-% \end{syntax}
-% Defines \meta{key} to set \meta{dimension} to \meta{value} (which
-% must a dimension expression). If the variable does not exist, it
-% is created globally at the point that the key is set up. The key will
-% require a value at point-of-use unless a default is set.
-% \end{function}
-%
-% \begin{function}[updated = 2020-01-17]
-% {.fp_set:N, .fp_set:c, .fp_gset:N, .fp_gset:c}
-% \begin{syntax}
-% \meta{key} .fp_set:N = \meta{floating point}
-% \end{syntax}
-% Defines \meta{key} to set \meta{floating point} to \meta{value}
-% (which must a floating point expression). If the variable does not exist,
-% it is created globally at the point that the key is set up. The key will
-% require a value at point-of-use unless a default is set.
-% \end{function}
-%
-% \begin{function}[added = 2013-07-14]
-% {.groups:n}
-% \begin{syntax}
-% \meta{key} .groups:n = \Arg{groups}
-% \end{syntax}
-% Defines \meta{key} as belonging to the \meta{groups} (a
-% comma-separated list). Groups
-% provide a \enquote{secondary axis} for selectively setting keys, and are
-% described in Section~\ref{sec:l3keys:selective}.
-% \begin{texnote}
-% The \meta{groups} argument is turned into a string then
-% interpreted as a comma-separated list, so group names cannot
-% contain commas nor start or end with a space character.
-% \end{texnote}
-% \end{function}
-%
-% \begin{function}[added = 2016-11-22]{.inherit:n}
-% \begin{syntax}
-% \meta{key} .inherit:n = \Arg{parents}
-% \end{syntax}
-% Specifies that the \meta{key} path should inherit the keys listed
-% as any of the \meta{parents} (a comma list), which can be a module
-% or a sub-division thereof. For example, after setting
-% \begin{verbatim}
-% \keys_define:nn { foo } { test .code:n = \tl_show:n {#1} }
-% \keys_define:nn { } { bar .inherit:n = foo }
-% \end{verbatim}
-% setting
-% \begin{verbatim}
-% \keys_set:nn { bar } { test = a }
-% \end{verbatim}
-% will be equivalent to
-% \begin{verbatim}
-% \keys_set:nn { foo } { test = a }
-% \end{verbatim}
-% Inheritance applies at point of use, not at definition, thus keys may
-% be added to the \meta{parent} after the use of \texttt{.inherit:n}
-% and will be active.
-% If more than one \meta{parent} is specified, the presence of the
-% \meta{key} will be tested for each in turn, with the first successful
-% hit taking priority.
-% \end{function}
-%
-% \begin{function}[updated = 2013-07-09]
-% {.initial:n, .initial:V, .initial:e, .initial:o}
-% \begin{syntax}
-% \meta{key} .initial:n = \Arg{value}
-% \end{syntax}
-% Initialises the \meta{key} with the \meta{value}, equivalent to
-% \begin{quote}
-% \cs{keys_set:nn} \Arg{module} \{ \meta{key} = \meta{value} \}
-% \end{quote}
-% \end{function}
-%
-% \begin{function}[updated = 2020-01-17]
-% {.int_set:N, .int_set:c, .int_gset:N, .int_gset:c}
-% \begin{syntax}
-% \meta{key} .int_set:N = \meta{integer}
-% \end{syntax}
-% Defines \meta{key} to set \meta{integer} to \meta{value} (which
-% must be an integer expression). If the variable does not exist, it
-% is created globally at the point that the key is set up. The key will
-% require a value at point-of-use unless a default is set.
-% \end{function}
-%
-% \begin{function}[updated = 2022-01-15]
-% {
-% .legacy_if_set:n, .legacy_if_gset:n,
-% .legacy_if_set_inverse:n, .legacy_if_gset_inverse:n
-% }
-% \begin{syntax}
-% \meta{key} .legacy_if_set:n = \meta{switch}
-% \end{syntax}
-% Defines \meta{key} to set legacy \cs[no-index]{if\meta{switch}} to \meta{value}
-% (which must be either \enquote{\texttt{true}} or \enquote{\texttt{false}}).
-% The \meta{switch} is the name of the switch \emph{without the leading
-% \texttt{if}}.
-%
-% The \texttt{inverse} versions will set the \meta{switch} to the logical
-% opposite of the \meta{value}.
-% \end{function}
-%
-% \begin{function}[updated = 2013-07-10]{.meta:n}
-% \begin{syntax}
-% \meta{key} .meta:n = \Arg{keyval list}
-% \end{syntax}
-% Makes \meta{key} a meta-key, which will set \meta{keyval list} in
-% one go. The \meta{keyval list} can refer as |#1| to the value given
-% at the time the \meta{key} is used (or, if no value is given, the
-% \meta{key}'s default value).
-% \end{function}
-%
-% \begin{function}[added = 2013-07-10]{.meta:nn}
-% \begin{syntax}
-% \meta{key} .meta:nn = \Arg{path} \Arg{keyval list}
-% \end{syntax}
-% Makes \meta{key} a meta-key, which will set \meta{keyval list} in
-% one go using the \meta{path} in place of the current one. The
-% \meta{keyval list} can refer as |#1| to the value given at the time
-% the \meta{key} is used (or, if no value is given, the \meta{key}'s
-% default value).
-% \end{function}
-%
-% \begin{function}[added = 2011-08-21]{.multichoice:}
-% \begin{syntax}
-% \meta{key} .multichoice:
-% \end{syntax}
-% Sets \meta{key} to act as a multiple choice key. Each valid choice
-% for \meta{key} must then be created, as discussed in
-% section~\ref{sec:l3keys:choice}.
-% \end{function}
-%
-% \begin{function}[added = 2011-08-21, updated = 2013-07-10]
-% {.multichoices:nn, .multichoices:Vn, .multichoices:en, .multichoices:on}
-% \begin{syntax}
-% \meta{key} .multichoices:nn \Arg{choices} \Arg{code}
-% \end{syntax}
-% Sets \meta{key} to act as a multiple choice key, and defines a series
-% \meta{choices}
-% which are implemented using the \meta{code}. Inside \meta{code},
-% \cs{l_keys_choice_tl} will be the name of the choice made, and
-% \cs{l_keys_choice_int} will be the position of the choice in the list
-% of \meta{choices} (indexed from~$1$).
-% Choices are discussed in detail in section~\ref{sec:l3keys:choice}.
-% \end{function}
-%
-% \begin{function}[added = 2019-05-05, updated = 2020-01-17]
-% {.muskip_set:N, .muskip_set:c, .muskip_gset:N, .muskip_gset:c}
-% \begin{syntax}
-% \meta{key} .muskip_set:N = \meta{muskip}
-% \end{syntax}
-% Defines \meta{key} to set \meta{muskip} to \meta{value} (which
-% must be a muskip expression). If the variable does not exist, it
-% is created globally at the point that the key is set up. The key will
-% require a value at point-of-use unless a default is set.
-% \end{function}
-%
-% \begin{function}[added = 2019-01-31]
-% {.prop_put:N, .prop_put:c, .prop_gput:N, .prop_gput:c}
-% \begin{syntax}
-% \meta{key} .prop_put:N = \meta{property list}
-% \end{syntax}
-% Defines \meta{key} to put the \meta{value} onto the \meta{property list}
-% stored under the \meta{key}.
-% If the variable does not exist, it
-% is created globally at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}[updated = 2020-01-17]
-% {.skip_set:N, .skip_set:c, .skip_gset:N, .skip_gset:c}
-% \begin{syntax}
-% \meta{key} .skip_set:N = \meta{skip}
-% \end{syntax}
-% Defines \meta{key} to set \meta{skip} to \meta{value} (which
-% must be a skip expression). If the variable does not exist, it
-% is created globally at the point that the key is set up. The key will
-% require a value at point-of-use unless a default is set.
-% \end{function}
-%
-% \begin{function}[added = 2021-10-30]
-% {.str_set:N, .str_set:c, .str_gset:N, .str_gset:c}
-% \begin{syntax}
-% \meta{key} .str_set:N = \meta{string variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{string variable} to \meta{value}.
-% If the variable does not exist, it is created globally
-% at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}[added = 2023-09-18]
-% {.str_set_e:N, .str_set_e:c, .str_gset_e:N, .str_gset_e:c}
-% \begin{syntax}
-% \meta{key} .str_set_e:N = \meta{string variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{string variable} to \meta{value},
-% which will be subjected to an \texttt{e}-type expansion
-% (\emph{i.e.}~using \cs{str_set:Ne}). If the variable does not exist,
-% it is created globally at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}{.tl_set:N, .tl_set:c, .tl_gset:N, .tl_gset:c}
-% \begin{syntax}
-% \meta{key} .tl_set:N = \meta{token list variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{token list variable} to \meta{value}.
-% If the variable does not exist, it is created globally
-% at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}[added = 2023-09-18]
-% {.tl_set_e:N, .tl_set_e:c, .tl_gset_e:N, .tl_gset_e:c}
-% \begin{syntax}
-% \meta{key} .tl_set_e:N = \meta{token list variable}
-% \end{syntax}
-% Defines \meta{key} to set \meta{token list variable} to \meta{value},
-% which will be subjected to an \texttt{e}-type expansion
-% (\emph{i.e.}~using \cs{tl_set:Ne}). If the variable does not exist,
-% it is created globally at the point that the key is set up.
-% \end{function}
-%
-% \begin{function}[added = 2015-07-14]{.undefine:}
-% \begin{syntax}
-% \meta{key} .undefine:
-% \end{syntax}
-% Removes the definition of the \meta{key} within the current \TeX{} group.
-% \end{function}
-%
-% \begin{function}[added = 2015-07-14]{.value_forbidden:n}
-% \begin{syntax}
-% \meta{key} .value_forbidden:n = \texttt{true\string|false}
-% \end{syntax}
-% Specifies that \meta{key} cannot receive a \meta{value} when used.
-% If a \meta{value} is given then an error will be issued. Setting
-% the property \enquote{\texttt{false}} cancels the restriction.
-% \end{function}
-%
-% \begin{function}[added = 2015-07-14]{.value_required:n}
-% \begin{syntax}
-% \meta{key} .value_required:n = \texttt{true\string|false}
-% \end{syntax}
-% Specifies that \meta{key} must receive a \meta{value} when used.
-% If a \meta{value} is not given then an error will be issued. Setting
-% the property \enquote{\texttt{false}} cancels the restriction.
-% \end{function}
-%
-% \section{Sub-dividing keys}
-% \label{sec:l3keys:subdivision}
-%
-% When creating large numbers of keys, it may be desirable to divide
-% them into several subsets for a given module. This can be achieved
-% either by adding a sub-division to the module name:
-% \begin{verbatim}
-% \keys_define:nn { mymodule / subset }
-% { key .code:n = code }
-% \end{verbatim}
-% or to the key name:
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% { subset / key .code:n = code }
-% \end{verbatim}
-% As illustrated, the best choice of token for sub-dividing keys in
-% this way is |/|. This is because of the method that is
-% used to represent keys internally. Both of the above code fragments
-% set the same key, which has full name \texttt{mymodule/subset/key}.
-%
-% As illustrated in the next section, this subdivision is
-% particularly relevant to making multiple choices.
-%
-% \section{Choice and multiple choice keys}
-% \label{sec:l3keys:choice}
-%
-% The \pkg{l3keys} system supports two types of choice key, in which a series
-% of pre-defined input values are linked to varying implementations. Choice
-% keys are usually created so that the various values are mutually-exclusive:
-% only one can apply at any one time. \enquote{Multiple} choice keys are also
-% supported: these allow a selection of values to be chosen at the same time.
-%
-% Mutually-exclusive choices are created by setting the \texttt{.choice:}
-% property:
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% { key .choice: }
-% \end{verbatim}
-% For keys which are set up as choices, the valid choices are generated
-% by creating sub-keys of the choice key. This can be carried out in
-% two ways.
-%
-% In many cases, choices execute similar code which is dependant only
-% on the name of the choice or the position of the choice in the
-% list of all possibilities. Here, the keys can share the same code, and can
-% be rapidly created using the \texttt{.choices:nn} property.
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .choices:nn =
-% { choice-a, choice-b, choice-c }
-% {
-% You~gave~choice~'\tl_use:N \l_keys_choice_tl',~
-% which~is~in~position~\int_use:N \l_keys_choice_int \c_space_tl
-% in~the~list.
-% }
-% }
-% \end{verbatim}
-% The index \cs{l_keys_choice_int} in the list of choices starts at~$1$.
-%
-% \begin{variable}{\l_keys_choice_int, \l_keys_choice_tl}
-% Inside the code block for a choice generated using \texttt{.choices:nn},
-% the variables \cs{l_keys_choice_tl} and \cs{l_keys_choice_int} are
-% available to indicate the name of the current choice, and its position in
-% the comma list. The position is indexed from~$1$. Note that, as with
-% standard key code generated using \texttt{.code:n}, the value passed to
-% the key (i.e.~the choice name) is also available as |#1|.
-% \end{variable}
-%
-% On the other hand, it is sometimes useful to create choices which
-% use entirely different code from one another. This can be achieved
-% by setting the \texttt{.choice:} property of a key, then manually
-% defining sub-keys.
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .choice:,
-% key / choice-a .code:n = code-a,
-% key / choice-b .code:n = code-b,
-% key / choice-c .code:n = code-c,
-% }
-% \end{verbatim}
-%
-% It is possible to mix the two methods, but manually-created choices
-% should \emph{not} use \cs{l_keys_choice_tl} or \cs{l_keys_choice_int}.
-% These variables do not have defined behaviour when used outside of
-% code created using \texttt{.choices:nn}
-% (\emph{i.e.}~anything might happen).
-%
-% It is possible to allow choice keys to take values which have not previously
-% been defined by adding code for the special \texttt{unknown} choice. The
-% general behavior of the \texttt{unknown} key is described in
-% Section~\ref{sec:l3keys:unknown}. A typical example in the case of a choice
-% would be to issue a custom error message:
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .choice:,
-% key / choice-a .code:n = code-a,
-% key / choice-b .code:n = code-b,
-% key / choice-c .code:n = code-c,
-% key / unknown .code:n =
-% \msg_error:nneee { mymodule } { unknown-choice }
-% { key } % Name of choice key
-% { choice-a , choice-b , choice-c } % Valid choices
-% { \exp_not:n {#1} } % Invalid choice given
-% %
-% %
-% }
-% \end{verbatim}
-%
-% Multiple choices are created in a very similar manner to mutually-exclusive
-% choices, using the properties \texttt{.multichoice:} and
-% \texttt{.multichoices:nn}. As with mutually exclusive choices, multiple
-% choices are define as sub-keys. Thus both
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .multichoices:nn =
-% { choice-a, choice-b, choice-c }
-% {
-% You~gave~choice~'\tl_use:N \l_keys_choice_tl',~
-% which~is~in~position~
-% \int_use:N \l_keys_choice_int \c_space_tl
-% in~the~list.
-% }
-% }
-% \end{verbatim}
-% and
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key .multichoice:,
-% key / choice-a .code:n = code-a,
-% key / choice-b .code:n = code-b,
-% key / choice-c .code:n = code-c,
-% }
-% \end{verbatim}
-% are valid.
-%
-% When a multiple choice key is set
-% \begin{verbatim}
-% \keys_set:nn { mymodule }
-% {
-% key = { a , b , c } % 'key' defined as a multiple choice
-% }
-% \end{verbatim}
-% each choice is applied in turn, equivalent to a \texttt{clist} mapping or
-% to applying each value individually:
-% \begin{verbatim}
-% \keys_set:nn { mymodule }
-% {
-% key = a ,
-% key = b ,
-% key = c ,
-% }
-% \end{verbatim}
-% Thus each separate choice will have passed to it the
-% \cs{l_keys_choice_tl} and \cs{l_keys_choice_int} in exactly
-% the same way as described for \texttt{.choices:nn}.
-%
-% \section{Key usage scope}
-%
-% Some keys will be used as settings which have a strictly limited scope
-% of usage. Some will be only available once, others will only be valid
-% until typesetting begins. To allow formats to support this in a structured
-% way, \pkg{l3keys} allows this information to be specified using the
-% \texttt{.usage:n} property.
-%
-% \begin{function}[added = 2022-01-10]{.usage:n}
-% \begin{syntax}
-% \meta{key} .usage:n = \meta{scope}
-% \end{syntax}
-% Defines the \meta{key} to have usage within the \meta{scope}, which
-% should be one of \texttt{general}, \texttt{preamble} or \texttt{load}.
-% \end{function}
-%
-% \begin{variable}[added = 2022-01-10]
-% {\l_keys_usage_load_prop, \l_keys_usage_preamble_prop}
-% \pkg{l3keys} itself does \emph{not} attempt to redefine keys based on the
-% usage scope. Rather, this information is made available with these
-% two property lists. These hold an entry for each module (prefix); the
-% value of each entry is a comma-separated list of the usage-restricted
-% key(s).
-% \end{variable}
-%
-% \section{Setting keys}
-%
-% \begin{function}[updated = 2017-11-14]
-% {
-% \keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:ne,
-% \keys_set:no,
-% }
-% \begin{syntax}
-% \cs{keys_set:nn} \Arg{module} \Arg{keyval list}
-% \end{syntax}
-% Parses the \meta{keyval list}, and sets those keys which are defined
-% for \meta{module}. The behaviour on finding an unknown key can be set
-% by defining a special \texttt{unknown} key: this is illustrated
-% later.
-% \end{function}
-%
-% \begin{variable}[updated = 2020-02-08]
-% {\l_keys_path_str, \l_keys_key_str, \l_keys_value_tl}
-% For each key processed, information of the full \emph{path} of the
-% key, the \emph{name} of the key and the \emph{value} of the key is
-% available within two string and one token list variables.
-% These may be used within the code of the key.
-%
-% The \emph{path} of the key is a \enquote{full} description of the key,
-% and is unique for each key. It consists of the module and full key name,
-% thus for example
-% \begin{verbatim}
-% \keys_set:nn { mymodule } { key-a = some-value }
-% \end{verbatim}
-% has path \texttt{mymodule/key-a} while
-% \begin{verbatim}
-% \keys_set:nn { mymodule } { subset / key-a = some-value }
-% \end{verbatim}
-% has path \texttt{mymodule/subset/key-a}. This information is stored in
-% \cs{l_keys_path_str}.
-%
-% The \emph{name} of the key is the part of the path after the last
-% \texttt{/}, and thus is not unique. In the preceding examples, both keys
-% have name \texttt{key-a} despite having different paths. This information
-% is stored in \cs{l_keys_key_str}.
-%
-% The \emph{value} is everything after the \texttt{=}, which may be
-% empty if no value was given. This is stored in \cs{l_keys_value_tl}, and
-% is not processed in any way by \cs{keys_set:nn}.
-% \end{variable}
-%
-% \section{Handling of unknown keys}
-% \label{sec:l3keys:unknown}
-%
-% If a key has not previously been defined (is unknown), \cs{keys_set:nn}
-% looks for a special \texttt{unknown} key for the same module, and if this is
-% not defined raises an error indicating that the key name was unknown. This
-% mechanism can be used for example to issue custom error texts. The
-% \texttt{unknown} key also supports the \texttt{.default:n} property.
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% unknown .code:n =
-% You~tried~to~set~key~'\l_keys_key_str'~to~'#1'. ,
-% unknown .default:V = \c_novalue_tl
-% }
-% \end{verbatim}
-%
-% \begin{function}[added = 2011-08-23, updated = 2019-01-29]
-% {
-% \keys_set_known:nn, \keys_set_known:nV,
-% \keys_set_known:nv, \keys_set_known:ne,
-% \keys_set_known:no,
-% \keys_set_known:nnN, \keys_set_known:nVN,
-% \keys_set_known:nvN, \keys_set_known:neN,
-% \keys_set_known:noN,
-% \keys_set_known:nnnN, \keys_set_known:nVnN,
-% \keys_set_known:nvnN, \keys_set_known:nenN,
-% \keys_set_known:nonN
-% }
-% \begin{syntax}
-% \cs{keys_set_known:nn} \Arg{module} \Arg{keyval list}
-% \cs{keys_set_known:nnN} \Arg{module} \Arg{keyval list} \meta{tl}
-% \cs{keys_set_known:nnnN} \Arg{module} \Arg{keyval list} \Arg{root} \meta{tl}
-% \end{syntax}
-% These functions set keys which are known for the \meta{module}, and
-% simply ignore other keys. The \cs{keys_set_known:nn} function parses the
-% \meta{keyval list}, and sets those keys which are defined for
-% \meta{module}. Any keys which are unknown are not processed further by
-% the parser. In addition, \cs{keys_set_known:nnN} stores the key--value
-% pairs in the \meta{tl} in comma-separated form (\emph{i.e.}~an edited
-% version of the \meta{keyval list}). When a \meta{root} is given
-% (\cs{keys_set_known:nnnN}), the key--value entries are returned
-% relative to this point in the key tree. When it is absent, only the
-% key name and value are provided. The correct list is returned by
-% nested calls.
-% \end{function}
-%
-% \section{Selective key setting}
-% \label{sec:l3keys:selective}
-%
-% In some cases it may be useful to be able to select only some keys for
-% setting, even though these keys have the same path. For example, with
-% a set of keys defined using
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key-one .code:n = { \my_func:n {#1} } ,
-% key-two .tl_set:N = \l_my_a_tl ,
-% key-three .tl_set:N = \l_my_b_tl ,
-% key-four .fp_set:N = \l_my_a_fp ,
-% }
-% \end{verbatim}
-% the use of \cs{keys_set:nn} attempts to set all four keys. However, in
-% some contexts it may only be sensible to set some keys, or to control the
-% order of setting. To do this, keys may be assigned to \emph{groups}:
-% arbitrary sets which are independent of the key tree. Thus modifying the
-% example to read
-% \begin{verbatim}
-% \keys_define:nn { mymodule }
-% {
-% key-one .code:n = { \my_func:n {#1} } ,
-% key-one .groups:n = { first } ,
-% key-two .tl_set:N = \l_my_a_tl ,
-% key-two .groups:n = { first } ,
-% key-three .tl_set:N = \l_my_b_tl ,
-% key-three .groups:n = { second } ,
-% key-four .fp_set:N = \l_my_a_fp ,
-% }
-% \end{verbatim}
-% assigns \texttt{key-one} and \texttt{key-two} to group \texttt{first},
-% \texttt{key-three} to group \texttt{second}, while \texttt{key-four} is
-% not assigned to a group.
-%
-% Selective key setting may be achieved either by selecting one or more
-% groups to be made \enquote{active}, or by marking one or more groups to
-% be ignored in key setting.
-%
-% \begin{function}[added = 2024-01-10]
-% {
-% \keys_set_exclude_groups:nnn, \keys_set_exclude_groups:nnV,
-% \keys_set_exclude_groups:nnv, \keys_set_exclude_groups:nno,
-% \keys_set_exclude_groups:nnnN, \keys_set_exclude_groups:nnVN,
-% \keys_set_exclude_groups:nnvN, \keys_set_exclude_groups:nnoN,
-% \keys_set_exclude_groups:nnnnN, \keys_set_exclude_groups:nnVnN,
-% \keys_set_exclude_groups:nnvnN, \keys_set_exclude_groups:nnonN,
-% }
-% \begin{syntax}
-% \cs{keys_set_exclude_groups:nnn} \Arg{module} \Arg{groups} \Arg{keyval list}
-% \cs{keys_set_exclude_groups:nnnN} \Arg{module} \Arg{groups} \Arg{keyval list} \meta{tl}
-% \cs{keys_set_exclude_groups:nnnnN} \Arg{module} \Arg{groups} \Arg{keyval list} \meta{root} \meta{tl}
-% \end{syntax}
-% Sets keys by excluding those in the specificied \meta{groups}.
-% The \meta{groups} are
-% given as a comma-separated list. Unknown keys are not assigned to any
-% group and are thus always set. The key--value pairs for each
-% key which is filtered out are stored in the \meta{tl} in a
-% comma-separated form (\emph{i.e.}~an edited version of the \meta{keyval
-% list}). The \cs{keys_set_exclude_groups:nnn} version skips this stage.
-%
-% Use of \cs{keys_set_exclude_groups:nnnN} can be nested, with the correct residual
-% \meta{keyval list} returned at each stage. In the version which takes
-% a \meta{root} argument, the key list is returned relative to that point
-% in the key tree. In the cases without a \meta{root} argument, only
-% the key names and values are returned.
-% \end{function}
-%
-% \begin{function}[added = 2013-07-14, updated = 2017-05-27]
-% {
-% \keys_set_groups:nnn, \keys_set_groups:nnV,
-% \keys_set_groups:nnv, \keys_set_groups:nno
-% }
-% \begin{syntax}
-% \cs{keys_set_groups:nnn} \Arg{module} \Arg{groups} \Arg{keyval list}
-% \end{syntax}
-% Activates key filtering in an \enquote{opt-in} sense: only keys assigned to
-% one or more of the \meta{groups} specified are set. The \meta{groups} are
-% given as a comma-separated list. Unknown keys are not assigned to any
-% group and are thus never set.
-% \end{function}
-%
-% \section{Digesting keys}
-%
-% \begin{function}[added = 2022-03-09]{\keys_precompile:nnN}
-% \begin{syntax}
-% \cs{keys_precompile:nnN} \Arg{module} \Arg{keyval list} \meta{tl}
-% \end{syntax}
-% Parses the \meta{keyval list} as for \cs{keys_set:nn}, placing the
-% resulting code for those which set variables or functions into the
-% \meta{tl}. Thus this function \enquote{precompiles} the keyval list into
-% a set of results which can be applied rapidly.
-% \end{function}
-%
-% \section{Utility functions for keys}
-%
-% \begin{function}[EXP, pTF, updated = 2022-01-10]
-% {\keys_if_exist:nn, \keys_if_exist:ne}
-% \begin{syntax}
-% \cs{keys_if_exist_p:nn} \Arg{module} \Arg{key} \\
-% \cs{keys_if_exist:nnTF} \Arg{module} \Arg{key} \Arg{true code} \Arg{false code}
-% \end{syntax}
-% Tests if the \meta{key} exists for \meta{module}, \emph{i.e.}~if any code
-% has been defined for \meta{key}.
-% \end{function}
-%
-% \begin{function}[added = 2011-08-21,EXP,pTF, updated = 2017-11-14]
-% {\keys_if_choice_exist:nnn}
-% \begin{syntax}
-% \cs{keys_if_choice_exist_p:nnn} \Arg{module} \Arg{key} \Arg{choice} \\
-% \cs{keys_if_choice_exist:nnnTF} \Arg{module} \Arg{key} \Arg{choice} \Arg{true code} \Arg{false code}
-% \end{syntax}
-% Tests if the \meta{choice} is defined for the \meta{key} within the
-% \meta{module}, \emph{i.e.}~if any code has been defined for
-% \meta{key}/\meta{choice}. The test is \texttt{false} if the \meta{key}
-% itself is not defined.
-% \end{function}
-%
-% \begin{function}[updated = 2015-08-09]{\keys_show:nn}
-% \begin{syntax}
-% \cs{keys_show:nn} \Arg{module} \Arg{key}
-% \end{syntax}
-% Displays in the terminal
-% the information associated to the \meta{key} for a \meta{module},
-% including the function which is used to actually implement it.
-% \end{function}
-%
-% \begin{function}[added = 2014-08-22, updated = 2015-08-09]{\keys_log:nn}
-% \begin{syntax}
-% \cs{keys_log:nn} \Arg{module} \Arg{key}
-% \end{syntax}
-% Writes in the log file the information associated to the \meta{key}
-% for a \meta{module}. See also \cs{keys_show:nn} which displays the
-% result in the terminal.
-% \end{function}
-%
-% \section{Low-level interface for parsing key--val lists}
-%
-% To re-cap from earlier, a key--value list is input of the form
-% \begin{verbatim}
-% KeyOne = ValueOne ,
-% KeyTwo = ValueTwo ,
-% KeyThree
-% \end{verbatim}
-% where each key--value pair is separated by a comma from the rest of
-% the list, and each key--value pair does not necessarily contain an
-% equals sign or a value! Processing this type of input correctly
-% requires a number of careful steps, to correctly account for
-% braces, spaces and the category codes of separators.
-%
-% While the functions described earlier are used as a high-level interface
-% for processing such input, in special circumstances you may wish to use
-% a lower-level approach.
-% The low-level parsing system converts a \meta{key--value list}
-% into \meta{keys} and associated \meta{values}. After the parsing phase
-% is completed, the resulting keys and values (or keys alone) are
-% available for further processing. This processing is not carried out by the
-% low-level parser itself, and so the parser requires the names of
-% two functions along with the key--value list. One function is
-% needed to process key--value pairs (it receives two arguments),
-% and a second function is required for keys given without any value
-% (it is called with a single argument).
-%
-% The parser does not double |#| tokens or expand any input. Active
-% tokens |=| and |,| appearing at the outer level of braces are converted
-% to category \enquote{other} (12) so that the parser does not \enquote{miss}
-% any due to category code changes. Spaces are removed from the ends
-% of the keys and values. Keys and values which are given in braces
-% have exactly one set removed (after space trimming), thus
-% \begin{verbatim}
-% key = {value here},
-% \end{verbatim}
-% and
-% \begin{verbatim}
-% key = value here,
-% \end{verbatim}
-% are treated identically.
-%
-% \begin{function}[rEXP, added=2020-12-19, updated = 2021-05-10]
-% {\keyval_parse:nnn, \keyval_parse:nnV, \keyval_parse:nnv}
-% \begin{syntax}
-% \cs{keyval_parse:nnn} \Arg{code_1} \Arg{code_2} \Arg{key--value list}
-% \end{syntax}
-% Parses the \meta{key--value list} into a series of \meta{keys} and
-% associated \meta{values}, or keys alone (if no \meta{value} was
-% given). \meta{code_1} receives each \meta{key} (with no \meta{value}) as a
-% trailing brace group, whereas \meta{code_2} is appended by two brace groups,
-% the \meta{key} and \meta{value}.
-% The order of the \meta{keys} in the \meta{key--value list}
-% is preserved. Thus
-% \begin{verbatim}
-% \keyval_parse:nnn
-% { \use_none:nn { code 1 } }
-% { \use_none:nnn { code 2 } }
-% { key1 = value1 , key2 = value2, key3 = , key4 }
-% \end{verbatim}
-% is converted into an input stream
-% \begin{verbatim}
-% \use_none:nnn { code 2 } { key1 } { value1 }
-% \use_none:nnn { code 2 } { key2 } { value2 }
-% \use_none:nnn { code 2 } { key3 } { }
-% \use_none:nn { code 1 } { key4 }
-% \end{verbatim}
-% Note that there is a difference between an empty value (an equals
-% sign followed by nothing) and a missing value (no equals sign at
-% all). Spaces are trimmed from the ends of the \meta{key} and \meta{value},
-% then one \emph{outer} set of braces is removed from the \meta{key}
-% and \meta{value} as part of the processing. If you need exactly the output
-% shown above, you'll need to either \texttt{e}-type or \texttt{x}-type expand
-% the function.
-% \begin{texnote}
-% The result of each list element is returned within \cs{exp_not:n}, which
-% means that the converted input stream does not expand further when
-% appearing in an \texttt{e}-type or \texttt{x}-type argument expansion.
-% \end{texnote}
-% \end{function}
-%
-% \begin{function}[rEXP, updated = 2021-05-10]
-% {\keyval_parse:NNn, \keyval_parse:NNV, \keyval_parse:NNv}
-% \begin{syntax}
-% \cs{keyval_parse:NNn} \meta{function_1} \meta{function_2} \Arg{key--value list}
-% \end{syntax}
-% Parses the \meta{key--value list} into a series of \meta{keys} and
-% associated \meta{values}, or keys alone (if no \meta{value} was
-% given). \meta{function_1} should take one argument, while
-% \meta{function_2} should absorb two arguments. After
-% \cs{keyval_parse:NNn} has parsed the \meta{key--value list},
-% \meta{function_1} is used to process keys given with no value
-% and \meta{function_2} is used to process keys given with a
-% value. The order of the \meta{keys} in the \meta{key--value list}
-% is preserved. Thus
-% \begin{verbatim}
-% \keyval_parse:NNn \function:n \function:nn
-% { key1 = value1 , key2 = value2, key3 = , key4 }
-% \end{verbatim}
-% is converted into an input stream
-% \begin{verbatim}
-% \function:nn { key1 } { value1 }
-% \function:nn { key2 } { value2 }
-% \function:nn { key3 } { }
-% \function:n { key4 }
-% \end{verbatim}
-% Note that there is a difference between an empty value (an equals
-% sign followed by nothing) and a missing value (no equals sign at
-% all). Spaces are trimmed from the ends of the \meta{key} and \meta{value},
-% then one \emph{outer} set of braces is removed from the \meta{key}
-% and \meta{value} as part of the processing.
-%
-% This shares the implementation of \cs{keyval_parse:nnn}, the difference is
-% only semantically.
-% \begin{texnote}
-% The result is returned within \cs{exp_not:n}, which means that the
-% converted input stream does not expand further when appearing in an
-% \texttt{e}-type or \texttt{x}-type argument expansion.
-% \end{texnote}
-% \end{function}
-%
-% \end{documentation}
-%
-% \begin{implementation}
-%
-% \section{\pkg{l3keys} implementation}
-%
-% \begin{macrocode}
-%<*package>
-% \end{macrocode}
-%
-% \subsection{Low-level interface}
-%
-% The low-level key parser's implementation is based heavily on \pkg{expkv}.
-% Compared to \pkg{keyval} it adds a number of additional \enquote{safety}
-% requirements and allows to process the parsed list of key--value pairs in a
-% variety of ways. The net result is that this code needs around one and a half
-% the amount of time as \pkg{keyval} to parse the same list of keys. To optimise
-% speed as far as reasonably practical, a number of lower-level approaches are
-% taken rather than using the higher-level \pkg{expl3} interfaces.
-%
-% \begin{macrocode}
-%<@@=keyval>
-% \end{macrocode}
-%
-% \begin{variable}{\s_@@_nil,\s_@@_mark,\s_@@_stop,\s_@@_tail}
-% \begin{macrocode}
-\scan_new:N \s_@@_nil
-\scan_new:N \s_@@_mark
-\scan_new:N \s_@@_stop
-\scan_new:N \s_@@_tail
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l__kernel_keyval_allow_blank_keys_bool}
-% The general behavior of the \pkg{l3keys} module is to throw an error on
-% blank key names. However to support the usage of \cs{keyval_parse:nnn} in
-% the \pkg{l3prop} module we allow this error to be switched off temporarily
-% and just ignore blank names.
-% \begin{macrocode}
-\bool_new:N \l__kernel_keyval_allow_blank_keys_bool
-% \end{macrocode}
-% \end{variable}
-%
-% This temporary macro will be used since some of the definitions will need an
-% active comma or equals sign. Inside of this macro |#1| will be the active
-% comma and |#2| will be the active equals sign.
-% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1#2
- {
-% \end{macrocode}
-%
-% \begin{macro}[EXP]
-% {
-% \keyval_parse:nnn, \keyval_parse:nnV, \keyval_parse:nnv,
-% \keyval_parse:NNn, \keyval_parse:NNV, \keyval_parse:NNv
-% }
-% The main function starts the first of two loops. The outer loop splits the
-% key--value list at active commas, the inner loop will do so at other commas.
-% The use of \cs{s_@@_mark} here prevents loss of braces from the key
-% argument.
-% \begin{macrocode}
- \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
- {
- \__kernel_exp_not:w \tex_expanded:D
- {
- {
- \@@_loop_active:nnw {##1} {##2}
- \s_@@_mark ##3 #1 \s_@@_tail #1
- }
- }
- }
- \cs_new_eq:NN \keyval_parse:NNn \keyval_parse:nnn
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_loop_active:nnw}
-% First a fast test for the end of the loop is done, it'll gobble everything
-% up to a \cs{s_@@_tail}. The loop ending macro will gobble everything to the
-% last comma in this definition.
-% If the end isn't reached yet, start the second loop splitting at other
-% commas, the next iteration of this first loop will be inserted by the end of
-% \cs{@@_loop_other:nnw}.
-% \begin{macrocode}
- \cs_new:Npn \@@_loop_active:nnw ##1 ##2 ##3 #1
- {
- \@@_if_recursion_tail:w ##3
- \@@_end_loop_active:w \s_@@_tail
- \@@_loop_other:nnw {##1} {##2} ##3 , \s_@@_tail ,
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_split_other:w, \@@_split_active:w}
-% These two macros allow to split at the first equals sign of category 12 or
-% 13. At the same time they also execute branching by inserting the first
-% token following \cs{s_@@_mark} that followed the equals sign. Hence they
-% also test for the presence of such an equals sign simultaneously.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_other:w ##1 = ##2 \s_@@_mark ##3
- { ##3 ##1 \s_@@_stop \s_@@_mark ##2 }
- \cs_new:Npn \@@_split_active:w ##1 #2 ##2 \s_@@_mark ##3
- { ##3 ##1 \s_@@_stop \s_@@_mark ##2 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_loop_other:nnw}
-% The second loop uses the same test for its end as the first loop, next it
-% splits at the first active equals sign using \cs{@@_split_active:w}. The
-% \cs{s_@@_nil} prevents accidental brace stripping and acts as a delimiter in
-% the next steps. First testing for an active equals sign will reduce the
-% number of necessary expansion steps for the expected average use case of
-% other equals signs and hence perform better on average.
-% \begin{macrocode}
- \cs_new:Npn \@@_loop_other:nnw ##1 ##2 ##3 ,
- {
- \@@_if_recursion_tail:w ##3
- \@@_end_loop_other:w \s_@@_tail
- \@@_split_active:w ##3 \s_@@_nil
- \s_@@_mark \@@_split_active_auxi:w
- #2 \s_@@_mark \@@_clean_up_active:w
- {##1} {##2}
- \s_@@_mark
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_split_active_auxi:w}
-% \begin{macro}[EXP]{\@@_split_active_auxii:w}
-% \begin{macro}[EXP]{\@@_split_active_auxiii:w}
-% \begin{macro}[EXP]{\@@_split_active_auxiv:w}
-% \begin{macro}[EXP]{\@@_split_active_auxv:w}
-% After \cs{@@_split_active:w} the following will only be called if there was
-% at least one active equals sign in the current key--value pair. Therefore
-% this is the execution branch for a key--value pair with an active equals
-% sign. |##1| will be everything up to the first active equals sign. First it
-% tests for other equals signs in the key name, which will eventually throw an
-% error via \cs{@@_misplaced_equal_after_active_error:w}. If none was found we
-% forward the key to \cs{@@_split_active_auxii:w}.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_active_auxi:w ##1 \s_@@_stop
- {
- \@@_split_other:w ##1 \s_@@_nil
- \s_@@_mark \@@_misplaced_equal_after_active_error:w
- = \s_@@_mark \@@_split_active_auxii:w
- }
-% \end{macrocode}
-% \cs{@@_split_active_auxii:w} gets the correct key name with a leading
-% \cs{s_@@_mark} as |##1|. It has to sanitise the remainder of the previous
-% test and trims the key name which will be forwarded to
-% \cs{@@_split_active_auxiii:w}.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_active_auxii:w
- ##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_after_active_error:w
- \s_@@_stop \s_@@_mark
- ##2 \s_@@_nil #2 \s_@@_mark \@@_clean_up_active:w
- { \@@_trim:nN {##1} \@@_split_active_auxiii:w ##2 \s_@@_nil }
-% \end{macrocode}
-% Next we test for a misplaced active equals sign in the value, if none is
-% found \cs{@@_split_active_auxiv:w} will be called.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_active_auxiii:w ##1 ##2 \s_@@_nil
- {
- \@@_split_active:w ##2 \s_@@_nil
- \s_@@_mark \@@_misplaced_equal_in_split_error:w
- #2 \s_@@_mark \@@_split_active_auxiv:w
- {##1}
- }
-% \end{macrocode}
-% This runs the last test after sanitising the remainder of the previous one.
-% This time test for a misplaced equals sign of category 12 in the value.
-% Finally the last auxiliary macro will be called.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_active_auxiv:w
- ##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_in_split_error:w
- \s_@@_stop \s_@@_mark
- {
- \@@_split_other:w ##1 \s_@@_nil
- \s_@@_mark \@@_misplaced_equal_in_split_error:w
- = \s_@@_mark \@@_split_active_auxv:w
- }
-% \end{macrocode}
-% This last macro in this execution branch sanitises the last test, trims the
-% value and passes it to \cs{@@_pair:nnnn}.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_active_auxv:w
- ##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_in_split_error:w
- \s_@@_stop \s_@@_mark
- { \@@_trim:nN { ##1 } \@@_pair:nnnn }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_clean_up_active:w}
-% The following is the branch taken if the key--value pair doesn't contain an
-% active equals sign. The remainder of that test will be cleaned up by
-% \cs{@@_clean_up_active:w} which will then split at an equals sign of
-% category other.
-% \begin{macrocode}
- \cs_new:Npn \@@_clean_up_active:w
- ##1 \s_@@_nil \s_@@_mark \@@_split_active_auxi:w \s_@@_stop \s_@@_mark
- {
- \@@_split_other:w ##1 \s_@@_nil
- \s_@@_mark \@@_split_other_auxi:w
- = \s_@@_mark \@@_clean_up_other:w
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_split_other_auxi:w}
-% \begin{macro}[EXP]{\@@_split_other_auxii:w}
-% \begin{macro}[EXP]{\@@_split_other_auxiii:w}
-% This is executed if the key--value pair doesn't contain an active equals
-% sign but at least one other. |##1| of \cs{@@_split_other_auxi:w} will
-% contain the complete key name, which is trimmed and forwarded to the next
-% auxiliary macro.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_other_auxi:w ##1 \s_@@_stop
- { \@@_trim:nN { ##1 } \@@_split_other_auxii:w }
-% \end{macrocode}
-% We know that the value doesn't contain misplaced active equals signs but we
-% have to test for others. Also we need to sanitise the previous test, which
-% is done here and not earlier to avoid superfluous argument grabbing.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_other_auxii:w
- ##1 ##2 \s_@@_nil = \s_@@_mark \@@_clean_up_other:w
- {
- \@@_split_other:w ##2 \s_@@_nil
- \s_@@_mark \@@_misplaced_equal_in_split_error:w
- = \s_@@_mark \@@_split_other_auxiii:w
- { ##1 }
- }
-% \end{macrocode}
-% \cs{@@_split_other_auxiii:w} sanitises the test for other equals signs,
-% trims the value and forwards it to \cs{@@_pair:nnnn}.
-% \begin{macrocode}
- \cs_new:Npn \@@_split_other_auxiii:w
- ##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_in_split_error:w
- \s_@@_stop \s_@@_mark
- { \@@_trim:nN { ##1 } \@@_pair:nnnn }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_clean_up_other:w}
-% \cs{@@_clean_up_other:w} is the last branch that might exist. It is called
-% if no equals sign was found, hence the only possibilities left are a blank
-% list element, which is to be skipped, or a lonely key. If it's no empty list
-% element this will trim the key name and forward it to \cs{@@_key:nn}.
-% \begin{macrocode}
- \cs_new:Npn \@@_clean_up_other:w
- ##1 \s_@@_nil \s_@@_mark \@@_split_other_auxi:w \s_@@_stop \s_@@_mark
- {
- \@@_if_blank:w ##1 \s_@@_nil \s_@@_stop \@@_blank_true:w
- \s_@@_mark \s_@@_stop
- \@@_trim:nN { ##1 } \@@_key:nn
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_misplaced_equal_after_active_error:w}
-% \begin{macro}[EXP]{\@@_misplaced_equal_in_split_error:w}
-% All these two macros do is gobble the remainder of the current other loop
-% execution and throw an error. Afterwards they have to insert the next loop
-% iteration.
-% \begin{macrocode}
- \cs_new:Npn \@@_misplaced_equal_after_active_error:w
- \s_@@_mark ##1 \s_@@_stop \s_@@_mark ##2 \s_@@_nil
- = \s_@@_mark \@@_split_active_auxii:w
- \s_@@_mark ##3 \s_@@_nil
- #2 \s_@@_mark \@@_clean_up_active:w
- {
- \msg_expandable_error:nn
- { keyval } { misplaced-equals-sign }
- \@@_loop_other:nnw
- }
- \cs_new:Npn \@@_misplaced_equal_in_split_error:w
- \s_@@_mark ##1 \s_@@_stop \s_@@_mark ##2 \s_@@_nil
- ##3 \s_@@_mark ##4 ##5
- {
- \msg_expandable_error:nn
- { keyval } { misplaced-equals-sign }
- \@@_loop_other:nnw
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_end_loop_other:w, \@@_end_loop_active:w}
-% All that's left for the parsing loops are the macros which end the
-% recursion. Both just gobble the remaining tokens of the respective loop
-% including the next recursion call. \cs{@@_end_loop_other:w} also has to
-% insert the next iteration of the active loop.
-% \begin{macrocode}
- \cs_new:Npn \@@_end_loop_other:w
- \s_@@_tail
- \@@_split_active:w
- \s_@@_mark \s_@@_tail
- \s_@@_nil \s_@@_mark
- \@@_split_active_auxi:w
- #2 \s_@@_mark \@@_clean_up_active:w
- { \@@_loop_active:nnw }
- \cs_new:Npn \@@_end_loop_active:w
- \s_@@_tail
- \@@_loop_other:nnw ##1 \s_@@_mark \s_@@_tail , \s_@@_tail ,
- { }
-% \end{macrocode}
-% \end{macro}
-%
-% The parsing loops are done, so here ends the definition of \cs{@@_tmp:w},
-% which will finally set up the macros.
-% \begin{macrocode}
- }
- \char_set_catcode_active:n { `\, }
- \char_set_catcode_active:n { `\= }
- \@@_tmp:w , =
-\group_end:
-\cs_generate_variant:Nn \keyval_parse:NNn { NNV , NNv }
-\cs_generate_variant:Nn \keyval_parse:nnn { nnV , nnv }
-% \end{macrocode}
-%
-% \begin{macro}[EXP]{\@@_pair:nnnn, \@@_key:nn}
-% These macros will be called on the parsed keys and values of the key--value
-% list. All arguments are completely trimmed. They test for blank key names
-% and call the functions passed to \cs{keyval_parse:nnn} inside of
-% \cs{exp_not:n} with the correct arguments. Afterwards they insert the next
-% iteration of the other loop.
-% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1#2
- {
- \cs_new:Npn \@@_pair:nnnn ##1 ##2 ##3 ##4
- {
- \@@_if_blank:w \s_@@_mark ##2 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
- \s_@@_mark \s_@@_stop
- #1
- \exp_not:n { ##4 {##2} {##1} }
- #2
- \@@_loop_other:nnw {##3} {##4}
- }
- \cs_new:Npn \@@_key:nn ##1 ##2
- {
- \@@_if_blank:w \s_@@_mark ##1 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
- \s_@@_mark \s_@@_stop
- #1
- \exp_not:n { ##2 {##1} }
- #2
- \@@_loop_other:nnw {##2}
- }
- }
- \@@_tmp:w { } { }
-\group_end:
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_if_empty:w,\@@_if_blank:w,\@@_if_recursion_tail:w}
-% All these tests work by gobbling tokens until a certain combination is met,
-% which makes them pretty fast. The test for a blank argument should be called
-% with an arbitrary token following the argument. Each of these utilize the
-% fact that the argument will contain a leading \cs{s_@@_mark}.
-% \begin{macrocode}
-\cs_new:Npn \@@_if_empty:w #1 \s_@@_mark \s_@@_stop { }
-\cs_new:Npn \@@_if_blank:w \s_@@_mark #1 { \@@_if_empty:w \s_@@_mark }
-\cs_new:Npn \@@_if_recursion_tail:w \s_@@_mark #1 \s_@@_tail { }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_blank_true:w,\@@_blank_key_error:w}
-% These macros will be called if the tests above didn't gobble them, they
-% execute the branching.
-% \begin{macrocode}
-\cs_new:Npn \@@_blank_true:w \s_@@_mark \s_@@_stop \@@_trim:nN #1 \@@_key:nn
- { \@@_loop_other:nnw }
-\cs_new:Npn \@@_blank_key_error:w \s_@@_mark \s_@@_stop #1 \@@_loop_other:nnw
- {
- \bool_if:NTF \l__kernel_keyval_allow_blank_keys_bool
- { #1 }
- { \msg_expandable_error:nn { keyval } { blank-key-name } }
- \@@_loop_other:nnw
- }
-% \end{macrocode}
-% \end{macro}
-%
-% Two messages for the low level parsing system.
-% \begin{macrocode}
-\msg_new:nnn { keyval } { misplaced-equals-sign }
- { Misplaced~'='~in~key-value~input~\msg_line_context: }
-\msg_new:nnn { keyval } { blank-key-name }
- { Blank~key~name~in~key-value~input~\msg_line_context: }
-\prop_gput:Nnn \g_msg_module_name_prop { keyval } { LaTeX }
-\prop_gput:Nnn \g_msg_module_type_prop { keyval } { }
-% \end{macrocode}
-%
-% \begin{macro}[EXP]{\@@_trim:nN}
-% \begin{macro}[EXP]
-% {\@@_trim_auxi:w,\@@_trim_auxii:w,\@@_trim_auxiii:w,\@@_trim_auxiv:w}
-% And an adapted version of \cs{__tl_trim_spaces:nn} which is a bit faster for
-% our use case, as it can strip the braces at the end. This is pretty much the
-% same concept, so I won't comment on it here. The speed gain by using this
-% instead of \cs{tl_trim_spaces_apply:nN} is about 10\,\% of the total time for
-% \cs{keyval_parse:NNn} with one key and one key--value pair, so I think it's
-% worth it.
-% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new:Npn \@@_trim:nN ##1
- {
- \@@_trim_auxi:w
- ##1
- \s_@@_nil
- \s_@@_mark #1 { }
- \s_@@_mark \@@_trim_auxii:w
- \@@_trim_auxiii:w
- #1 \s_@@_nil
- \@@_trim_auxiv:w
- }
- \cs_new:Npn \@@_trim_auxi:w ##1 \s_@@_mark #1 ##2 \s_@@_mark ##3
- {
- ##3
- \@@_trim_auxi:w
- \s_@@_mark
- ##2
- \s_@@_mark #1 {##1}
- }
- \cs_new:Npn \@@_trim_auxii:w \@@_trim_auxi:w \s_@@_mark \s_@@_mark ##1
- {
- \@@_trim_auxiii:w
- ##1
- }
- \cs_new:Npn \@@_trim_auxiii:w ##1 #1 \s_@@_nil ##2
- {
- ##2
- ##1 \s_@@_nil
- \@@_trim_auxiii:w
- }
-% \end{macrocode}
-% This is the one macro which differs from the original definition.
-% \begin{macrocode}
- \cs_new:Npn \@@_trim_auxiv:w
- \s_@@_mark ##1 \s_@@_nil
- \@@_trim_auxiii:w \s_@@_nil \@@_trim_auxiii:w
- ##2
- { ##2 { ##1 } }
- }
- \@@_tmp:w { ~ }
-\group_end:
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Constants and variables}
-%
-% \begin{macrocode}
-%<@@=keys>
-% \end{macrocode}
-%
-% \begin{variable}
-% {
-% \c_@@_code_root_str ,
-% \c_@@_check_root_str ,
-% \c_@@_default_root_str ,
-% \c_@@_groups_root_str ,
-% \c_@@_inherit_root_str ,
-% \c_@@_type_root_str
-% }
-% Various storage areas for the different data which make up keys.
-% \begin{macrocode}
-\str_const:Nn \c_@@_code_root_str { key~code~>~ }
-\str_const:Nn \c_@@_check_root_str { key~check~>~ }
-\str_const:Nn \c_@@_default_root_str { key~default~>~ }
-\str_const:Nn \c_@@_groups_root_str { key~groups~>~ }
-\str_const:Nn \c_@@_inherit_root_str { key~inherit~>~ }
-\str_const:Nn \c_@@_type_root_str { key~type~>~ }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_@@_props_root_str}
-% The prefix for storing properties.
-% \begin{macrocode}
-\str_const:Nn \c_@@_props_root_str { key~prop~>~ }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_keys_choice_int, \l_keys_choice_tl}
-% Publicly accessible data on which choice is being used when several
-% are generated as a set.
-% \begin{macrocode}
-\int_new:N \l_keys_choice_int
-\tl_new:N \l_keys_choice_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_groups_clist}
-% Used for storing and recovering the list of groups which apply to a key:
-% set as a comma list but at one point we have to use this for a token
-% list recovery.
-% \begin{macrocode}
-\clist_new:N \l_@@_groups_clist
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_inherit_clist}
-% For normalisation.
-% \begin{macrocode}
-\clist_new:N \l_@@_inherit_clist
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_keys_key_str}
-% The name of a key itself: needed when setting keys.
-% \begin{macrocode}
-\str_new:N \l_keys_key_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}[deprecated]{\l_keys_key_tl}
-% The |tl| version is deprecated but has to be handled manually.
-% \begin{macrocode}
-\tl_new:N \l_keys_key_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_module_str}
-% The module for an entire set of keys.
-% \begin{macrocode}
-\str_new:N \l_@@_module_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_no_value_bool}
-% A marker is needed internally to show if only a key or a key plus a
-% value was seen: this is recorded here.
-% \begin{macrocode}
-\bool_new:N \l_@@_no_value_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_only_known_bool}
-% Used to track if only \enquote{known} keys are being set.
-% \begin{macrocode}
-\bool_new:N \l_@@_only_known_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_keys_path_str}
-% The \enquote{path} of the current key is stored here: this is
-% available to the programmer and so is public.
-% \begin{macrocode}
-\str_new:N \l_keys_path_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}[deprecated]{\l_keys_path_tl}
-% The older version is deprecated but has to be handled manually.
-% \begin{macrocode}
-\tl_new:N \l_keys_path_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_inherit_str}
-% \begin{macrocode}
-\str_new:N \l_@@_inherit_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_relative_tl}
-% The relative path for passing keys back to the user. As this can
-% be explicitly no-value, it must be a token list.
-% \begin{macrocode}
-\tl_new:N \l_@@_relative_tl
-\tl_set:Nn \l_@@_relative_tl { \q_@@_no_value }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_property_str}
-% The \enquote{property} begin set for a key at definition time is
-% stored here.
-% \begin{macrocode}
-\str_new:N \l_@@_property_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_selective_bool, \l_@@_filtered_bool}
-% Two booleans for using key groups: one to indicate that \enquote{selective}
-% setting is active, a second to specify which type (\enquote{opt-in}
-% or \enquote{opt-out}).
-% \begin{macrocode}
-\bool_new:N \l_@@_selective_bool
-\bool_new:N \l_@@_filtered_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_selective_seq}
-% The list of key groups being filtered in or out during selective setting.
-% \begin{macrocode}
-\seq_new:N \l_@@_selective_seq
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_unused_clist}
-% Used when setting only some keys to store those left over.
-% \begin{macrocode}
-\clist_new:N \l_@@_unused_clist
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_keys_value_tl}
-% The value given for a key: may be empty if no value was given.
-% \begin{macrocode}
-\tl_new:N \l_keys_value_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_tmp_bool, \l_@@_tmpa_tl, \l_@@_tmpb_tl}
-% Scratch space.
-% \begin{macrocode}
-\bool_new:N \l_@@_tmp_bool
-\tl_new:N \l_@@_tmpa_tl
-\tl_new:N \l_@@_tmpb_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_precompile_bool, \l_@@_precompile_tl}
-% For digesting keys.
-% \begin{macrocode}
-\bool_new:N \l_@@_precompile_bool
-\tl_new:N \l_@@_precompile_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_keys_usage_load_prop, \l_keys_usage_preamble_prop}
-% Global data for document-level information.
-% \begin{macrocode}
-\prop_new:N \l_keys_usage_load_prop
-\prop_new:N \l_keys_usage_preamble_prop
-% \end{macrocode}
-% \end{variable}
-%
-% \subsubsection{Internal auxiliaries}
-%
-% \begin{variable}{\s_@@_nil,\s_@@_mark,\s_@@_stop}
-% Internal scan marks.
-% \begin{macrocode}
-\scan_new:N \s_@@_nil
-\scan_new:N \s_@@_mark
-\scan_new:N \s_@@_stop
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\q_@@_no_value}
-% Internal quarks.
-% \begin{macrocode}
-\quark_new:N \q_@@_no_value
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[pTF]{\@@_quark_if_no_value:N}
-% Branching quark conditional.
-% \begin{macrocode}
-\__kernel_quark_new_conditional:Nn \@@_quark_if_no_value:N { TF }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_precompile:n}
-% An auxiliary to allow cleaner showing of code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_precompile:n #1
- {
- \bool_if:NTF \l_@@_precompile_bool
- { \tl_put_right:Nn \l_@@_precompile_tl }
- { \use:n }
- {#1}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_cs_undefine:c}
-% Local version of \cs{cs_undefine:c} to avoid sprinkling
-% \cs{tex_undefined:D} everywhere.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_cs_undefine:c #1
- {
- \if_cs_exist:w #1 \cs_end:
- \else:
- \use_i:nnnn
- \fi:
- \cs_set_eq:cN {#1} \tex_undefined:D
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{The key defining mechanism}
-%
-% \begin{macro}{\keys_define:nn, \keys_define:ne, \keys_define:nx}
-% \begin{macro}{\@@_define:nnn, \@@_define:onn}
-% The public function for definitions is just a wrapper for the lower
-% level mechanism, more or less. The outer function is designed to
-% keep a track of the current module, to allow safe nesting. The module is set
-% removing any leading |/| (which is not needed here).
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_define:nn
- { \@@_define:onn \l_@@_module_str }
-\cs_generate_variant:Nn \keys_define:nn { ne , nx }
-\cs_new_protected:Npn \@@_define:nnn #1#2#3
- {
- \str_set:Ne \l_@@_module_str { \@@_trim_spaces:n {#2} }
- \keyval_parse:NNn \@@_define:n \@@_define:nn {#3}
- \str_set:Nn \l_@@_module_str {#1}
- }
-\cs_generate_variant:Nn \@@_define:nnn { o }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_define:n}
-% \begin{macro}{\@@_define:nn}
-% \begin{macro}{\@@_define_aux:nn}
-% The outer functions here record whether a value was given and then
-% converge on a common internal mechanism. There is first a search for
-% a property in the current key name, then a check to make sure it is
-% known before the code hands off to the next step.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_define:n #1
- {
- \bool_set_true:N \l_@@_no_value_bool
- \@@_define_aux:nn {#1} { }
- }
-\cs_new_protected:Npn \@@_define:nn #1#2
- {
- \bool_set_false:N \l_@@_no_value_bool
- \@@_define_aux:nn {#1} {#2}
- }
-\cs_new_protected:Npn \@@_define_aux:nn #1#2
- {
- \@@_property_find:n {#1}
- \cs_if_exist:cTF { \c_@@_props_root_str \l_@@_property_str }
- { \@@_define_code:n {#2} }
- {
- \str_if_empty:NF \l_@@_property_str
- {
- \msg_error:nnee { keys } { property-unknown }
- \l_@@_property_str \l_keys_path_str
- }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_property_find:n}
-% \begin{macro}[EXP]{\@@_property_find_auxi:w}
-% \begin{macro}{\@@_property_find_auxii:w}
-% \begin{macro}[EXP]
-% {
-% \@@_property_find_auxiii:w ,
-% \@@_property_find_auxiv:w
-% }
-% \begin{macro}{\@@_property_find_err:w}
-% Searching for a property means finding the last |.| in the input,
-% and storing the text before and after it. Everything is first turned into
-% strings, so there is no problem using \cs{cs_set_nopar:Npe} instead of
-% \cs{str_set:Ne} to set \cs{l_keys_path_str}. To gain further speed, brace
-% tricks are used and \cs{@@_property_find_auxiv:w} is defined as expandable.
-% Since spaces will already be trimmed from the module we can omit it from the
-% argument to \cs{@@_trim_spaces:n}.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_property_find:n #1
- {
- \exp_after:wN \@@_property_find_auxi:w \tl_to_str:n {#1}
- \s_@@_nil \@@_property_find_auxii:w
- . \s_@@_nil \@@_property_find_err:w
- }
-\cs_new:Npn \@@_property_find_auxi:w #1 . #2 \s_@@_nil #3
- {
- #3 #1 \s_@@_mark #2 \s_@@_nil #3
- }
-\cs_new_protected:Npn \@@_property_find_auxii:w
- #1 \s_@@_mark #2 \s_@@_nil \@@_property_find_auxii:w . \s_@@_nil
- \@@_property_find_err:w
- {
- \cs_set_nopar:Npe \l_keys_path_str
- {
- \str_if_empty:NF \l_@@_module_str { \l_@@_module_str / }
- \exp_after:wN \@@_trim_spaces:n \tex_expanded:D {{
- #1
- \if_false: }}} \fi:
- \@@_property_find_auxi:w #2 \s_@@_nil \@@_property_find_auxiii:w
- . \s_@@_nil \@@_property_find_auxiv:w
- }
-\cs_new:Npn \@@_property_find_auxiii:w #1 \s_@@_mark #2 . #3 \s_@@_nil #4
- {
- . #1 #4 #2 \s_@@_mark #3 \s_@@_nil #4
- }
-\cs_new:Npn \@@_property_find_auxiv:w
- #1 \s_@@_nil \@@_property_find_auxiii:w
- \s_@@_mark \s_@@_nil \@@_property_find_auxiv:w
- {
- \if_false: {{{ \fi: }}}
- \cs_set_nopar:Npe \l_@@_property_str { . #1 }
- \tl_set_eq:NN \l_keys_path_tl \l_keys_path_str
- }
-\cs_new_protected:Npn \@@_property_find_err:w
- #1 \s_@@_nil #2 \@@_property_find_err:w
- {
- \str_clear:N \l_@@_property_str
- \msg_error:nnn { keys } { no-property } {#1}
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_define_code:n}
-% \begin{macro}[EXP]{\@@_define_code:w}
-% Two possible cases. If there is a value for the key, then just use
-% the function. If not, then a check to make sure there is no need for
-% a value with the property. If there should be one then complain,
-% otherwise execute it. There is no need to check for a |:| as if it
-% was missing the earlier tests would have failed.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_define_code:n #1
- {
- \bool_if:NTF \l_@@_no_value_bool
- {
- \exp_after:wN \@@_define_code:w
- \l_@@_property_str \s_@@_stop
- { \use:c { \c_@@_props_root_str \l_@@_property_str } }
- {
- \msg_error:nnee { keys } { property-requires-value }
- \l_@@_property_str \l_keys_path_str
- }
- }
- { \use:c { \c_@@_props_root_str \l_@@_property_str } {#1} }
- }
-\exp_last_unbraced:NNNNo
- \cs_new:Npn \@@_define_code:w #1 \c_colon_str #2 \s_@@_stop
- { \tl_if_empty:nTF {#2} }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Turning properties into actions}
-%
-% \begin{macro}
-% {
-% \@@_bool_set:Nn, \@@_bool_set:cn,
-% \@@_bool_set_inverse:Nn, \@@_bool_set_inverse:cn
-% }
-% \begin{macro}{\@@_bool_set:Nnnn}
-% Boolean keys are really just choices, but all done by hand. The
-% second argument here is the scope: either empty or \texttt{ g } for
-% global.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_bool_set:Nn #1#2
- { \@@_bool_set:Nnnn #1 {#2} { true } { false } }
-\cs_generate_variant:Nn \@@_bool_set:Nn { c }
-\cs_new_protected:Npn \@@_bool_set_inverse:Nn #1#2
- { \@@_bool_set:Nnnn #1 {#2} { false } { true } }
-\cs_generate_variant:Nn \@@_bool_set_inverse:Nn { c }
-\cs_new_protected:Npn \@@_bool_set:Nnnn #1#2#3#4
- {
- \bool_if_exist:NF #1 { \bool_new:N #1 }
- \@@_choice_make:
- \@@_cmd_set:ne { \l_keys_path_str / true }
- { \exp_not:c { bool_ #2 set_ #3 :N } \exp_not:N #1 }
- \@@_cmd_set:ne { \l_keys_path_str / false }
- { \exp_not:c { bool_ #2 set_ #4 :N } \exp_not:N #1 }
- \@@_cmd_set_direct:nn { \l_keys_path_str / unknown }
- {
- \msg_error:nne { keys } { boolean-values-only }
- \l_keys_path_str
- }
- \@@_default_set:n { true }
- }
-\cs_generate_variant:Nn \@@_bool_set:Nn { c }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_choice_make:, \@@_multichoice_make:}
-% \begin{macro}{\@@_choice_make:N}
-% \begin{macro}{\@@_choice_make_aux:N}
-% To make a choice from a key, two steps: set the code, and set the
-% unknown key. As multichoices and choices are essentially the same bar one
-% function, the code is given together.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_choice_make:
- { \@@_choice_make:N \@@_choice_find:n }
-\cs_new_protected:Npn \@@_multichoice_make:
- { \@@_choice_make:N \@@_multichoice_find:n }
-\cs_new_protected:Npn \@@_choice_make:N #1
- {
- \cs_if_exist:cTF
- { \c_@@_type_root_str \@@_parent:o \l_keys_path_str }
- {
- \str_if_eq:vnTF
- { \c_@@_type_root_str \@@_parent:o \l_keys_path_str }
- { choice }
- {
- \msg_error:nnee { keys } { nested-choice-key }
- \l_keys_path_tl { \@@_parent:o \l_keys_path_str }
- }
- { \@@_choice_make_aux:N #1 }
- }
- { \@@_choice_make_aux:N #1 }
- }
-\cs_new_protected:Npn \@@_choice_make_aux:N #1
- {
- \cs_set_nopar:cpn { \c_@@_type_root_str \l_keys_path_str }
- { choice }
- \@@_cmd_set_direct:nn \l_keys_path_str { #1 {##1} }
- \@@_cmd_set_direct:nn { \l_keys_path_str / unknown }
- {
- \msg_error:nnee { keys } { choice-unknown }
- \l_keys_path_str {##1}
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_choices_make:nn, \@@_multichoices_make:nn}
-% \begin{macro}{\@@_choices_make:Nnn}
-% Auto-generating choices means setting up the root key as a choice, then
-% defining each choice in turn.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_choices_make:nn
- { \@@_choices_make:Nnn \@@_choice_make: }
-\cs_new_protected:Npn \@@_multichoices_make:nn
- { \@@_choices_make:Nnn \@@_multichoice_make: }
-\cs_new_protected:Npn \@@_choices_make:Nnn #1#2#3
- {
- #1
- \int_zero:N \l_keys_choice_int
- \clist_map_inline:nn {#2}
- {
- \int_incr:N \l_keys_choice_int
- \@@_cmd_set:ne
- { \l_keys_path_str / \@@_trim_spaces:n {##1} }
- {
- \tl_set:Nn \exp_not:N \l_keys_choice_tl {##1}
- \int_set:Nn \exp_not:N \l_keys_choice_int
- { \int_use:N \l_keys_choice_int }
- \exp_not:n {#3}
- }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% \@@_cmd_set:nn, \@@_cmd_set:Vn, \@@_cmd_set:ne, \@@_cmd_set:Vo,
-% \@@_cmd_set_direct:nn
-% }
-% Setting the code for a key first logs if appropriate that we are
-% defining a new key, then saves the code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_cmd_set:nn #1#2
- { \@@_cmd_set_direct:nn {#1} { \@@_precompile:n {#2} } }
-\cs_generate_variant:Nn \@@_cmd_set:nn { ne , Vn , Vo }
-\cs_new_protected:Npn \@@_cmd_set_direct:nn #1#2
- { \cs_set_protected:cpn { \c_@@_code_root_str #1 } ##1 {#2} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_cs_set:NNpn, \@@_cs_set:Ncpn}
-% Creating control sequences is a bit more tricky than other cases as
-% we need to pick up the |p| argument. To make the internals look clearer,
-% the trailing |n| argument here is just for appearance.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_cs_set:NNpn #1#2#3#
- {
- \cs_set_protected:cpe { \c_@@_code_root_str \l_keys_path_str } ##1
- {
- \@@_precompile:n
- { #1 \exp_not:N #2 \exp_not:n {#3} {##1} }
- }
- \use_none:n
- }
-\cs_generate_variant:Nn \@@_cs_set:NNpn { Nc }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_default_set:n}
-% Setting a default value is easy. These are stored using \cs{cs_set_nopar:cpe} as this
-% avoids any worries about whether a token list exists.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_default_set:n #1
- {
- \tl_if_empty:nTF {#1}
- {
- \@@_cs_undefine:c
- { \c_@@_default_root_str \l_keys_path_str }
- }
- {
- \cs_set_nopar:cpe
- { \c_@@_default_root_str \l_keys_path_str }
- { \exp_not:n {#1} }
- \@@_value_requirement:nn { required } { false }
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_groups_set:n}
-% Assigning a key to one or more groups uses comma lists. As the list of
-% groups only exists if there is anything to do, the setting is done using
-% a scratch list. For the usual grouping reasons we use the low-level
-% approach to undefining a list. We also use the low-level approach for
-% the other case to avoid tripping up the |check-declarations| code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_groups_set:n #1
- {
- \clist_set:Ne \l_@@_groups_clist { \tl_to_str:n {#1} }
- \clist_if_empty:NTF \l_@@_groups_clist
- {
- \@@_cs_undefine:c
- { \c_@@_groups_root_str \l_keys_path_str }
- }
- {
- \cs_set_eq:cN { \c_@@_groups_root_str \l_keys_path_str }
- \l_@@_groups_clist
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_inherit:n}
-% Inheritance means ignoring anything already said about the key:
-% zap the lot and set up.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_inherit:n #1
- {
- \@@_undefine:
- \clist_set:Nn \l_@@_inherit_clist {#1}
- \cs_set_eq:cN { \c_@@_inherit_root_str \l_keys_path_str }
- \l_@@_inherit_clist
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_initialise:n}
-% A set up for initialisation: just run the code if it exists.
-% We need to set the key string here, using the deprecated \texttt{tl}
-% as a piece of scratch space.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_initialise:n #1
- {
- \cs_if_exist:cTF
- { \c_@@_inherit_root_str \@@_parent:o \l_keys_path_str }
- { \@@_execute_inherit: }
- {
- \str_clear:N \l_@@_inherit_str
- \cs_if_exist:cT { \c_@@_code_root_str \l_keys_path_str }
- {
- \exp_after:wN \@@_find_key_module:wNN
- \l_keys_path_str \s_@@_stop
- \l_keys_key_tl \l_keys_key_str
- \tl_set_eq:NN \l_keys_key_tl \l_keys_key_str
- \tl_set:Nn \l_keys_value_tl {#1}
- \@@_execute:no \l_keys_path_str \l_keys_value_tl
- }
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_legacy_if_set:nn, \@@_legacy_if_inverse:nn}
-% \begin{macro}{\@@_legacy_if_inverse:nnnn}
-% Much the same as \pkg{expl3} booleans, except we assume that the switch
-% exists.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_legacy_if_set:nn #1#2
- { \@@_legacy_if_set:nnnn {#1} {#2} { true } { false } }
-\cs_new_protected:Npn \@@_legacy_if_set_inverse:nn #1#2
- { \@@_legacy_if_set:nnnn {#1} {#2} { false } { true } }
-\cs_new_protected:Npn \@@_legacy_if_set:nnnn #1#2#3#4
- {
- \@@_choice_make:
- \@@_cmd_set:ne { \l_keys_path_str / true }
- { \exp_not:c { legacy_if_#2 set_ #3 :n } { \exp_not:n {#1} } }
- \@@_cmd_set:ne { \l_keys_path_str / false }
- { \exp_not:c { legacy_if_#2 set_ #4 :n } { \exp_not:n {#1} } }
- \@@_cmd_set:nn { \l_keys_path_str / unknown }
- {
- \msg_error:nne { keys } { boolean-values-only }
- \l_keys_path_str
- }
- \@@_default_set:n { true }
- \cs_if_exist:cF { if#1 }
- {
- \cs:w newif \exp_after:wN \cs_end:
- \cs:w if#1 \cs_end:
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_meta_make:n}
-% \begin{macro}{\@@_meta_make:nn}
-% To create a meta-key, simply set up to pass data through. The internal
-% function is used here as a meta key should respect the prevailing
-% filtering, etc.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_meta_make:n #1
- {
- \exp_args:NVo \@@_cmd_set_direct:nn \l_keys_path_str
- {
- \exp_after:wN \@@_set:nn \exp_after:wN
- { \l_@@_module_str } {#1}
- }
- }
-\cs_new_protected:Npn \@@_meta_make:nn #1#2
- {
- \exp_args:NV \@@_cmd_set_direct:nn
- \l_keys_path_str { \@@_set:nn {#1} {#2} }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_prop_put:Nn, \@@_prop_put:cn}
-% Much the same as other variables, but needs a dedicated auxiliary.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_prop_put:Nn #1#2
- {
- \prop_if_exist:NF #1 { \prop_new:N #1 }
- \exp_after:wN \@@_find_key_module:wNN \l_keys_path_str \s_@@_stop
- \l_@@_tmpa_tl \l_@@_tmpb_tl
- \@@_cmd_set:ne \l_keys_path_str
- {
- \exp_not:c { prop_ #2 put:Nnn }
- \exp_not:N #1
- { \l_@@_tmpb_tl }
- \exp_not:n { {##1} }
- }
- }
-\cs_generate_variant:Nn \@@_prop_put:Nn { c }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_undefine:}
-% Undefining a key has to be done without \cs{cs_undefine:c} as that
-% function acts globally.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_undefine:
- {
- \clist_map_inline:nn
- { code , default , groups , inherit , type , check }
- {
- \@@_cs_undefine:c
- { \tl_use:c { c_@@_ ##1 _root_str } \l_keys_path_str }
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_value_requirement:nn}
-% \begin{macro}{\@@_check_forbidden:, \@@_check_required:}
-% Validating key input is done using a second function which runs before
-% the main key code. Setting that up means setting it equal to a generic
-% stub which does the check. This approach makes the lookup very fast at
-% the cost of one additional csname per key that needs it. The cleanup here
-% has to know the structure of the following code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_value_requirement:nn #1#2
- {
- \str_case:nnF {#2}
- {
- { true }
- {
- \cs_set_eq:cc
- { \c_@@_check_root_str \l_keys_path_str }
- { @@_check_ #1 : }
- }
- { false }
- {
- \cs_if_eq:ccT
- { \c_@@_check_root_str \l_keys_path_str }
- { @@_check_ #1 : }
- {
- \@@_cs_undefine:c
- { \c_@@_check_root_str \l_keys_path_str }
- }
- }
- }
- {
- \msg_error:nne { keys }
- { boolean-values-only }
- { .value_ #1 :n }
- }
- }
-\cs_new_protected:Npn \@@_check_forbidden:
- {
- \bool_if:NF \l_@@_no_value_bool
- {
- \msg_error:nnee { keys } { value-forbidden }
- \l_keys_path_str \l_keys_value_tl
- \use_none:nnn
- }
- }
-\cs_new_protected:Npn \@@_check_required:
- {
- \bool_if:NT \l_@@_no_value_bool
- {
- \msg_error:nne { keys } { value-required }
- \l_keys_path_str
- \use_none:nnn
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_usage:n}
-% \begin{macro}{\@@_usage:NN}
-% \begin{macro}{\@@_usage:w}
-% Save the relevant data.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_usage:n #1
- {
- \str_case:nnF {#1}
- {
- { general }
- {
- \@@_usage:NN \l_keys_usage_load_prop
- \c_false_bool
- \@@_usage:NN \l_keys_usage_preamble_prop
- \c_false_bool
- }
- { load }
- {
- \@@_usage:NN \l_keys_usage_load_prop
- \c_true_bool
- \@@_usage:NN \l_keys_usage_preamble_prop
- \c_false_bool
- }
- { preamble }
- {
- \@@_usage:NN \l_keys_usage_load_prop
- \c_false_bool
- \@@_usage:NN \l_keys_usage_preamble_prop
- \c_true_bool
- }
- }
- {
- \msg_error:nnnn { keys }
- { choice-unknown }
- { .usage:n }
- {#1}
- }
- }
-\cs_new_protected:Npn \@@_usage:NN #1#2
- {
- \prop_get:NVNF #1 \l_@@_module_str \l_@@_tmpa_tl
- { \tl_clear:N \l_@@_tmpa_tl }
- \tl_set:Ne \l_@@_tmpb_tl
- { \exp_after:wN \@@_usage:w \l_keys_path_str \s_@@_stop }
- \bool_if:NTF #2
- { \clist_put_right:NV \l_@@_tmpa_tl \l_@@_tmpb_tl }
- { \clist_remove_all:NV \l_@@_tmpa_tl \l_@@_tmpb_tl }
- \prop_put:NVV #1 \l_@@_module_str
- \l_@@_tmpa_tl
- }
-\cs_new:Npn \@@_usage:w #1 / #2 \s_@@_stop {#2}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_variable_set:NnnN, \@@_variable_set:cnnN}
-% \begin{macro}{\@@_variable_set_required:NnnN, \@@_variable_set_required:cnnN}
-% Setting a variable takes the type and scope separately so that
-% it is easy to make a new variable if needed.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_variable_set:NnnN #1#2#3#4
- {
- \use:c { #2_if_exist:NF } #1 { \use:c { #2 _new:N } #1 }
- \@@_cmd_set:ne \l_keys_path_str
- {
- \exp_not:c { #2 _ #3 set:N #4 }
- \exp_not:N #1
- \exp_not:n { {##1} }
- }
- }
-\cs_generate_variant:Nn \@@_variable_set:NnnN { c }
-\cs_new_protected:Npn \@@_variable_set_required:NnnN #1#2#3#4
- {
- \@@_variable_set:NnnN #1 {#2} {#3} #4
- \@@_value_requirement:nn { required } { true }
- }
-\cs_generate_variant:Nn \@@_variable_set_required:NnnN { c }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Creating key properties}
-%
-% The key property functions are all wrappers for internal functions,
-% meaning that things stay readable and can also be altered later on.
-%
-% Importantly, while key properties have \enquote{normal} argument specs, the
-% underlying code always supplies one braced argument to these. As such, argument
-% expansion is handled by hand rather than using the standard tools. This shows
-% up particularly for the two-argument properties, where things would otherwise
-% go badly wrong.
-%
-% \begin{macro}{.bool_set:N, .bool_set:c}
-% \begin{macro}{.bool_gset:N, .bool_gset:c}
-% One function for this.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_set:N } #1
- { \@@_bool_set:Nn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_set:c } #1
- { \@@_bool_set:cn {#1} { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_gset:N } #1
- { \@@_bool_set:Nn #1 { g } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_gset:c } #1
- { \@@_bool_set:cn {#1} { g } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.bool_set_inverse:N, .bool_set_inverse:c}
-% \begin{macro}{.bool_gset_inverse:N, .bool_gset_inverse:c}
-% One function for this.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_set_inverse:N } #1
- { \@@_bool_set_inverse:Nn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_set_inverse:c } #1
- { \@@_bool_set_inverse:cn {#1} { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_gset_inverse:N } #1
- { \@@_bool_set_inverse:Nn #1 { g } }
-\cs_new_protected:cpn { \c_@@_props_root_str .bool_gset_inverse:c } #1
- { \@@_bool_set_inverse:cn {#1} { g } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.choice:}
-% Making a choice is handled internally, as it is also needed by
-% \texttt{.generate_choices:n}.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .choice: }
- { \@@_choice_make: }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.choices:nn, .choices:Vn, .choices:en, .choices:on, .choices:xn}
-% For auto-generation of a series of mutually-exclusive choices.
-% Here, |#1| consists of two separate
-% arguments, hence the slightly odd-looking implementation.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .choices:nn } #1
- { \@@_choices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .choices:Vn } #1
- { \exp_args:NV \@@_choices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .choices:en } #1
- { \exp_args:Ne \@@_choices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .choices:on } #1
- { \exp_args:No \@@_choices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .choices:xn } #1
- { \exp_args:Nx \@@_choices_make:nn #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.code:n}
-% Creating code is simply a case of passing through to the underlying
-% \texttt{set} function.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .code:n } #1
- { \@@_cmd_set:nn \l_keys_path_str {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.clist_set:N, .clist_set:c}
-% \begin{macro}{.clist_gset:N, .clist_gset:c}
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .clist_set:N } #1
- { \@@_variable_set:NnnN #1 { clist } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .clist_set:c } #1
- { \@@_variable_set:cnnN {#1} { clist } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .clist_gset:N } #1
- { \@@_variable_set:NnnN #1 { clist } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .clist_gset:c } #1
- { \@@_variable_set:cnnN {#1} { clist } { g } n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {.cs_set:Np, .cs_set:cp, .cs_set_protected:Np, .cs_set_protected:cp}
-% \begin{macro}
-% {.cs_gset:Np, .cs_gset:cp, .cs_gset_protected:Np, .cs_gset_protected:cp}
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_set:Np } #1
- { \@@_cs_set:NNpn \cs_set:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_set:cp } #1
- { \@@_cs_set:Ncpn \cs_set:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_set_protected:Np } #1
- { \@@_cs_set:NNpn \cs_set_protected:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_set_protected:cp } #1
- { \@@_cs_set:Ncpn \cs_set_protected:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_gset:Np } #1
- { \@@_cs_set:NNpn \cs_gset:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_gset:cp } #1
- { \@@_cs_set:Ncpn \cs_gset:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_gset_protected:Np } #1
- { \@@_cs_set:NNpn \cs_gset_protected:Npn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .cs_gset_protected:cp } #1
- { \@@_cs_set:Ncpn \cs_gset_protected:Npn #1 { } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.default:n, .default:V, .default:e, .default:o, .default:x}
-% Expansion is left to the internal functions.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .default:n } #1
- { \@@_default_set:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .default:V } #1
- { \exp_args:NV \@@_default_set:n #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .default:e } #1
- { \exp_args:Ne \@@_default_set:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .default:o } #1
- { \exp_args:No \@@_default_set:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .default:x } #1
- { \exp_args:Nx \@@_default_set:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.dim_set:N, .dim_set:c}
-% \begin{macro}{.dim_gset:N, .dim_gset:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .dim_set:N } #1
- { \@@_variable_set_required:NnnN #1 { dim } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .dim_set:c } #1
- { \@@_variable_set_required:cnnN {#1} { dim } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .dim_gset:N } #1
- { \@@_variable_set_required:NnnN #1 { dim } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .dim_gset:c } #1
- { \@@_variable_set_required:cnnN {#1} { dim } { g } n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.fp_set:N, .fp_set:c}
-% \begin{macro}{.fp_gset:N, .fp_gset:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .fp_set:N } #1
- { \@@_variable_set_required:NnnN #1 { fp } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .fp_set:c } #1
- { \@@_variable_set_required:cnnN {#1} { fp } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .fp_gset:N } #1
- { \@@_variable_set_required:NnnN #1 { fp } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .fp_gset:c } #1
- { \@@_variable_set_required:cnnN {#1} { fp } { g } n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.groups:n}
-% A single property to create groups of keys.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .groups:n } #1
- { \@@_groups_set:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.inherit:n}
-% Nothing complex: only one variant at the moment!
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .inherit:n } #1
- { \@@_inherit:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.initial:n, .initial:V, .initial:e, .initial:o, .initial:x}
-% The standard hand-off approach.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .initial:n } #1
- { \@@_initialise:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .initial:V } #1
- { \exp_args:NV \@@_initialise:n #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .initial:e } #1
- { \exp_args:Ne \@@_initialise:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .initial:o } #1
- { \exp_args:No \@@_initialise:n {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .initial:x } #1
- { \exp_args:Nx \@@_initialise:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.int_set:N, .int_set:c}
-% \begin{macro}{.int_gset:N, .int_gset:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .int_set:N } #1
- { \@@_variable_set_required:NnnN #1 { int } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .int_set:c } #1
- { \@@_variable_set_required:cnnN {#1} { int } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .int_gset:N } #1
- { \@@_variable_set_required:NnnN #1 { int } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .int_gset:c } #1
- { \@@_variable_set_required:cnnN {#1} { int } { g } n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% .legacy_if_set:n, .legacy_if_gset:n,
-% .legacy_if_set_inverse:n, .legacy_if_gset_inverse:n
-% }
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .legacy_if_set:n } #1
- { \@@_legacy_if_set:nn {#1} { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .legacy_if_gset:n } #1
- { \@@_legacy_if_set:nn {#1} { g } }
-\cs_new_protected:cpn { \c_@@_props_root_str .legacy_if_set_inverse:n } #1
- { \@@_legacy_if_set_inverse:nn {#1} { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .legacy_if_gset_inverse:n } #1
- { \@@_legacy_if_set_inverse:nn {#1} { g } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.meta:n}
-% Making a meta is handled internally.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .meta:n } #1
- { \@@_meta_make:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.meta:nn}
-% Meta with path: potentially lots of variants, but for the moment
-% no so many defined.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .meta:nn } #1
- { \@@_meta_make:nn #1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.multichoice:}
-% \begin{macro}{.multichoices:nn, .multichoices:Vn, .multichoices:en, .multichoices:on, .multichoices:xn}
-% The same idea as \texttt{.choice:} and \texttt{.choices:nn}, but
-% where more than one choice is allowed.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoice: }
- { \@@_multichoice_make: }
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoices:nn } #1
- { \@@_multichoices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoices:Vn } #1
- { \exp_args:NV \@@_multichoices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoices:en } #1
- { \exp_args:Ne \@@_multichoices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoices:on } #1
- { \exp_args:No \@@_multichoices_make:nn #1 }
-\cs_new_protected:cpn { \c_@@_props_root_str .multichoices:xn } #1
- { \exp_args:Nx \@@_multichoices_make:nn #1 }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.muskip_set:N, .muskip_set:c, .muskip_gset:N, .muskip_gset:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .muskip_set:N } #1
- { \@@_variable_set_required:NnnN #1 { muskip } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .muskip_set:c } #1
- { \@@_variable_set_required:cnnN {#1} { muskip } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .muskip_gset:N } #1
- { \@@_variable_set_required:NnnN #1 { muskip } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .muskip_gset:c } #1
- { \@@_variable_set_required:cnnN {#1} { muskip } { g } n }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.prop_put:N, .prop_put:c, .prop_gput:N, .prop_gput:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .prop_put:N } #1
- { \@@_prop_put:Nn #1 { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .prop_put:c } #1
- { \@@_prop_put:cn {#1} { } }
-\cs_new_protected:cpn { \c_@@_props_root_str .prop_gput:N } #1
- { \@@_prop_put:Nn #1 { g } }
-\cs_new_protected:cpn { \c_@@_props_root_str .prop_gput:c } #1
- { \@@_prop_put:cn {#1} { g } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.skip_set:N, .skip_set:c}
-% \begin{macro}{.skip_gset:N, .skip_gset:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .skip_set:N } #1
- { \@@_variable_set_required:NnnN #1 { skip } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .skip_set:c } #1
- { \@@_variable_set_required:cnnN {#1} { skip } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .skip_gset:N } #1
- { \@@_variable_set_required:NnnN #1 { skip } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .skip_gset:c } #1
- { \@@_variable_set_required:cnnN {#1} { skip } { g } n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.str_set:N, .str_set:c}
-% \begin{macro}{.str_gset:N, .str_gset:c}
-% \begin{macro}{.str_set_e:N, .str_set_e:c}
-% \begin{macro}{.str_gset_e:N, .str_gset_e:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .str_set:N } #1
- { \@@_variable_set:NnnN #1 { str } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_set:c } #1
- { \@@_variable_set:cnnN {#1} { str } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_set_e:N } #1
- { \@@_variable_set:NnnN #1 { str } { } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_set_e:c } #1
- { \@@_variable_set:cnnN {#1} { str } { } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_gset:N } #1
- { \@@_variable_set:NnnN #1 { str } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_gset:c } #1
- { \@@_variable_set:cnnN {#1} { str } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_gset_e:N } #1
- { \@@_variable_set:NnnN #1 { str } { g } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .str_gset_e:c } #1
- { \@@_variable_set:cnnN {#1} { str } { g } e }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.tl_set:N, .tl_set:c}
-% \begin{macro}{.tl_gset:N, .tl_gset:c}
-% \begin{macro}{.tl_set_e:N, .tl_set_e:c}
-% \begin{macro}{.tl_gset_e:N, .tl_gset_e:c}
-% Setting a variable is very easy: just pass the data along.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_set:N } #1
- { \@@_variable_set:NnnN #1 { tl } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_set:c } #1
- { \@@_variable_set:cnnN {#1} { tl } { } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_set_e:N } #1
- { \@@_variable_set:NnnN #1 { tl } { } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_set_e:c } #1
- { \@@_variable_set:cnnN {#1} { tl } { } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_gset:N } #1
- { \@@_variable_set:NnnN #1 { tl } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_gset:c } #1
- { \@@_variable_set:cnnN {#1} { tl } { g } n }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_gset_e:N } #1
- { \@@_variable_set:NnnN #1 { tl } { g } e }
-\cs_new_protected:cpn { \c_@@_props_root_str .tl_gset_e:c } #1
- { \@@_variable_set:cnnN {#1} { tl } { g } e }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{.undefine:}
-% Another simple wrapper.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .undefine: }
- { \@@_undefine: }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.usage:n}
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .usage:n } #1
- { \@@_usage:n {#1} }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{.value_forbidden:n}
-% \begin{macro}{.value_required:n}
-% These are very similar, so both call the same function.
-% \begin{macrocode}
-\cs_new_protected:cpn { \c_@@_props_root_str .value_forbidden:n } #1
- { \@@_value_requirement:nn { forbidden } {#1} }
-\cs_new_protected:cpn { \c_@@_props_root_str .value_required:n } #1
- { \@@_value_requirement:nn { required } {#1} }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Setting keys}
-%
-% \begin{macro}
-% {
-% \keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:ne,
-% \keys_set:no, \keys_set:nx,
-% \@@_set:nn
-% }
-% \begin{macro}{\@@_set:nnn}
-% A simple wrapper allowing for nesting.
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_set:nn #1#2
- {
- \use:e
- {
- \bool_set_false:N \exp_not:N \l_@@_only_known_bool
- \bool_set_false:N \exp_not:N \l_@@_filtered_bool
- \bool_set_false:N \exp_not:N \l_@@_selective_bool
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:N \q_@@_no_value }
- \@@_set:nn \exp_not:n { {#1} {#2} }
- \bool_if:NT \l_@@_only_known_bool
- { \bool_set_true:N \exp_not:N \l_@@_only_known_bool }
- \bool_if:NT \l_@@_filtered_bool
- { \bool_set_true:N \exp_not:N \l_@@_filtered_bool }
- \bool_if:NT \l_@@_selective_bool
- { \bool_set_true:N \exp_not:N \l_@@_selective_bool }
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:o \l_@@_relative_tl }
- }
- }
-\cs_generate_variant:Nn \keys_set:nn { nV , nv , ne , no , nx }
-\cs_new_protected:Npn \@@_set:nn #1#2
- { \exp_args:No \@@_set:nnn \l_@@_module_str {#1} {#2} }
-\cs_new_protected:Npn \@@_set:nnn #1#2#3
- {
- \str_set:Ne \l_@@_module_str { \@@_trim_spaces:n {#2} }
- \keyval_parse:NNn \@@_set_keyval:n \@@_set_keyval:nn {#3}
- \str_set:Nn \l_@@_module_str {#1}
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% \keys_set_known:nnN, \keys_set_known:nVN,
-% \keys_set_known:nvN, \keys_set_known:neN,
-% \keys_set_known:noN
-% }
-% \begin{macro}
-% {
-% \keys_set_known:nnnN, \keys_set_known:nVnN,
-% \keys_set_known:nvnN, \keys_set_known:nenN,
-% \keys_set_known:nonN
-% }
-% \begin{macro}{\@@_set_known:nnnnN}
-% \begin{macro}
-% {
-% \keys_set_known:nn, \keys_set_known:nV,
-% \keys_set_known:nv, \keys_set_known:ne,
-% \keys_set_known:no
-% }
-% \begin{macro}{\@@_set_known:nnn}
-% Setting known keys simply means setting the appropriate boolean, then
-% running the standard code. To allow for nested setting, any existing
-% value of \cs{l_@@_unused_clist} is saved on the stack and reset
-% afterwards. Note that for speed/simplicity reasons we use a \texttt{tl}
-% operation to set the \texttt{clist} here!
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_set_known:nnN #1#2#3
- {
- \exp_args:No \@@_set_known:nnnnN
- \l_@@_unused_clist \q_@@_no_value {#1} {#2} #3
- }
-\cs_generate_variant:Nn \keys_set_known:nnN { nV , nv , ne , no }
-\cs_new_protected:Npn \keys_set_known:nnnN #1#2#3#4
- {
- \exp_args:No \@@_set_known:nnnnN
- \l_@@_unused_clist {#3} {#1} {#2} #4
- }
-\cs_generate_variant:Nn \keys_set_known:nnnN { nV , nv , ne , no }
-\cs_new_protected:Npn \@@_set_known:nnnnN #1#2#3#4#5
- {
- \clist_clear:N \l_@@_unused_clist
- \@@_set_known:nnn {#2} {#3} {#4}
- \__kernel_tl_set:Nx #5 { \exp_not:o \l_@@_unused_clist }
- \__kernel_tl_set:Nx \l_@@_unused_clist { \exp_not:n {#1} }
- }
-\cs_new_protected:Npn \keys_set_known:nn #1#2
- { \@@_set_known:nnn \q_@@_no_value {#1} {#2} }
-\cs_generate_variant:Nn \keys_set_known:nn { nV , nv , ne , no }
-\cs_new_protected:Npn \@@_set_known:nnn #1#2#3
- {
- \use:e
- {
- \bool_set_true:N \exp_not:N \l_@@_only_known_bool
- \bool_set_false:N \exp_not:N \l_@@_filtered_bool
- \bool_set_false:N \exp_not:N \l_@@_selective_bool
- \tl_set:Nn \exp_not:N \l_@@_relative_tl { \exp_not:n {#1} }
- \@@_set:nn \exp_not:n { {#2} {#3} }
- \bool_if:NF \l_@@_only_known_bool
- { \bool_set_false:N \exp_not:N \l_@@_only_known_bool }
- \bool_if:NT \l_@@_filtered_bool
- { \bool_set_true:N \exp_not:N \l_@@_filtered_bool }
- \bool_if:NT \l_@@_selective_bool
- { \bool_set_true:N \exp_not:N \l_@@_selective_bool }
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:o \l_@@_relative_tl }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% \keys_set_exclude_groups:nnnN, \keys_set_exclude_groups:nnVN,
-% \keys_set_exclude_groups:nnvN, \keys_set_exclude_groups:nnoN
-% }
-% \begin{macro}
-% {
-% \keys_set_exclude_groups:nnnnN, \keys_set_exclude_groups:nnVnN,
-% \keys_set_exclude_groups:nnvnN, \keys_set_exclude_groups:nnonN
-% }
-% \begin{macro}{\@@_set_exclude_groups:nnnnnN}
-% \begin{macro}
-% {
-% \keys_set_exclude_groups:nnn, \keys_set_exclude_groups:nnV,
-% \keys_set_exclude_groups:nnv, \keys_set_exclude_groups:nno
-% }
-% \begin{macro}{\@@_set_exclude_groups:nnnn}
-% \begin{macro}
-% {
-% \keys_set_groups:nnn, \keys_set_groups:nnV, \keys_set_groups:nnv,
-% \keys_set_groups:nno
-% }
-% \begin{macro}{\@@_set_selective:nnn}
-% \begin{macro}{\@@_set_selective:nnnn}
-% The idea of setting keys in a selective manner again uses booleans
-% wrapped around the basic code. The comments on \cs{keys_set_known:nnN}
-% also apply here. We have a bit more shuffling to do to keep everything
-% nestable.
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_set_exclude_groups:nnnN #1#2#3#4
- {
- \exp_args:No \@@_set_exclude_groups:nnnnnN
- \l_@@_unused_clist
- \q_@@_no_value {#1} {#2} {#3} #4
- }
-\cs_generate_variant:Nn \keys_set_exclude_groups:nnnN { nnV , nnv , nno }
-\cs_new_protected:Npn \keys_set_exclude_groups:nnnnN #1#2#3#4#5
- {
- \exp_args:No \@@_set_exclude_groups:nnnnnN
- \l_@@_unused_clist {#4} {#1} {#2} {#3} #5
- }
-\cs_generate_variant:Nn \keys_set_exclude_groups:nnnnN { nnV , nnv , nno }
-\cs_new_protected:Npn \@@_set_exclude_groups:nnnnnN #1#2#3#4#5#6
- {
- \clist_clear:N \l_@@_unused_clist
- \@@_set_exclude_groups:nnnn {#2} {#3} {#4} {#5}
- \__kernel_tl_set:Nx #6 { \exp_not:o \l_@@_unused_clist }
- \__kernel_tl_set:Nx \l_@@_unused_clist { \exp_not:n {#1} }
- }
-\cs_new_protected:Npn \keys_set_exclude_groups:nnn #1#2#3
- {\@@_set_exclude_groups:nnnn \q_@@_no_value {#1} {#2} {#3} }
-\cs_generate_variant:Nn \keys_set_exclude_groups:nnn { nnV , nnv , nno }
-\cs_new_protected:Npn \@@_set_exclude_groups:nnnn #1#2#3#4
- {
- \use:e
- {
- \bool_set_false:N \exp_not:N \l_@@_only_known_bool
- \bool_set_true:N \exp_not:N \l_@@_filtered_bool
- \bool_set_true:N \exp_not:N \l_@@_selective_bool
- \tl_set:Nn \exp_not:N \l_@@_relative_tl { \exp_not:n {#1} }
- \@@_set_selective:nnn \exp_not:n { {#2} {#3} {#4} }
- \bool_if:NT \l_@@_only_known_bool
- { \bool_set_true:N \exp_not:N \l_@@_only_known_bool }
- \bool_if:NF \l_@@_filtered_bool
- { \bool_set_false:N \exp_not:N \l_@@_filtered_bool }
- \bool_if:NF \l_@@_selective_bool
- { \bool_set_false:N \exp_not:N \l_@@_selective_bool }
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:o \l_@@_relative_tl }
- }
- }
-\cs_new_protected:Npn \keys_set_groups:nnn #1#2#3
- {
- \use:e
- {
- \bool_set_false:N \exp_not:N \l_@@_only_known_bool
- \bool_set_false:N \exp_not:N \l_@@_filtered_bool
- \bool_set_true:N \exp_not:N \l_@@_selective_bool
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:N \q_@@_no_value }
- \@@_set_selective:nnn \exp_not:n { {#1} {#2} {#3} }
- \bool_if:NT \l_@@_only_known_bool
- { \bool_set_true:N \exp_not:N \l_@@_only_known_bool }
- \bool_if:NF \l_@@_filtered_bool
- { \bool_set_true:N \exp_not:N \l_@@_filtered_bool }
- \bool_if:NF \l_@@_selective_bool
- { \bool_set_false:N \exp_not:N \l_@@_selective_bool }
- \tl_set:Nn \exp_not:N \l_@@_relative_tl
- { \exp_not:o \l_@@_relative_tl }
- }
- }
-\cs_generate_variant:Nn \keys_set_groups:nnn { nnV , nnv , nno }
-\cs_new_protected:Npn \@@_set_selective:nnn
- { \exp_args:No \@@_set_selective:nnnn \l_@@_selective_seq }
-\cs_new_protected:Npn \@@_set_selective:nnnn #1#2#3#4
- {
- \exp_args:NNe \seq_set_from_clist:Nn
- \l_@@_selective_seq { \tl_to_str:n {#3} }
- \@@_set:nn {#2} {#4}
- \tl_set:Nn \l_@@_selective_seq {#1}
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\keys_precompile:nnN}
-% A simple wrapper.
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_precompile:nnN #1#2#3
- {
- \bool_set_true:N \l_@@_precompile_bool
- \tl_clear:N \l_@@_precompile_tl
- \keys_set:nn {#1} {#2}
- \bool_set_false:N \l_@@_precompile_bool
- \tl_set_eq:NN #3 \l_@@_precompile_tl
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_set_keyval:n, \@@_set_keyval:nn}
-% \begin{macro}{\@@_set_keyval:nnn, \@@_set_keyval:onn}
-% \begin{macro}{\@@_find_key_module:wNN}
-% \begin{macro}
-% {
-% \@@_find_key_module_auxi:Nw ,
-% \@@_find_key_module_auxii:Nw ,
-% \@@_find_key_module_auxiii:Nn ,
-% \@@_find_key_module_auxiv:Nw
-% }
-% \begin{macro}{\@@_set_selective:}
-% A shared system once again. First, set the current path and add a
-% default if needed. There are then checks to see if a value is
-% required or forbidden. If everything passes, move on to execute the
-% code.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_set_keyval:n #1
- {
- \bool_set_true:N \l_@@_no_value_bool
- \@@_set_keyval:onn \l_@@_module_str {#1} { }
- }
-\cs_new_protected:Npn \@@_set_keyval:nn #1#2
- {
- \bool_set_false:N \l_@@_no_value_bool
- \@@_set_keyval:onn \l_@@_module_str {#1} {#2}
- }
-% \end{macrocode}
-% The key path here can be fully defined, after which there is a search
-% for the key and module names: the user may have passed them with part
-% of what is actually the module (for our purposes) in the key name. As
-% that happens on a per-key basis, we use the stack approach to restore
-% the module name without a group.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_set_keyval:nnn #1#2#3
- {
- \__kernel_tl_set:Nx \l_keys_path_str
- {
- \tl_if_blank:nF {#1}
- { #1 / }
- \@@_trim_spaces:n {#2}
- }
- \str_clear:N \l_@@_module_str
- \str_clear:N \l_@@_inherit_str
- \exp_after:wN \@@_find_key_module:wNN \l_keys_path_str \s_@@_stop
- \l_@@_module_str \l_keys_key_str
- \tl_set_eq:NN \l_keys_key_tl \l_keys_key_str
- \@@_value_or_default:n {#3}
- \bool_if:NTF \l_@@_selective_bool
- \@@_set_selective:
- \@@_execute:
- \str_set:Nn \l_@@_module_str {#1}
- }
-\cs_generate_variant:Nn \@@_set_keyval:nnn { o }
-% \end{macrocode}
-% This function uses \cs{cs_set_nopar:Npe} internally for performance reasons,
-% the argument |#1| is already a string in every usage, so turning it into a
-% string again seems unnecessary.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_find_key_module:wNN #1 \s_@@_stop #2 #3
- {
- \@@_find_key_module_auxi:Nw #2 #1 \s_@@_nil \@@_find_key_module_auxii:Nw
- / \s_@@_nil \@@_find_key_module_auxiv:Nw #3
- }
-\cs_new_protected:Npn \@@_find_key_module_auxi:Nw #1 #2 / #3 \s_@@_nil #4
- {
- #4 #1 #2 \s_@@_mark #3 \s_@@_nil #4
- }
-\cs_new_protected:Npn \@@_find_key_module_auxii:Nw
- #1 #2 \s_@@_mark #3 \s_@@_nil \@@_find_key_module_auxii:Nw
- {
- \cs_set_nopar:Npe #1 { \tl_if_empty:NF #1 { #1 / } #2 }
- \@@_find_key_module_auxi:Nw #1 #3 \s_@@_nil \@@_find_key_module_auxiii:Nw
- }
-\cs_new_protected:Npn \@@_find_key_module_auxiii:Nw #1 #2 \s_@@_mark
- {
- \cs_set_nopar:Npe #1 { \tl_if_empty:NF #1 { #1 / } #2 }
- \@@_find_key_module_auxi:Nw #1
- }
-\cs_new_protected:Npn \@@_find_key_module_auxiv:Nw
- #1 #2 \s_@@_nil #3 \s_@@_mark
- \s_@@_nil \@@_find_key_module_auxiv:Nw #4
- {
- \cs_set_nopar:Npn #4 { #2 }
- }
-% \end{macrocode}
-% If selective setting is active, there are a number of possible sub-cases
-% to consider. The key name may not be known at all or if it is, it may not
-% have any groups assigned. There is then the question of whether the
-% selection is opt-in or opt-out.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_set_selective:
- {
- \cs_if_exist:cTF { \c_@@_groups_root_str \l_keys_path_str }
- {
- \clist_set_eq:Nc \l_@@_groups_clist
- { \c_@@_groups_root_str \l_keys_path_str }
- \@@_check_groups:
- }
- {
- \bool_if:NTF \l_@@_filtered_bool
- \@@_execute:
- \@@_store_unused:
- }
- }
-% \end{macrocode}
-% In the case where selective setting requires a comparison of the list
-% of groups which apply to a key with the list of those which have been
-% set active. That requires two mappings, and again a different outcome
-% depending on whether opt-in or opt-out is set.
-% It is safe to use \cs{clist_if_in:NnTF} because
-% both \cs{l_@@_selective_seq} and \cs{l_@@_groups_clist} contain the
-% groups as strings, without leading/trailing spaces in any item,
-% since the \pkg{l3clist} functions were applied to the result of
-% applying \cs{tl_to_str:n}.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_check_groups:
- {
- \bool_set_false:N \l_@@_tmp_bool
- \seq_map_inline:Nn \l_@@_selective_seq
- {
- \clist_if_in:NnT \l_@@_groups_clist {##1}
- {
- \bool_set_true:N \l_@@_tmp_bool
- \seq_map_break:
- }
- }
- \bool_if:NTF \l_@@_tmp_bool
- {
- \bool_if:NTF \l_@@_filtered_bool
- \@@_store_unused:
- \@@_execute:
- }
- {
- \bool_if:NTF \l_@@_filtered_bool
- \@@_execute:
- \@@_store_unused:
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_value_or_default:n}
-% \begin{macro}{\@@_default_inherit:}
-% If a value is given, return it as |#1|, otherwise send a default if
-% available.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_value_or_default:n #1
- {
- \bool_if:NTF \l_@@_no_value_bool
- {
- \cs_if_exist:cTF { \c_@@_default_root_str \l_keys_path_str }
- {
- \tl_set_eq:Nc
- \l_keys_value_tl
- { \c_@@_default_root_str \l_keys_path_str }
- }
- {
- \tl_clear:N \l_keys_value_tl
- \cs_if_exist:cT
- { \c_@@_inherit_root_str \@@_parent:o \l_keys_path_str }
- { \@@_default_inherit: }
- }
- }
- { \tl_set:Nn \l_keys_value_tl {#1} }
- }
-\cs_new_protected:Npn \@@_default_inherit:
- {
- \clist_map_inline:cn
- { \c_@@_inherit_root_str \@@_parent:o \l_keys_path_str }
- {
- \cs_if_exist:cT
- { \c_@@_default_root_str ##1 / \l_keys_key_str }
- {
- \tl_set_eq:Nc
- \l_keys_value_tl
- { \c_@@_default_root_str ##1 / \l_keys_key_str }
- \clist_map_break:
- }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_execute:, \@@_execute_inherit:, \@@_execute_unknown:}
-% \begin{macro}[EXP]{\@@_execute:nn, \@@_execute:no}
-% \begin{macro}{\@@_store_unused:,\@@_store_unused_aux:}
-% Actually executing a key is done in two parts. First, look for the
-% key itself, then look for the \texttt{unknown} key with the same
-% path. If both of these fail, complain. What exactly happens if a key
-% is unknown depends on whether unknown keys are being skipped or if
-% an error should be raised.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_execute:
- {
- \cs_if_exist:cTF { \c_@@_code_root_str \l_keys_path_str }
- {
- \cs_if_exist_use:c { \c_@@_check_root_str \l_keys_path_str }
- \@@_execute:no \l_keys_path_str \l_keys_value_tl
- }
- {
- \cs_if_exist:cTF
- { \c_@@_inherit_root_str \@@_parent:o \l_keys_path_str }
- { \@@_execute_inherit: }
- { \@@_execute_unknown: }
- }
- }
-% \end{macrocode}
-% To deal with the case where there is no hit, we leave
-% \cs{@@_execute_unknown:} in the input stream and clean it up using the
-% break function: that avoids needing a boolean.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_execute_inherit:
- {
- \clist_map_inline:cn
- { \c_@@_inherit_root_str \@@_parent:o \l_keys_path_str }
- {
- \cs_if_exist:cT
- { \c_@@_code_root_str ##1 / \l_keys_key_str }
- {
- \str_set:Nn \l_@@_inherit_str {##1}
- \cs_if_exist_use:c { \c_@@_check_root_str ##1 / \l_keys_key_str }
- \@@_execute:no { ##1 / \l_keys_key_str } \l_keys_value_tl
- \clist_map_break:n \use_none:n
- }
- }
- \@@_execute_unknown:
- }
-\cs_new_protected:Npn \@@_execute_unknown:
- {
- \bool_if:NTF \l_@@_only_known_bool
- { \@@_store_unused: }
- {
- \cs_if_exist:cTF
- { \c_@@_code_root_str \l_@@_module_str / unknown }
- {
- \bool_if:NT \l_@@_no_value_bool
- {
- \cs_if_exist:cT
- { \c_@@_default_root_str \l_@@_module_str / unknown }
- {
- \tl_set_eq:Nc
- \l_keys_value_tl
- { \c_@@_default_root_str \l_@@_module_str / unknown }
- }
- }
- \@@_execute:no { \l_@@_module_str / unknown } \l_keys_value_tl
- }
- {
- \msg_error:nnee { keys } { unknown }
- \l_keys_path_str \l_@@_module_str
- }
- }
- }
-% \end{macrocode}
-% A key's code is in the control sequence with csname
-% \cs{c_@@_code_root_str} |#1|. We expand it once to get the
-% replacement text (with argument |#2|) and call \cs{use:n}
-% with this replacement as its argument. This ensures that any
-% undefined control sequence error in the key's code will lead to an
-% error message of the form |<argument>|\ldots{}\meta{control
-% sequence} in which one can read the (undefined) \meta{control
-% sequence} in full, rather than an error message that starts with the
-% potentially very long key name, which would make the (undefined)
-% \meta{control sequence} be truncated or sometimes completely hidden.
-% See \url{https://github.com/latex3/latex2e/issues/351}.
-% \begin{macrocode}
-\cs_new:Npn \@@_execute:nn #1#2
- { \@@_execute:no {#1} { \prg_do_nothing: #2 } }
-\cs_new:Npn \@@_execute:no #1#2
- {
- \exp_args:NNo \exp_args:No \use:n
- {
- \cs:w \c_@@_code_root_str #1 \exp_after:wN \cs_end:
- \exp_after:wN {#2}
- }
- }
-% \end{macrocode}
-% When there is no relative path, things here are easy: just save the key
-% name and value. When we are working with a relative path, first we
-% need to turn it into a string: that can't happen earlier as we need
-% to store \cs{q_@@_no_value}. Then, use a standard delimited approach to fish
-% out the partial path.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_store_unused:
- {
- \@@_quark_if_no_value:NTF \l_@@_relative_tl
- {
- \clist_put_right:Ne \l_@@_unused_clist
- {
- \l_keys_key_str
- \bool_if:NF \l_@@_no_value_bool
- { = { \exp_not:o \l_keys_value_tl } }
- }
- }
- {
- \tl_if_empty:NTF \l_@@_relative_tl
- {
- \clist_put_right:Ne \l_@@_unused_clist
- {
- \l_keys_path_str
- \bool_if:NF \l_@@_no_value_bool
- { = { \exp_not:o \l_keys_value_tl } }
- }
- }
- { \@@_store_unused_aux: }
- }
- }
-\cs_new_protected:Npn \@@_store_unused_aux:
- {
- \__kernel_tl_set:Nx \l_@@_relative_tl
- { \exp_args:No \@@_trim_spaces:n \l_@@_relative_tl }
- \use:e
- {
- \cs_set_protected:Npn \@@_store_unused:w
- ##1 \l_@@_relative_tl /
- ##2 \l_@@_relative_tl /
- ##3 \s_@@_stop
- }
- {
- \tl_if_blank:nF {##1}
- {
- \msg_error:nnee { keys } { bad-relative-key-path }
- \l_keys_path_str
- \l_@@_relative_tl
- }
- \clist_put_right:Ne \l_@@_unused_clist
- {
- \exp_not:n {##2}
- \bool_if:NF \l_@@_no_value_bool
- { = { \exp_not:o \l_keys_value_tl } }
- }
- }
- \use:e
- {
- \@@_store_unused:w \l_keys_path_str
- \l_@@_relative_tl / \l_@@_relative_tl /
- \s_@@_stop
- }
- }
-\cs_new_protected:Npn \@@_store_unused:w { }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_choice_find:n}
-% \begin{macro}[EXP]{\@@_choice_find:nn}
-% \begin{macro}[EXP]{\@@_multichoice_find:n}
-% Executing a choice has two parts. First, try the choice given, then
-% if that fails call the unknown key. That always exists, as it is created
-% when a choice is first made. So there is no need for any escape code.
-% For multiple choices, the same code ends up used in a mapping.
-% \begin{macrocode}
-\cs_new:Npn \@@_choice_find:n #1
- {
- \str_if_empty:NTF \l_@@_inherit_str
- { \@@_choice_find:nn \l_keys_path_str {#1} }
- {
- \@@_choice_find:nn
- { \l_@@_inherit_str / \l_keys_key_str } {#1}
- }
- }
-\cs_new:Npn \@@_choice_find:nn #1#2
- {
- \cs_if_exist:cTF { \c_@@_code_root_str #1 / \@@_trim_spaces:n {#2} }
- { \@@_execute:nn { #1 / \@@_trim_spaces:n {#2} } {#2} }
- { \@@_execute:nn { #1 / unknown } {#2} }
- }
-\cs_new:Npn \@@_multichoice_find:n #1
- { \clist_map_function:nN {#1} \@@_choice_find:n }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Utilities}
-%
-% \begin{macro}[EXP]{\@@_parent:o}
-% \begin{macro}[EXP]
-% {
-% \@@_parent_auxi:w ,
-% \@@_parent_auxii:w ,
-% \@@_parent_auxiii:n ,
-% \@@_parent_auxiv:w
-% }
-% Used to strip off the ending part of the key path after the last~|/|.
-% \begin{macrocode}
-\cs_new:Npn \@@_parent:o #1
- {
- \exp_after:wN \@@_parent_auxi:w #1 \q_nil \@@_parent_auxii:w
- / \q_nil \@@_parent_auxiv:w
- }
-\cs_new:Npn \@@_parent_auxi:w #1 / #2 \q_nil #3
- {
- #3 { #1 } #2 \q_nil #3
- }
-\cs_new:Npn \@@_parent_auxii:w #1 #2 \q_nil \@@_parent_auxii:w
- {
- #1 \@@_parent_auxi:w #2 \q_nil \@@_parent_auxiii:n
- }
-\cs_new:Npn \@@_parent_auxiii:n #1
- {
- / #1 \@@_parent_auxi:w
- }
-\cs_new:Npn \@@_parent_auxiv:w #1 \q_nil \@@_parent_auxiv:w
- {
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\@@_trim_spaces:n}
-% \begin{macro}[EXP]
-% {
-% \@@_trim_spaces_auxi:w ,
-% \@@_trim_spaces_auxii:w ,
-% \@@_trim_spaces_auxiii:w
-% }
-% Space stripping has to allow for the fact that the key here might have
-% several parts, and spaces need to be stripped from each part. Since the key
-% name is turned into a string groups can't be stripped accidentally and the
-% precautions of \cs{tl_trim_spaces:n} aren't necessary, in this case it is
-% much faster to just directly strip spaces around |/|.
-% \begin{macrocode}
-\group_begin:
- \cs_set:Npn \@@_tmp:w #1
- {
- \cs_new:Npn \@@_trim_spaces:n ##1
- {
- \exp_after:wN \@@_trim_spaces_auxi:w \tl_to_str:n { / ##1 } /
- \s_@@_nil \@@_trim_spaces_auxi:w
- \s_@@_mark \@@_trim_spaces_auxii:w
- #1 / #1
- \s_@@_nil \@@_trim_spaces_auxii:w
- \s_@@_mark \@@_trim_spaces_auxiii:w
- }
- }
- \@@_tmp:w { ~ }
-\group_end:
-\cs_new:Npn \@@_trim_spaces_auxi:w #1 ~ / #2 \s_@@_nil #3
- {
- #3 #1 / #2 \s_@@_nil #3
- }
-\cs_new:Npn \@@_trim_spaces_auxii:w #1 / ~ #2 \s_@@_mark #3
- {
- #3 #1 / #2 \s_@@_mark #3
- }
-\cs_new:Npn \@@_trim_spaces_auxiii:w
- / #1 /
- \s_@@_nil \@@_trim_spaces_auxi:w
- \s_@@_mark \@@_trim_spaces_auxii:w
- /
- \s_@@_nil \@@_trim_spaces_auxii:w
- \s_@@_mark \@@_trim_spaces_auxiii:w
- {
- #1
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP,pTF]{\keys_if_exist:nn}
-% A utility for others to see if a key exists.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p , T , F , TF }
- {
- \cs_if_exist:cTF
- { \c_@@_code_root_str \@@_trim_spaces:n { #1 / #2 } }
- { \prg_return_true: }
- { \prg_return_false: }
- }
-\prg_generate_conditional_variant:Nnn \keys_if_exist:nn { ne } { p , T , F , TF }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP,pTF]{\keys_if_choice_exist:nnn}
-% Just an alternative view on \cs{keys_if_exist:nnTF}.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \keys_if_choice_exist:nnn #1#2#3
- { p , T , F , TF }
- {
- \cs_if_exist:cTF
- { \c_@@_code_root_str \@@_trim_spaces:n { #1 / #2 / #3 } }
- { \prg_return_true: }
- { \prg_return_false: }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\keys_show:nn, \keys_log:nn}
-% \begin{macro}{\@@_show:Nnn}
-% \begin{macro}{\@@_show:n}
-% \begin{macro}{\@@_show:w}
-% \begin{macro}{\@@_show:Nw}
-% To show a key, show its code using a message.
-% \begin{macrocode}
-\cs_new_protected:Npn \keys_show:nn
- { \@@_show:Nnn \msg_show:nneeee }
-\cs_new_protected:Npn \keys_log:nn
- { \@@_show:Nnn \msg_log:nneeee }
-\cs_new_protected:Npn \@@_show:Nnn #1#2#3
- {
- #1 { keys } { show-key }
- { \@@_trim_spaces:n { #2 / #3 } }
- {
- \keys_if_exist:nnT {#2} {#3}
- {
- \exp_args:Nnf \msg_show_item_unbraced:nn { code }
- {
- \exp_args:Ne \@@_show:n
- {
- \exp_args:Nc \cs_replacement_spec:N
- {
- \c_@@_code_root_str
- \@@_trim_spaces:n { #2 / #3 }
- }
- }
- }
- }
- }
- { } { }
- }
-\cs_new:Npe \@@_show:n #1
- {
- \exp_not:N \@@_show:w
- #1
- \tl_to_str:n { \@@_precompile:n }
- #1
- \tl_to_str:n { \@@_precompile:n }
- \exp_not:N \s_@@_stop
- }
-\use:e
- {
- \cs_new:Npn \exp_not:N \@@_show:w
- #1 \tl_to_str:n { \@@_precompile:n }
- #2 \tl_to_str:n { \@@_precompile:n }
- #3 \exp_not:N \s_@@_stop
- }
- {
- \tl_if_blank:nTF {#2}
- {#1}
- { \@@_show:Nw #2 \s_@@_stop }
- }
-\use:e
- {
- \cs_new:Npn \exp_not:N \@@_show:Nw #1#2
- \c_right_brace_str \exp_not:N \s_@@_stop
- }
- {#2}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Messages}
-%
-% For when there is a need to complain.
-% \begin{macrocode}
-\msg_new:nnnn { keys } { bad-relative-key-path }
- { The~key~'#1'~is~not~inside~the~'#2'~path. }
- { The~key~'#1'~cannot~be~expressed~relative~to~path~'#2'. }
-\msg_new:nnnn { keys } { boolean-values-only }
- { Key~'#1'~accepts~boolean~values~only. }
- { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. }
-\msg_new:nnnn { keys } { choice-unknown }
- { Key~'#1'~accepts~only~a~fixed~set~of~choices. }
- {
- The~key~'#1'~only~accepts~predefined~values,~
- and~'#2'~is~not~one~of~these.
- }
-\msg_new:nnnn { keys } { unknown }
- { The~key~'#1'~is~unknown~and~is~being~ignored. }
- {
- The~module~'#2'~does~not~have~a~key~called~'#1'.\\
- Check~that~you~have~spelled~the~key~name~correctly.
- }
-\msg_new:nnnn { keys } { nested-choice-key }
- { Attempt~to~define~'#1'~as~a~nested~choice~key. }
- {
- The~key~'#1'~cannot~be~defined~as~a~choice~as~the~parent~key~'#2'~is~
- itself~a~choice.
- }
-\msg_new:nnnn { keys } { value-forbidden }
- { The~key~'#1'~does~not~take~a~value. }
- {
- The~key~'#1'~should~be~given~without~a~value.\\
- The~value~'#2'~was~present:~the~key~will~be~ignored.
- }
-\msg_new:nnnn { keys } { value-required }
- { The~key~'#1'~requires~a~value. }
- {
- The~key~'#1'~must~have~a~value.\\
- No~value~was~present:~the~key~will~be~ignored.
- }
-\msg_new:nnn { keys } { show-key }
- {
- The~key~#1~
- \tl_if_empty:nTF {#2}
- { is~undefined. }
- { has~the~properties: #2 . }
- }
-\prop_gput:Nnn \g_msg_module_name_prop { keys } { LaTeX }
-\prop_gput:Nnn \g_msg_module_type_prop { keys } { }
-% \end{macrocode}
-%
-% \begin{macrocode}
-%</package>
-% \end{macrocode}
-%
-%\end{implementation}
-%
-%\PrintIndex