% \iffalse %% File: l3keys.dtx Copyright (C) 2009-2010 LaTeX3 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 %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the ``expl3 bundle'' (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX Project Team. %% %% ----------------------------------------------------------------------- %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3keys.dtx 2082 2010-11-11 11:34:57Z joseph $ {L3 Experimental key-value support} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{l3doc} \begin{document} \DocInput{l3keys.dtx} \end{document} % % \fi % % \title{The \textsf{l3keys} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Key--value support} % \author{\Team} % \date{\filedate} % \maketitle % %\begin{documentation} % % The key--value method is a popular system for creating large numbers % of settings for controlling function or package behaviour. For the % user, the system normally results in input of the form %\begin{verbatim} % \PackageControlMacro{ % key-one = value one, % key-two = value two % } %\end{verbatim} % or %\begin{verbatim} % \PackageMacro[ % key-one = value one, % key-two = value two % ]{argument}. %\end{verbatim} % For the programmer, the original \pkg{keyval} package gives only % the most basic interface for this work. All key macros have to be % created one at a time, and as a result the \pkg{kvoptions} and % \pkg{xkeyval} packages have been written to extend the ease of % creating keys. A very different approach has been provided by % the \pkg{pgfkeys} package, which uses a key--value list to % generate keys. % % The \pkg{l3keys} package is aimed at creating a programming % interface for key--value controls in \LaTeX3. Keys are % created using a key--value interface, in a similar manner to % \pkg{pgfkeys}. Each key is created by setting one or more % \emph{properties} of the key: %\begin{verbatim} % \keys_define:nn { module } % key-one .code:n = code including parameter #1, % key-two .tl_set:N = \l_module_store_tl % } %\end{verbatim} % These values can then be set as with other key--value approaches: %\begin{verbatim} % \keys_set:nn { module } % key-one = value one, % key-two = value two % } %\end{verbatim} % % At a document level, \cs{keys_set:nn} is used within a % document function. For \LaTeXe, a generic set up function could be % created with %\begin{verbatim} % \newcommand*\SomePackageSetup[1]{% % \@nameuse{keys_set:nn}{module}{#1}% % } %\end{verbatim} % or to use key--value input as the optional argument for a macro: %\begin{verbatim} % \newcommand*\SomePackageMacro[2][]{% % \begingroup % \@nameuse{keys_set:nn}{module}{#1}% % % Main code for \SomePackageMacro % \endgroup % } %\end{verbatim} % The same concepts using \pkg{xparse} for \LaTeX3 use: %\begin{verbatim} % \DeclareDocumentCommand \SomePackageSetup { m } { % \keys_set:nn { module } { #1 } % } % \DeclareDocumentCommand \SomePackageMacro { o m } { % \group_begin: % \keys_set:nn { module } { #1 } % % Main code for \SomePackageMacro % \group_end: % } %\end{verbatim} % % Key names may contain any tokens, as they are handled internally % using \cs{tl_to_str:n}. As will be discussed in % section~\ref{sec:subdivision}, it is suggested that the character % `\texttt{/}' is reserved for sub-division of keys into logical % groups. Macros are \emph{not} expanded when creating key names, % and so %\begin{verbatim} % \tl_set:Nn \l_module_tmp_tl { key } % \keys_define:nn { module } { % \l_module_tmp_tl .code:n = code % } %\end{verbatim} % will create a key called \cs{l_module_tmp_tl}, and not one called % \texttt{key}. % %\section{Creating keys} % %\begin{function}{\keys_define:nn} % \begin{syntax} % "\keys_define:nn" \Arg{module} \Arg{keyval list} % \end{syntax} % Parses the and defines the keys listed there for % . The name should be a text value, but there are % no restrictions on the nature of the text. In practice the % should be chosen to be unique to the module in question % (unless deliberately adding keys to an existing module). % % The 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: % } % \end{verbatim} % where the properties of the key begin from the \texttt{.} after % the key name. % % The \cs{keys_define:nn} function does not skip spaces in the % input, and does not check the category codes for \texttt{,} and % \texttt{=} tokens. This means that it is intended for use with % code blocks and other environments where spaces are ignored. %\end{function} % %\begin{function}{ % .bool_set:N | % .bool_gset:N %} % \begin{syntax} % .bool_set:N = % \end{syntax} % Defines to set to (which must be either % \texttt{true} or \texttt{false}). Here, is a \LaTeX3 % boolean variable (\emph{i.e}.~created using \cs{bool_new:N}). % If the variable does not exist, it will be created at the point % that the key is set up. %\end{function} % %\begin{function}{.choice:} % \begin{syntax} % .choice: % \end{syntax} % Sets to act as a multiple choice key. Each valid choice % for must then be created, as discussed in % section~\ref{sec:choice}. %\end{function} % %\begin{function}{ % .choice_code:n | % .choice_code:x %} % \begin{syntax} % .choice_code:n = % \end{syntax} % Stores for use when \texttt{.generate_choices:n} creates one % or more choice sub-keys of the current key. Inside , % \cs{l_keys_choice_tl} contains the name of the choice made, and % \cs{l_keys_choice_int} is the position of the choice in the list % given to \texttt{.generate_choices:n}. Choices are discussed in % detail in section~\ref{sec:choice}. %\end{function} % %\begin{function}{ % .code:n | % .code:x % } % \begin{syntax} % .code:n = % \end{syntax} % Stores the for execution when is called. The can % include one parameter ("#1"), which will be the given for the % . The \texttt{.code:x} variant will expand at the point % where the is created. %\end{function} % %\begin{function}{ % .default:n | % .default:V % } % \begin{syntax} % .default:n = % \end{syntax} % Creates a value for , which is used if no value is % given. This will be used if only the key name is given, but not if % a blank is given: % \begin{verbatim} % \keys_define:nn { module } { % key .code:n = Hello #1, % key .default:n = World % } % \keys_set:nn { module} { % key = Fred, % Prints 'Hello Fred' % key, % Prints 'Hello World' % key = , % Prints 'Hello ' % } % \end{verbatim} % \begin{texnote} % The is stored as a token list variable, and therefore % should not contain unescaped "#" tokens. % \end{texnote} %\end{function} % %\begin{function}{ % .dim_set:N | % .dim_set:c | % .dim_gset:N | % .dim_gset:c | %} % \begin{syntax} % .dim_set:N = % \end{syntax} % Sets to store the value it is given in . Here, % is a \LaTeX3 \texttt{dim} variable % (\emph{i.e}.~created using \cs{dim_new:N}) or a \LaTeXe\ % \texttt{dimen} (\emph{i.e} created using \cs{newdimen}). If the % variable does not exist, it will be created at the point that the % key is set up. %\end{function} % %\begin{function}{ % .fp_set:N | % .fp_set:c | % .fp_gset:N | % .fp_gset:c | %} % \begin{syntax} % .fp_set:N = % \end{syntax} % Sets to store the value it is given in . Here, % is a \LaTeX3 \texttt{fp} variable % (\emph{i.e}.~created using \cs{fp_new:N}). If the % variable does not exist, it will be created at the point that the % key is set up. %\end{function} % %\begin{function}{.generate_choices:n} % \begin{syntax} % .generate_choices:n = % \end{syntax} % Makes a multiple choice key, accepting the choices specified % in . Each choice will execute code which should % previously have been defined using \texttt{.choice_code:n} or % \texttt{.choice_code:x}. Choices are discussed in detail in % section~\ref{sec:choice}. %\end{function} % %\begin{function}{ % .int_set:N | % .int_set:c | % .int_gset:N | % .int_gset:c | %} % \begin{syntax} % .int_set:N = % \end{syntax} % Sets to store the value it is given in . Here, % is a \LaTeX3 \texttt{int} variable % (\emph{i.e}.~created using \cs{int_new:N}) or a \LaTeXe\ % \texttt{count} (\emph{i.e} created using \cs{newcount}). If the % variable does not exist, it will be created at the point that the % key is set up. %\end{function} % %\begin{function}{ % .meta:n | % .meta:x %} % \begin{syntax} % .meta:n = % \end{syntax} % Makes a meta-key, which will set in % one go. If is given with a value at the time the key % is used, then the value will be passed through to the subsidiary % for processing (as "#1"). %\end{function} % %\begin{function}{ % .skip_set:N | % .skip_set:c | % .skip_gset:N | % .skip_gset:c | %} % \begin{syntax} % .skip_set:N = % \end{syntax} % Sets to store the value it is given in , which is % created if it does not already exist. Here, % is a \LaTeX3 \texttt{skip} variable % (\emph{i.e}.~created using \cs{skip_new:N}) or a \LaTeXe\ % \texttt{skip} (\emph{i.e} created using \cs{newskip}). If the % variable does not exist, it will be created at the point that the % key is set up. %\end{function} % %\begin{function}{ % .tl_set:N | % .tl_set:c | % .tl_set_x:N | % .tl_set_x:c | % .tl_gset:N | % .tl_gset:c | % .tl_gset_x:N | % .tl_gset_x:c | %} % \begin{syntax} % .tl_set:N = % \end{syntax} % Sets to store the value it is given in , % which is created if it does not already exist. Here, % is a \LaTeX3 \texttt{tl} variable % (\emph{i.e}.~created using \cs{tl_new:N}) or a \LaTeXe\ % macro with no arguments (\emph{i.e}.~created using % \cs{newcommand} or \cs{def}). If the variable does not exist, it % will be created at the point that the key is set up. The \texttt{x} % variants perform an \texttt{x} expansion at the time the % passed to the is saved to the . %\end{function} % %\begin{function}{ % .value_forbidden: | % .value_required: | % } % \begin{syntax} % .value_forbidden: % \end{syntax} % Flags for forbidding and requiring a for . Giving a % for a which has the \texttt{.value_forbidden:} % property set will result in an error. In the same way, if a has % the \texttt{.value_required:} property set then a must be % given when the is used. %\end{function} % %\section{Sub-dividing keys} %\label{sec:subdivision} % % When creating large numbers of keys, it may be desirable to divide % them into several sub-groups for a given module. This can be achieved % either by adding a sub-division to the module name: %\begin{verbatim} % \keys_define:nn { module / subgroup } { % key .code:n = code % } %\end{verbatim} % or to the key name: %\begin{verbatim} % \keys_define:nn { module } { % subgroup / key .code:n = code % } %\end{verbatim} % As illustrated, the best choice of token for sub-dividing keys in % this way is `\texttt{/}'. 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{module/subgroup/key}. % % As will be illustrated in the next section, this subdivision is % particularly relevant to making multiple choices. % %\subsection{Multiple choices} %\label{sec:choice} % % Multiple choices are created by setting the \texttt{.choice:} % property: %\begin{verbatim} % \keys_define:nn { module } { % 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 choices. Here, the keys can share the same code, and can % be rapidly created using the \texttt{.choice_code:n} and % \texttt{.generate_choices:n} properties: %\begin{verbatim} % \keys_define:nn { module } { % key .choice_code:n = { % You~gave~choice~``\int_use:N \l_keys_choice_tl'',~ % which~is~in~position~ % \int_use:N\l_keys_choice_int\space % in~the~list. % }, % key .generate_choices:n = { % choice-a, choice-b, choice-c % } % } %\end{verbatim} % Following common computing practice, \cs{l_keys_choice_int} is % indexed from \(0\) (as an offset), so that the value of % \cs{l_keys_choice_int} for the first choice in a list will be % zero. This means that \cs{l_keys_choice_int} can be used directly % with \cs{if_case:w} and so on. % %\begin{variable}{ % \l_keys_choice_int | % \l_keys_choice_tl %} % Inside the code block for a choice generated using % \texttt{.generate_choice:}, 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 \(0\). %\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 { module } { % key .choice:n, % 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{.generate_choices:n} % (\emph{i.e}.~anything might happen!). % %\section{Setting keys} % %\begin{function}{ % \keys_set:nn | % \keys_set:nV | % \keys_set:nv %} % \begin{syntax} % "\keys_set:nn" \Arg{module} \Arg{keyval list} % \end{syntax} % Parses the , and sets those keys which are defined % for . The behaviour on finding an unknown key can be % set by defining a special \texttt{unknown} key: this will be % illustrated later. In contrast to \cs{keys_define:nn}, this function % does check category codes and ignore spaces, and is therefore % suitable for user input. %\end{function} % % If a key is not known, \cs{keys_set:nn} will look for a special % \texttt{unknown} key for the same module. This mechanism can be % used to create new keys from user input. %\begin{verbatim} % \keys_define:nn { module } { % unknown .code:n = % You~tried~to~set~key~'\l_keys_path_tl'~to~'#1' % } %\end{verbatim} % %\begin{variable}{\l_keys_key_tl} % When processing an unknown key, the name of the key is available % as \cs{l_keys_key_tl}. Note that this will have been processed % using \cs{tl_to_str:N}. The value passed to the key (if any) is % available as the macro parameter "#1". %\end{variable} % %\subsection{Examining keys: internal representation} % %\begin{function}{\keys_if_exist:nn / (TF)} % \begin{syntax} % "\keys_if_exist:nnTF" \Arg{module} \Arg{key} \Arg{true code} % ~~~~\Arg{false code} % \end{syntax} % Tests if exists for , \emph{i.e}.~if any code has % been defined for . % \begin{texnote} % The function works by testing for the existence of the internal % function \cs{keys > /.cmd:n}. % \end{texnote} %\end{function} % %\begin{function}{\keys_show:nn} % \begin{syntax} % "\keys_show:nn" \Arg{module} \Arg{key} % \end{syntax} % Shows the internal representation of a . % \begin{texnote} % Keys are stored as functions with names of the format % \cs{keys > /.cmd:n}. % \end{texnote} %\end{function} % %\section{Internal functions} % %\begin{function}{\keys_bool_set:Nn} % \begin{syntax} % "\keys_bool_set:Nn" \marg{scope} % \end{syntax} % Creates code to set when is given, with setting using % (empty or \texttt{g} for local or global, % respectively). should be a \LaTeX3 boolean variable. %\end{function} % %\begin{function}{\keys_choice_code_store:x} % \begin{syntax} % "\keys_choice_code_store:x" % \end{syntax} % Stores for later use by \texttt{.generate_code:n}. %\end{function} % %\begin{function}{\keys_choice_make:} % \begin{syntax} % "\keys_choice_make:" % \end{syntax} % Makes a choice key. %\end{function} % %\begin{function}{\keys_choices_generate:n} % \begin{syntax} % "\keys_choices_generate:n" \Arg{comma list} % \end{syntax} % Makes choices for . %\end{function} % %\begin{function}{\keys_choice_find:n} % \begin{syntax} % "\keys_choice_find:n" \Arg{choice} % \end{syntax} % Searches for as a sub-key of . %\end{function} % %\begin{function}{ % \keys_cmd_set:nn | % \keys_cmd_set:nx %} % \begin{syntax} % "\keys_cmd_set:nn" \Arg{path} \Arg{code} % \end{syntax} % Creates a function for using . %\end{function} % %\begin{function}{ % \keys_default_set:n | % \keys_default_set:V %} % \begin{syntax} % "\keys_default_set:n" \Arg{default} % \end{syntax} % Sets for . %\end{function} % %\begin{function}{ % \keys_define_elt:n | % \keys_define_elt:nn %} % \begin{syntax} % "\keys_define_elt:nn" \Arg{key} \Arg{value} % \end{syntax} % Processing functions for key--value pairs when defining keys. %\end{function} % %\begin{function}{\keys_define_key:n} % \begin{syntax} % "\keys_define_key:n" \Arg{key} % \end{syntax} % Defines . %\end{function} % %\begin{function}{\keys_execute:} % \begin{syntax} % "\keys_execute:" % \end{syntax} % Executes (where the name of the will be stored % internally). %\end{function} % %\begin{function}{\keys_execute_unknown:} % \begin{syntax} % "\keys_execute_unknown:" % \end{syntax} % Handles unknown names. %\end{function} % %\begin{function}{\keys_if_value_requirement:nTF / (EXP)} % \begin{syntax} % "\keys_if_value_requirement:nTF" \Arg{requirement} % ~~~~\Arg{true code} \Arg{false code} % \end{syntax} % Check if applies to . %\end{function} % %\begin{function}{ % \keys_meta_make:n | % \keys_meta_make:x %} % \begin{syntax} % "\keys_meta_make:n" \Arg{keys} % \end{syntax} % Makes a meta-key to set . %\end{function} % %\begin{function}{\keys_property_find:n} % \begin{syntax} % "\keys_property_find:n" \Arg{key} % \end{syntax} % Separates from . %\end{function} % %\begin{function}{ % \keys_property_new:nn | % \keys_property_new_arg:nn %} % \begin{syntax} % "\keys_property_new:nn" \Arg{property} \Arg{code} % \end{syntax} % Makes a new expanding to . The \texttt{arg} % version makes properties with one argument. %\end{function} % %\begin{function}{\keys_property_undefine:n} % \begin{syntax} % "\keys_property_undefine:n" \Arg{property} % \end{syntax} % Deletes of . %\end{function} % %\begin{function}{ % \keys_set_elt:n | % \keys_set_elt:nn %} % \begin{syntax} % "\keys_set_elt:nn" \Arg{key} \Arg{value} % \end{syntax} % Processing functions for key--value pairs when setting keys. %\end{function} % %\begin{function}{\keys_tmp:w} % \begin{syntax} % "\keys_tmp:w" % \end{syntax} % Used to store to execute a . %\end{function} % %\begin{function}{\keys_value_or_default:n} % \begin{syntax} % "\keys_value_or_default:n" \Arg{value} % \end{syntax} % Sets \cs{l_keys_value_tl} to , or if % was not given and if is available. %\end{function} % %\begin{function}{\keys_value_requirement:n} % \begin{syntax} % "\keys_value_requirement:n" \Arg{requirement} % \end{syntax} % Sets to have concerning . %\end{function} % %\begin{function}{ % \keys_variable_set:NnNN | % \keys_variable_set:cnNN | %} % \begin{syntax} % "\keys_variable_set:NnNN" % \end{syntax} % Sets to assign to . The (blank % for local, \texttt{g} for global) and (\texttt{tl}, % \texttt{int}, etc.) are given explicitly. %\end{function} % %\section{Variables and constants} % %\begin{variable}{ % \c_keys_properties_root_tl | % \c_keys_root_tl %} % The root paths for keys and properties, used to generate the % names of the functions which store these items. %\end{variable} % %\begin{variable}{ % \c_keys_value_forbidden_tl | % \c_keys_value_required_tl %} % Marker text containers: by storing the values the code can make % comparisons slightly faster. %\end{variable} % %\begin{variable}{\l_keys_choice_code_tl} % Used to transfer code from storage when making multiple choices. %\end{variable} % %\begin{variable}{ % \l_keys_module_tl | % \l_keys_path_tl | % \l_keys_property_tl %} % Various key paths need to be stored. These are flexible items % that are set during the key reading process. %\end{variable} % %\begin{variable}{\l_keys_no_value_bool} % A marker for `no value' as key input. %\end{variable} % %\begin{variable}{\l_keys_value_tl} % Holds the currently supplied value, in a token register as % there may be "#" tokens. %\end{variable} % %\end{documentation} % %\begin{implementation} % % The usual preliminaries. % \begin{macrocode} %<*package> \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} \package_check_loaded_expl: % %<*initex|package> % \end{macrocode} % %\subsubsection{Variables and constants} % %\begin{macro}{\c_keys_root_tl} %\begin{macro}{\c_keys_properties_root_tl} % Where the keys are really stored. % \begin{macrocode} \tl_const:Nn \c_keys_root_tl { keys~>~ } \tl_const:Nn \c_keys_properties_root_tl { keys_properties } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\c_keys_value_forbidden_tl} %\begin{macro}{\c_keys_value_required_tl} % Two marker token lists. % \begin{macrocode} \tl_const:Nn \c_keys_value_forbidden_tl { forbidden } \tl_const:Nn \c_keys_value_required_tl { required } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\l_keys_choice_int} %\begin{macro}{\l_keys_choice_tl} % Used for the multiple choice system. % \begin{macrocode} \int_new:N \l_keys_choice_int \tl_new:N \l_keys_choice_tl % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\l_keys_choice_code_tl} % When creating multiple choices, the code is stored here. % \begin{macrocode} \tl_new:N \l_keys_choice_code_tl % \end{macrocode} %\end{macro} % %\begin{macro}{\l_keys_key_tl} %\begin{macro}{\l_keys_path_tl} %\begin{macro}{\l_keys_property_tl} % Storage for the current key name and the path of the key (key name % plus module name). % \begin{macrocode} \tl_new:N \l_keys_key_tl \tl_new:N \l_keys_path_tl \tl_new:N \l_keys_property_tl % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\l_keys_module_tl} % The module for an entire set of keys. % \begin{macrocode} \tl_new:N \l_keys_module_tl % \end{macrocode} %\end{macro} % %\begin{macro}{\l_keys_no_value_bool} % To indicate that no value has been given. % \begin{macrocode} \bool_new:N \l_keys_no_value_bool % \end{macrocode} %\end{macro} % %\begin{macro}{\l_keys_value_tl} % A token variable for the given value. % \begin{macrocode} \tl_new:N \l_keys_value_tl % \end{macrocode} %\end{macro} % %\subsubsection{Internal functions} % %\begin{macro}{\keys_bool_set:Nn} % Boolean keys are really just choices, but all done by hand. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_bool_set:Nn #1#2 { \keys_cmd_set:nx { \l_keys_path_tl / true } { \exp_not:c { bool_ #2 set_true:N } \exp_not:N #1 } \keys_cmd_set:nx { \l_keys_path_tl / false } { \exp_not:N \use:c { bool_ #2 set_false:N } \exp_not:N #1 } \keys_choice_make: \cs_if_exist:NF #1 { \bool_new:N #1 } \keys_default_set:n { true } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_choice_code_store:x} % The code for making multiple choices is stored in a token list as there should % not be any "#" tokens. % \begin{macrocode} \cs_new_protected:Npn \keys_choice_code_store:x #1 { \tl_set:cx { \c_keys_root_tl \l_keys_path_tl .choice_code_tl } {#1} } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_choice_find:n} % Executing a choice has two parts. First, try the choice given, then % if that fails call the unknown key. That will exist, as it is created % when a choice is first made. So there is no need for any escape code. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_choice_find:n #1 { \keys_execute_aux:nn { \l_keys_path_tl / \tl_to_str:n {#1} } { \keys_execute_aux:nn { \l_keys_path_tl / unknown } { } } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_choice_make:} % To make a choice from a key, two steps: set the code, and set the % unknown key. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_choice_make: { \keys_cmd_set:nn { \l_keys_path_tl } { \keys_choice_find:n {##1} } \keys_cmd_set:nn { \l_keys_path_tl / unknown } { \msg_kernel_error:nnxx { keys } { choice-unknown } { \l_keys_path_tl } {##1} } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_choices_generate:n} %\begin{macro}[aux]{\keys_choices_generate_aux:n} % Creating multiple-choices means setting up the ``indicator'' code, % then applying whatever the user wanted. % \begin{macrocode} \cs_new_protected:Npn \keys_choices_generate:n #1 { \keys_choice_make: \int_zero:N \l_keys_choice_int \cs_if_exist:cTF { \c_keys_root_tl \l_keys_path_tl .choice_code_tl } { \tl_set:Nv \l_keys_choice_code_tl { \c_keys_root_tl \l_keys_path_tl .choice_code_tl } }{ \msg_kernel_error:nnx { keys } { generate-choices-before-code } { \l_keys_path_tl } } \clist_map_function:nN {#1} \keys_choices_generate_aux:n } \cs_new_protected_nopar:Npn \keys_choices_generate_aux:n #1 { \keys_cmd_set:nx { \l_keys_path_tl / #1 } { \exp_not:n { \tl_set:Nn \l_keys_choice_tl } {#1} \exp_not:n { \int_set:Nn \l_keys_choice_int } { \int_use:N \l_keys_choice_int } \exp_not:V \l_keys_choice_code_tl } \int_incr:N \l_keys_choice_int } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\keys_cmd_set:nn} %\begin{macro}{\keys_cmd_set:nx} %\begin{macro}[aux]{\keys_cmd_set_aux:n} % Creating a new command means setting properties and then creating % a function with the correct number of arguments. % \begin{macrocode} \cs_new_protected:Npn \keys_cmd_set:nn #1#2 { \keys_cmd_set_aux:n {#1} \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:n } \cs_set:Npn 1 {#2} } \cs_new_protected:Npn \keys_cmd_set:nx #1#2 { \keys_cmd_set_aux:n {#1} \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:n } \cs_set:Npx 1 {#2} } \cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1 { \keys_property_undefine:n { #1 .default_tl } \cs_if_free:cT { \c_keys_root_tl #1 .req_tl } { \tl_new:c { \c_keys_root_tl #1 .req_tl } } \tl_clear:c { \c_keys_root_tl #1 .req_tl } } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\keys_default_set:n} %\begin{macro}{\keys_default_set:V} % Setting a default value is easy. % \begin{macrocode} \cs_new_protected:Npn \keys_default_set:n #1 { \cs_if_free:cT { \c_keys_root_tl \l_keys_path_tl .default_tl } { \tl_new:c { \c_keys_root_tl \l_keys_path_tl .default_tl } } \tl_set:cn { \c_keys_root_tl \l_keys_path_tl .default_tl } {#1} } \cs_generate_variant:Nn \keys_default_set:n { V } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\keys_define:nn} %\begin{macro}[aux]{\keys_define_aux:nnn} %\begin{macro}[aux]{\keys_define_aux:onn} % The main key-defining function mainly sets up things for \pkg{l3keyval} % to use. % \begin{macrocode} \cs_new_protected:Npn \keys_define:nn { \keys_define_aux:onn { \l_keys_module_tl } } \cs_new_protected:Npn \keys_define_aux:nnn #1#2#3 { \tl_set:Nn \l_keys_module_tl {#2} \KV_process_no_space_removal_no_sanitize:NNn \keys_define_elt:n \keys_define_elt:nn {#3} \tl_set:Nn \l_keys_module_tl {#1} } \cs_generate_variant:Nn \keys_define_aux:nnn { o } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\keys_define_elt:n} %\begin{macro}{\keys_define_elt:nn} % The element processors for defining keys. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_define_elt:n #1 { \bool_set_true:N \l_keys_no_value_bool \keys_define_elt_aux:nn {#1} { } } \cs_new_protected:Npn \keys_define_elt:nn #1#2 { \bool_set_false:N \l_keys_no_value_bool \keys_define_elt_aux:nn {#1} {#2} } % \end{macrocode} %\end{macro} %\end{macro} %\begin{macro}[aux]{\keys_define_elt_aux:nn} % The auxiliary function does most of the work. % \begin{macrocode} \cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 { \keys_property_find:n {#1} \cs_set_eq:Nc \keys_tmp:w { \c_keys_properties_root_tl \l_keys_property_tl } \cs_if_exist:NTF \keys_tmp:w { \keys_define_key:n {#2} }{ \msg_kernel_error:nnxx { keys } { property-unknown } { \l_keys_property_tl } { \l_keys_path_tl } } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_define_key:n} % Defining a new key means finding the code for the appropriate % property then running it. As properties have signatures, a check % can be made for required values without needing anything set % explicitly. % \begin{macrocode} \cs_new_protected:Npn \keys_define_key:n #1 { \bool_if:NTF \l_keys_no_value_bool { \int_compare:nTF { \exp_args:Nc \cs_get_arg_count_from_signature:N { \l_keys_property_tl } = \c_zero } { \keys_tmp:w }{ \msg_kernel_error:nnxx { key } { property-requires-value } { \l_keys_property_tl } { \l_keys_path_tl } } }{ \keys_tmp:w {#1} } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_execute:} %\begin{macro}{\keys_execute_unknown:} %\begin{macro}[aux]{\keys_execute_aux:nn} % 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! % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_execute: { \keys_execute_aux:nn { \l_keys_path_tl } { \keys_execute_unknown: } } \cs_new_protected_nopar:Npn \keys_execute_unknown: { \keys_execute_aux:nn { \l_keys_module_tl / unknown } { \msg_kernel_error:nnxx { keys } { key-unknown } { \l_keys_path_tl } { \l_keys_module_tl } } } % \end{macrocode} % If there is only one argument required, it is wrapped in braces so % that everything is passed through properly. On the other hand, if more % than one is needed it is down to the user to have put things in % correctly! The use of \cs{q_keys_stop} here means that arguments % do not run away (hence the nine empty groups), but that the module % can clean up the spare groups at the end of executing the key. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_execute_aux:nn #1#2 { \cs_set_eq:Nc \keys_tmp:w { \c_keys_root_tl #1 .cmd:n } \cs_if_exist:NTF \keys_tmp:w { \exp_args:NV \keys_tmp:w \l_keys_value_tl }{ #2 } } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}[TF]{\keys_if_exist:nn} % A check for the existance of a key. This works by looking for the % command function for the key (which ends \texttt{.cmd:n}). % \begin{macrocode} \prg_set_conditional:Nnn \keys_if_exist:nn {TF,T,F} { \cs_if_exist:cTF { \c_keys_root_tl #1 / #2 .cmd:n } { \prg_return_true: }{ \prg_return_false: } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_if_value_requirement:nTF} % To test if a value is required or forbidden. Only one version is % needed, so done by hand. % \begin{macrocode} \cs_new_nopar:Npn \keys_if_value_requirement:nTF #1 { \tl_if_eq:ccTF { c_keys_value_ #1 _tl } { \c_keys_root_tl \l_keys_path_tl .req_tl } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_meta_make:n} %\begin{macro}{\keys_meta_make:x} % To create a met-key, simply set up to pass data through. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_meta_make:n #1 { \exp_last_unbraced:NNo \keys_cmd_set:nn \l_keys_path_tl \exp_after:wN { \exp_after:wN \keys_set:nn \exp_after:wN { \l_keys_module_tl } {#1} } } \cs_new_protected_nopar:Npn \keys_meta_make:x #1 { \keys_cmd_set:nx { \l_keys_path_tl } { \exp_not:N \keys_set:nn { \l_keys_module_tl } {#1} } } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\keys_property_find:n} %\begin{macro}[aux]{\keys_property_find_aux:n} %\begin{macro}[aux]{\keys_property_find_aux:w} % Searching for a property means finding the last ``\texttt{.}'' in % the input, and storing the text before and after it. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_property_find:n #1 { \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } \tl_if_in:nnTF {#1} {.} { \keys_property_find_aux:n {#1} }{ \msg_kernel_error:nnx { keys } { key-no-property } {#1} } } \cs_new_protected_nopar:Npn \keys_property_find_aux:n #1 { \keys_property_find_aux:w #1 \q_stop } \cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop { \tl_if_in:nnTF {#2} { . } { \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} . } \keys_property_find_aux:w #2 \q_stop }{ \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } \tl_set:Nn \l_keys_property_tl { . #2 } } } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\keys_property_new:nn} %\begin{macro}{\keys_property_new_arg:nn} % Creating a new property is simply a case of making the correctly-named % function. % \begin{macrocode} \cs_new_nopar:Npn \keys_property_new:nn #1#2 { \cs_new:cpn { \c_keys_properties_root_tl #1 } {#2} } \cs_new_protected_nopar:Npn \keys_property_new_arg:nn #1#2 { \cs_new:cpn { \c_keys_properties_root_tl #1 } ##1 {#2} } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\keys_property_undefine:n} % Removing a property means undefining it. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_property_undefine:n #1 { \cs_set_eq:cN { \c_keys_root_tl #1 } \c_undefined } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_set:nn} %\begin{macro}{\keys_set:nV} %\begin{macro}{\keys_set:nv} %\begin{macro}{\keys_set_aux:nnn} %\begin{macro}{\keys_set_aux:onn} % The main setting function just does the set up to get \pkg{l3keyval} % to do the hard work. % \begin{macrocode} \cs_new_protected:Npn \keys_set:nn { \keys_set_aux:onn { \l_keys_module_tl } } \cs_generate_variant:Nn \keys_set:nn { nV, nv } \cs_new_protected:Npn \keys_set_aux:nnn #1#2#3 { \tl_set:Nn \l_keys_module_tl {#2} \KV_process_space_removal_sanitize:NNn \keys_set_elt:n \keys_set_elt:nn {#3} \tl_set:Nn \l_keys_module_tl {#1} } \cs_generate_variant:Nn \keys_set_aux:nnn { o } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{\keys_set_elt:n} %\begin{macro}{\keys_set_elt:nn} % The two element processors are almost identical, and pass the data % through to the underlying auxiliary, which does the work. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_set_elt:n #1 { \bool_set_true:N \l_keys_no_value_bool \keys_set_elt_aux:nn {#1} { } } \cs_new_protected:Npn \keys_set_elt:nn #1#2 { \bool_set_false:N \l_keys_no_value_bool \keys_set_elt_aux:nn {#1} {#2} } % \end{macrocode} %\end{macro} %\end{macro} %\begin{macro}[aux]{\keys_set_elt_aux:nn} %\begin{macro}[aux]{\keys_set_elt_aux:} % First, set the current path and add a default if needed. There are % then checks to see if the a value is required or forbidden. If % everything passes, move on to execute the code. % \begin{macrocode} \cs_new_protected:Npn \keys_set_elt_aux:nn #1#2 { \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / \l_keys_key_tl } \keys_value_or_default:n {#2} \keys_if_value_requirement:nTF { required } { \bool_if:NTF \l_keys_no_value_bool { \msg_kernel_error:nnx { keys } { value-required } { \l_keys_path_tl } }{ \keys_set_elt_aux: } }{ \keys_set_elt_aux: } } \cs_new_protected_nopar:Npn \keys_set_elt_aux: { \keys_if_value_requirement:nTF { forbidden } { \bool_if:NTF \l_keys_no_value_bool { \keys_execute: }{ \msg_kernel_error:nnxx { keys } { value-forbidden } { \l_keys_path_tl } { \tl_use:N \l_keys_value_tl } } }{ \keys_execute: } } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{\keys_show:nn} % Showing a key is just a question of using the correct name. % \begin{macrocode} \cs_new_nopar:Npn \keys_show:nn #1#2 { \cs_show:c { \c_keys_root_tl #1 / \tl_to_str:n {#2} .cmd:n } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_tmp:w} % This scratch function is used to actually execute keys. % \begin{macrocode} \cs_new:Npn \keys_tmp:w {} % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_value_or_default:n} % If a value is given, return it as "#1", otherwise send a default if % available. % \begin{macrocode} \cs_new_protected:Npn \keys_value_or_default:n #1 { \tl_set:Nn \l_keys_value_tl {#1} \bool_if:NT \l_keys_no_value_bool { \cs_if_exist:cT { \c_keys_root_tl \l_keys_path_tl .default_tl } { \tl_set:Nv \l_keys_value_tl { \c_keys_root_tl \l_keys_path_tl .default_tl } } } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_value_requirement:n} % Values can be required or forbidden by having the appropriate marker % set. % \begin{macrocode} \cs_new_protected_nopar:Npn \keys_value_requirement:n #1 { \tl_set_eq:cc { \c_keys_root_tl \l_keys_path_tl .req_tl } { c_keys_value_ #1 _tl } } % \end{macrocode} %\end{macro} % %\begin{macro}{\keys_variable_set:NnNN} %\begin{macro}{\keys_variable_set: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_nopar:Npn \keys_variable_set:NnNN #1#2#3#4 { \cs_if_exist:NF #1 { \use:c { #2 _new:N } #1 } \keys_cmd_set:nx { \l_keys_path_tl } { \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1} } } \cs_generate_variant:Nn \keys_variable_set:NnNN { c } % \end{macrocode} %\end{macro} %\end{macro} % %\subsubsection{Properties} % %\begin{macro}{.bool_set:N} %\begin{macro}{.bool_gset:N} % One function for this. % \begin{macrocode} \keys_property_new_arg:nn { .bool_set:N } { \keys_bool_set:Nn #1 { } } \keys_property_new_arg:nn { .bool_gset:N } { \keys_bool_set:Nn #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} \keys_property_new:nn { .choice: } { \keys_choice_make: } % \end{macrocode} %\end{macro} % %\begin{macro}{.choice_code:n} %\begin{macro}{.choice_code:x} % Storing the code for choices, using \cs{exp_not:n} to avoid needing % two internal functions. % \begin{macrocode} \keys_property_new_arg:nn { .choice_code:n } { \keys_choice_code_store:x { \exp_not:n {#1} } } \keys_property_new_arg:nn { .choice_code:x } { \keys_choice_code_store:x {#1} } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{.code:n} %\begin{macro}{.code:x} % Creating code is simply a case of passing through to the underlying % \texttt{set} function. % \begin{macrocode} \keys_property_new_arg:nn { .code:n } { \keys_cmd_set:nn { \l_keys_path_tl } {#1} } \keys_property_new_arg:nn { .code:x } { \keys_cmd_set:nx { \l_keys_path_tl } {#1} } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{.default:n} %\begin{macro}{.default:V} % Expansion is left to the internal functions. % \begin{macrocode} \keys_property_new_arg:nn { .default:n } { \keys_default_set:n {#1} } \keys_property_new_arg:nn { .default:V } { \keys_default_set:V #1 } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{.dim_set:N} %\begin{macro}{.dim_set:c} %\begin{macro}{.dim_gset:N} %\begin{macro}{.dim_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} \keys_property_new_arg:nn { .dim_set:N } { \keys_variable_set:NnNN #1 { dim } { } n } \keys_property_new_arg:nn { .dim_set:c } { \keys_variable_set:cnNN {#1} { dim } { } n } \keys_property_new_arg:nn { .dim_gset:N } { \keys_variable_set:NnNN #1 { dim } g n } \keys_property_new_arg:nn { .dim_gset:c } { \keys_variable_set:cnNN {#1} { dim } g n } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{.fp_set:N} %\begin{macro}{.fp_set:c} %\begin{macro}{.fp_gset:N} %\begin{macro}{.fp_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} \keys_property_new_arg:nn { .fp_set:N } { \keys_variable_set:NnNN #1 { fp } { } n } \keys_property_new_arg:nn { .fp_set:c } { \keys_variable_set:cnNN {#1} { fp } { } n } \keys_property_new_arg:nn { .fp_gset:N } { \keys_variable_set:NnNN #1 { fp } g n } \keys_property_new_arg:nn { .fp_gset:c } { \keys_variable_set:cnNN {#1} { fp } g n } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{.generate_choices:n} % Making choices is easy. % \begin{macrocode} \keys_property_new_arg:nn { .generate_choices:n } { \keys_choices_generate:n {#1} } % \end{macrocode} %\end{macro} % %\begin{macro}{.int_set:N} %\begin{macro}{.int_set:c} %\begin{macro}{.int_gset:N} %\begin{macro}{.int_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} \keys_property_new_arg:nn { .int_set:N } { \keys_variable_set:NnNN #1 { int } { } n } \keys_property_new_arg:nn { .int_set:c } { \keys_variable_set:cnNN {#1} { int } { } n } \keys_property_new_arg:nn { .int_gset:N } { \keys_variable_set:NnNN #1 { int } g n } \keys_property_new_arg:nn { .int_gset:c } { \keys_variable_set:cnNN {#1} { int } g n } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{.meta:n} %\begin{macro}{.meta:x} % Making a meta is handled internally. % \begin{macrocode} \keys_property_new_arg:nn { .meta:n } { \keys_meta_make:n {#1} } \keys_property_new_arg:nn { .meta:x } { \keys_meta_make:x {#1} } % \end{macrocode} %\end{macro} %\end{macro} % %\begin{macro}{.skip_set:N} %\begin{macro}{.skip_set:c} %\begin{macro}{.skip_gset:N} %\begin{macro}{.skip_gset:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} \keys_property_new_arg:nn { .skip_set:N } { \keys_variable_set:NnNN #1 { skip } { } n } \keys_property_new_arg:nn { .skip_set:c } { \keys_variable_set:cnNN {#1} { skip } { } n } \keys_property_new_arg:nn { .skip_gset:N } { \keys_variable_set:NnNN #1 { skip } g n } \keys_property_new_arg:nn { .skip_gset:c } { \keys_variable_set:cnNN {#1} { skip } g n } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{.tl_set:N} %\begin{macro}{.tl_set:c} %\begin{macro}{.tl_set_x:N} %\begin{macro}{.tl_set_x:c} %\begin{macro}{.tl_gset:N} %\begin{macro}{.tl_gset:c} %\begin{macro}{.tl_gset_x:N} %\begin{macro}{.tl_gset_x:c} % Setting a variable is very easy: just pass the data along. % \begin{macrocode} \keys_property_new_arg:nn { .tl_set:N } { \keys_variable_set:NnNN #1 { tl } { } n } \keys_property_new_arg:nn { .tl_set:c } { \keys_variable_set:cnNN {#1} { tl } { } n } \keys_property_new_arg:nn { .tl_set_x:N } { \keys_variable_set:NnNN #1 { tl } { } x } \keys_property_new_arg:nn { .tl_set_x:c } { \keys_variable_set:cnNN {#1} { tl } { } x } \keys_property_new_arg:nn { .tl_gset:N } { \keys_variable_set:NnNN #1 { tl } g n } \keys_property_new_arg:nn { .tl_gset:c } { \keys_variable_set:cnNN {#1} { tl } g n } \keys_property_new_arg:nn { .tl_gset_x:N } { \keys_variable_set:NnNN #1 { tl } g x } \keys_property_new_arg:nn { .tl_gset_x:c } { \keys_variable_set:cnNN {#1} { tl } g x } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} %\end{macro} % %\begin{macro}{.value_forbidden:} %\begin{macro}{.value_required:} % These are very similar, so both call the same function. % \begin{macrocode} \keys_property_new:nn { .value_forbidden: } { \keys_value_requirement:n { forbidden } } \keys_property_new:nn { .value_required: } { \keys_value_requirement:n { required } } % \end{macrocode} %\end{macro} %\end{macro} % %\subsubsection{Messages} % % For when there is a need to complain. % \begin{macrocode} \msg_kernel_new:nnnn { keys } { choice-unknown } { Choice~'#2'~unknown~for~key~'#1'. } { The~key~'#1'~takes~a~limited~number~of~values.\\ The~input~given,~'#2',~is~not~on~the~list~accepted. } \msg_kernel_new:nnnn { keys } { generate-choices-before-code } { No~code~available~to~generate~choices~for~key~'#1'. } { \l_msg_coding_error_text_tl Before~using~.generate_choices:n~the~code~should~be~defined\\% with~.choice_code:n~or~.choice_code:x. } \msg_kernel_new:nnnn { keys } { key-no-property } { No~property~given~in~definition~of~key~'#1'. } { \c_msg_coding_error_text_tl Inside~\token_to_str:N \keys_define:nn \c_space_tl each~key~name needs~a~property: \\ ~ ~ #1 . \\ LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property. } \msg_kernel_new:nnnn { keys } { key-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_kernel_new:nnnn { keys } { property-requires-value } { The~property~'#1'~requires~a~value. } { \l_msg_coding_error_text_tl LaTeX~was~asked~to~set~property~'#2'~for~key~'#1'.\\ No~value~was~given~for~the~property,~and~one~is~required. } \msg_kernel_new:nnnn { keys } { property-unknown } { The~key~property~'#1'~is~unknown. } { \l_msg_coding_error_text_tl LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':\\ this~property~is~not~defined. } \msg_kernel_new:nnnn { keys } { value-forbidden } { The~key~'#1'~does~not~taken~a~value. } { The~key~'#1'~should~be~given~without~a~value.\\ LaTeX~will~ignore~the~given~value~'#2'. } \msg_kernel_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. } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % %\end{implementation}