From dac945b204407dae96f70ec228206516093156d7 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 31 Jul 2011 18:27:06 +0000 Subject: l3kernel (5jun11) git-svn-id: svn://tug.org/texlive/trunk@23282 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/source/latex/l3kernel/l3keys.dtx | 1365 ++++++++++++++++++++ 1 file changed, 1365 insertions(+) create mode 100644 Master/texmf-dist/source/latex/l3kernel/l3keys.dtx (limited to 'Master/texmf-dist/source/latex/l3kernel/l3keys.dtx') diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx new file mode 100644 index 00000000000..cbc1fb62a7d --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -0,0 +1,1365 @@ +% \iffalse meta-comment +% +%% File: l3keys.dtx Copyright (C) 2009-2011 The 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 LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3keys.dtx 2478 2011-06-19 21:34:23Z joseph $ + {L3 Experimental key-value interfaces} +% +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% \title{^^A +% The \pkg{l3keys} package\\ Key--value interfaces^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \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} +% +% 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 { 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} will be used within a +% document function, for example +% \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 +% |/| is reserved for sub-division of keys into logical +% groups. Functions and variables 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} +% \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 should be a text value, but +% there are no restrictions on the nature of the text. 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: +% } +% \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 exactly one argument. 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. +% +% \begin{function}{.bool_set:N} +% \begin{syntax} +% \meta{key} .bool_set:N = \meta{boolean} +% \end{syntax} +% Defines \meta{key} to set \meta{boolean} to \meta{value} (which +% must be either \texttt{true} or \texttt{false}). If the variable +% does not exist, it will be created at the point that the key is +% set up. The \meta{boolean} will be assigned locally. +% \end{function} +% +% \begin{function}{.bool_gset:N} +% \begin{syntax} +% \meta{key} .bool_gset:N = \meta{boolean} +% \end{syntax} +% Defines \meta{key} to set \meta{boolean} to \meta{value} (which +% must be either \texttt{true} or \texttt{false}). If the variable +% does not exist, it will be created at the point that the key is +% set up. The \meta{boolean} will be assigned globally. +% \end{function} +% +% \begin{function}{.choice:} +% \begin{syntax} +% \meta{key} .choice: +% \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:choice}. +% \end{function} +% +% \begin{function}{.choice_code:n, .choice_code:x} +% \begin{syntax} +% \meta{key} .choice_code:n = \meta{code} +% \end{syntax} +% Stores \meta{code} for use when \texttt{.generate_choices:n} creates +% one or more choice sub-keys of the current key. Inside \meta{code}, +% \cs{l_keys_choice_tl} will expand to the name of the choice made, and +% \cs{l_keys_choice_int} will be 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} +% \meta{key} .code:n = \meta{code} +% \end{syntax} +% Stores the \meta{code} for execution when \meta{key} is used. The +% The \meta{code} can include one parameter ("#1"), which will be the +% \meta{value} given for the \meta{key}. The \texttt{x}-type variant +% will expand \meta{code} at the point where the \meta{key} is +% created. +% \end{function} +% +% \begin{function}{.default:n, .default:V} +% \begin{syntax} +% \meta{key} .default:n = \meta{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 { 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} +% \end{function} +% +% \begin{function}{.dim_set:N, .dim_set: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 +% will be created at the point that the key is set up. The +% \meta{dimension} will be assigned locally. +% \end{function} +% +% \begin{function}{.dim_gset:N, .dim_gset:c} +% \begin{syntax} +% \meta{key} .dim_gset: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 +% will be created at the point that the key is set up. The +% \meta{dimension} will be assigned globally. +% \end{function} +% +% \begin{function}{.fp_set:N, .fp_set: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 integer expression). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{integer} will be assigned locally. +% \end{function} +% +% \begin{function}{.fp_gset:N, .fp_gset:c} +% \begin{syntax} +% \meta{key} .fp_gset:N = \meta{floating point} +% \end{syntax} +% Defines \meta{key} to set \meta{floating-point} to \meta{value} +% (which must a integer expression). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{integer} will be assigned globally. +% \end{function} +% +% \begin{function}{.generate_choices:n} +% \begin{syntax} +% \meta{key} .generate_choices:n = \Arg{list} +% \end{syntax} +% This property will mark \meta{key} as a multiple choice key, +% and will use the \meta{list} to define the choices. The \meta{list} +% should consist of a comma-separated list of choice names. Each +% choice will be set up to execute \meta{code} as set 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} +% \begin{syntax} +% \meta{key} .int_set:N = \meta{integer} +% \end{syntax} +% Defines \meta{key} to set \meta{integer} to \meta{value} (which +% must a integer expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{integer} will be assigned locally. +% \end{function} +% +% \begin{function}{.int_gset:N, .int_gset:c} +% \begin{syntax} +% \meta{key} .int_gset:N = \meta{integer} +% \end{syntax} +% Defines \meta{key} to set \meta{integer} to \meta{value} (which +% must a integer expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{integer} will be assigned globally. +% \end{function} +% +% \begin{function}{.meta:n, .meta:x} +% \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. If \meta{key} is given with a value at the time the key +% is used, then the value will be passed through to the subsidiary +% \meta{keys} for processing (as |#1|). +% \end{function} +% +% \begin{function}{.skip_set:N, .skip_set:c} +% \begin{syntax} +% \meta{key} .skip_set:N = \meta{skip} +% \end{syntax} +% Defines \meta{key} to set \meta{skip} to \meta{value} (which +% must a skip expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{skip} will be assigned locally. +% \end{function} +% +% \begin{function}{.skip_gset:N, .skip_gset:c} +% \begin{syntax} +% \meta{key} .skip_gset:N = \meta{skip} +% \end{syntax} +% Defines \meta{key} to set \meta{skip} to \meta{value} (which +% must a skip expression). If the variable does not exist, it +% will be created at the point that the key is set up. The +% \meta{skip} will be assigned globally. +% \end{function} +% +% \begin{function}{.tl_set:N, .tl_set: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 will be created at the point that +% the key is set up. The \meta{token list variable} will be assigned +% locally. +% \end{function} +% +% \begin{function}{.tl_gset:N, .tl_gset:c} +% \begin{syntax} +% \meta{key} .tl_gset: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 will be created at the point that +% the key is set up. The \meta{token list variable} will be assigned +% globally. +% \end{function} +% +% \begin{function}{.tl_set_x:N, .tl_set_x:c} +% \begin{syntax} +% \meta{key} .tl_set_x: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{x}-type expansion +% (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{token list variable} will be assigned locally. +% \end{function} +% +% \begin{function}{.tl_gset_x:N, .tl_gset_x:c} +% \begin{syntax} +% \meta{key} .tl_gset_x: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{x}-type expansion +% (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist, +% it will be created at the point that the key is set up. The +% \meta{token list variable} will be assigned globally. +% \end{function} +% +% \begin{function}{.value_forbidden:} +% \begin{syntax} +% \meta{key} .value_forbidden: +% \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. +% \end{function} +% +% \begin{function}{.value_required:} +% \begin{syntax} +% \meta{key} .value_required: +% \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. +% \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 |/|. 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. +% +% \section{Multiple choice keys} +% \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 \c_space_tl +% 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. +% +% \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, \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 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_key_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} +% +% \begin{variable}{\l_keys_path_tl} +% When processing an unknown key, the path of the key used is available +% as \cs{l_keys_path_tl}. Note that this will have been processed +% using \cs{tl_to_str:n}. +% \end{variable} +% +% \section{Utility functions for keys} +% +% \begin{function}[EXP,pTF]{\keys_if_exist:nn} +% \begin{syntax} +% \cs{keys_if_exist:nn} \meta{module} \meta{key} +% \cs{keys_if_exist:nn} \meta{module} \meta{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}. +% The branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth +% of the test and the variant of the function chosen. The logical +% truth of the test is left in the input stream by the predicate +% version. +% \end{function} +% +% \begin{function}{\keys_show:nn} +% \begin{syntax} +% \cs{keys_show:nn} \Arg{module} \Arg{key} +% \end{syntax} +% Shows the function which is used to actually implement a +% \meta{key} for a \meta{module}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3keys} Implementation} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +% +% \end{macrocode} +% +% \subsection{Constants and variables} +% +% \begin{variable}{\c_keys_code_root_tl, \c_keys_vars_root_tl} +% The prefixes for the code and variables of the keys themselves. +% \begin{macrocode} +\tl_const:Nn \c_keys_code_root_tl { key~code~>~ } +\tl_const:Nn \c_keys_vars_root_tl { key~var~>~ } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_keys_props_root_tl} +% The prefix for storing properties. +% \begin{macrocode} +\tl_const:Nn \c_keys_props_root_tl { key~prop~>~ } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_keys_value_forbidden_tl, \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{variable} +% +% \begin{variable}{\l_keys_choice_int, \l_keys_choices_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_choices_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_key_tl} +% The name of a key itself: needed when setting keys. +% \begin{macrocode} +\tl_new:N \l_keys_key_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_module_tl} +% The module for an entire set of keys. +% \begin{macrocode} +\tl_new:N \l_keys_module_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_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_keys_no_value_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_path_tl} +% The \enquote{path} of the current key is stored here: this is +% available to the programmer and so is public. +% \begin{macrocode} +\tl_new:N \l_keys_path_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_keys_property_tl} +% The \enquote{property} begin set for a key at definition time is +% stored here. +% \begin{macrocode} +\tl_new:N \l_keys_property_tl +% \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} +% +% \subsection{The key defining mechanism} +% +% \begin{macro}{\keys_define:nn} +% \begin{macro}[aux]{\keys_define_aux:nnn, \keys_define_aux: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. +% \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:Nx \l_keys_module_tl { \tl_to_str:n {#2} } + \keyval_parse: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} +% +% \begin{macro}[int]{\keys_define_elt:n} +% \begin{macro}[int]{\keys_define_elt:nn} +% \begin{macro}[aux]{\keys_define_elt_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_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} + } +\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 { + \keys_property_find:n {#1} + \cs_if_exist:cTF { \c_keys_props_root_tl \l_keys_property_tl } + { \keys_define_key:n {#2} } + { + \msg_kernel_error:nnxx { keys } { property-unknown } + { \l_keys_property_tl } { \l_keys_path_tl } + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_property_find:n} +% \begin{macro}[aux]{\keys_property_find_aux:w} +% Searching for a property means finding the last |.| in the input, +% and storing the text before and after it. Everything is turned into +% strings, so there is no problem using an \texttt{x}-type expansion. +% \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:w #1 \q_stop } + { \msg_kernel_error:nnx { keys } { key-no-property } {#1} } + } +\cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } + \tl_if_in:nnTF {#2} { . } + { + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . } + \keys_property_find_aux:w #2 \q_stop + } + { \tl_set:Nn \l_keys_property_tl { . #2 } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_define_key:n} +% \begin{macro}[aux]{\keys_define_key_aux: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 +% is missing the earlier tests will have failed. +% \begin{macrocode} +\cs_new_protected:Npn \keys_define_key:n #1 + { + \bool_if:NTF \l_keys_no_value_bool + { + \exp_after:wN \keys_define_key_aux:w + \l_keys_property_tl \q_stop + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } } + { + \msg_kernel_error:nnxx { keys } + { property-requires-value } { \l_keys_property_tl } + { \l_keys_path_tl } + } + } + { \use:c { \c_keys_props_root_tl \l_keys_property_tl } {#1} } + } +\cs_new_protected:Npn \keys_define_key_aux:w #1 : #2 \q_stop + { \tl_if_empty:nTF {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Turning properties into actions} +% +% \begin{macro}[int]{\keys_bool_set:NN} +% 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_nopar:Npn \keys_bool_set:NN #1#2 + { + \cs_if_exist:NF #1 { \bool_new:N #1 } + \keys_choice_make: + \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:c { bool_ #2 set_false:N } \exp_not:N #1 } + \keys_cmd_set:nn { \l_keys_path_tl / unknown } + { + \msg_kernel_error:nnx { keys } { boolean-values-only } + { \l_keys_key_tl } + } + \keys_default_set:n { true } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\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}[int]{\keys_choices_generate:n} +% \begin{macro}[aux]{\keys_choices_generate_aux:n} +% Creating multiple-choices means setting up the \enquote{indicator} +% code, then applying whatever the user wanted. +% \begin{macrocode} +\cs_new_protected:Npn \keys_choices_generate:n #1 + { + \cs_if_exist:cTF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \keys_choice_make: + \int_zero:N \l_keys_choice_int + \clist_map_function:nN {#1} \keys_choices_generate_aux:n + } + { + \msg_kernel_error:nnx { keys } + { generate-choices-before-code } { \l_keys_path_tl } + } + } +\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 + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \int_incr:N \l_keys_choice_int + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_choice_code_store:x} +% The code for making multiple choices is stored in a token list. +% \begin{macrocode} +\cs_new_protected:Npn \keys_choice_code_store:x #1 + { + \cs_if_exist:cF + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + { + \tl_new:c + { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + } + \tl_set:cx { \c_keys_vars_root_tl \l_keys_path_tl .choice~code } + {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_cmd_set:nn, \keys_cmd_set:nx} +% \begin{macro}[aux]{\keys_cmd_set_aux:n} +% Creating a new command means tidying up the properties and then making +% the internal function which actually does the work. +% \begin{macrocode} +\cs_new_protected:Npn \keys_cmd_set:nn #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpn { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected:Npn \keys_cmd_set:nx #1#2 + { + \keys_cmd_set_aux:n {#1} + \cs_set:cpx { \c_keys_code_root_tl #1 } ##1 {#2} + } +\cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1 + { + \tl_clear_new:c { \c_keys_vars_root_tl #1 .default } + \tl_set:cn { \c_keys_vars_root_tl #1 .default } { \q_no_value } + \tl_clear_new:c { \c_keys_vars_root_tl #1 .req } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_default_set:n, \keys_default_set:V} +% Setting a default value is easy. +% \begin{macrocode} +\cs_new_protected:Npn \keys_default_set:n #1 + { \tl_set:cn { \c_keys_vars_root_tl \l_keys_path_tl .default } {#1} } +\cs_generate_variant:Nn \keys_default_set:n { V } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\keys_meta_make:n, \keys_meta_make:x} +% To create a meta-key, simply set up to pass data through. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \keys_meta_make:n #1 + { + \exp_args:NNo \keys_cmd_set:nn \l_keys_path_tl + { \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} +% +% \begin{macro}[int]{\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_vars_root_tl \l_keys_path_tl .req } + { c_keys_value_ #1 _tl } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_variable_set:NnNN, \keys_variable_set:cnNN} +% \begin{macro}[int]{\keys_variable_set:NnN, \keys_variable_set:cnN} +% Setting a variable takes the type and scope separately so that +% it is easy to make a new variable if needed. The three-argument +% version is set up so that the use of |{ }| as an \texttt{N}-type +% variable is only done once! +% \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_new_protected_nopar:Npn \keys_variable_set:NnN #1#2#3 + { \keys_variable_set:NnNN #1 {#2} { } #3 } +\cs_generate_variant:Nn \keys_variable_set:NnNN { c } +\cs_generate_variant:Nn \keys_variable_set:NnN { 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. +% +% \begin{macro}{.bool_set:N} +% \begin{macro}{.bool_gset:N} +% One function for this. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_set:N } #1 + { \keys_bool_set:NN #1 { } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_gset:N } #1 + { \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} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .choice: } + { \keys_choice_make: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.code:n, .code:x} +% Creating code is simply a case of passing through to the underlying +% \texttt{set} function. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .code:n } #1 + { \keys_cmd_set:nn { \l_keys_path_tl } {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .code:x } #1 + { \keys_cmd_set:nx { \l_keys_path_tl } {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.choice_code:n, .choice_code:x} +% Storing the code for choices, using \cs{exp_not:n} to avoid needing +% two internal functions. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:n } #1 + { \keys_choice_code_store:x { \exp_not:n {#1} } } +\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:x } #1 + { \keys_choice_code_store:x {#1} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.default:n, .default:V} +% Expansion is left to the internal functions. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .default:n } #1 + { \keys_default_set:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .default:V } #1 + { \keys_default_set:V #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_nopar:cpn { \c_keys_props_root_tl .dim_set:N } #1 + { \keys_variable_set:NnN #1 { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:c } #1 + { \keys_variable_set:cnN {#1} { dim } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:N } #1 + { \keys_variable_set:NnNN #1 { dim } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:c } #1 + { \keys_variable_set: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_nopar:cpn { \c_keys_props_root_tl .fp_set:N } #1 + { \keys_variable_set:NnN #1 { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:c } #1 + { \keys_variable_set:cnN {#1} { fp } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:N } #1 + { \keys_variable_set:NnNN #1 { fp } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:c } #1 + { \keys_variable_set:cnNN {#1} { fp } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{.generate_choices:n} +% Making choices is easy. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .generate_choices:n } #1 + { \keys_choices_generate: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_nopar:cpn { \c_keys_props_root_tl .int_set:N } #1 + { \keys_variable_set:NnN #1 { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:c } #1 + { \keys_variable_set:cnN {#1} { int } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:N } #1 + { \keys_variable_set:NnNN #1 { int } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:c } #1 + { \keys_variable_set:cnNN {#1} { int } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%\begin{macro}{.meta:n, .meta:x} +% Making a meta is handled internally. +% \begin{macrocode} +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:n } #1 + { \keys_meta_make:n {#1} } +\cs_new_protected:cpn { \c_keys_props_root_tl .meta:x } #1 + { \keys_meta_make:x {#1} } +% \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_nopar:cpn { \c_keys_props_root_tl .skip_set:N } #1 + { \keys_variable_set:NnN #1 { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:c } #1 + { \keys_variable_set:cnN {#1} { skip } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:N } #1 + { \keys_variable_set:NnNN #1 { skip } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:c } #1 + { \keys_variable_set:cnNN {#1} { skip } g n } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{.tl_set:N, .tl_set:c} +% \begin{macro}{.tl_gset:N, .tl_gset:c} +% \begin{macro}{.tl_set_x:N, .tl_set_x:c} +% \begin{macro}{.tl_gset_x:N, .tl_gset_x:c} +% Setting a variable is very easy: just pass the data along. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:N } #1 + { \keys_variable_set:NnN #1 { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:c } #1 + { \keys_variable_set:cnN {#1} { tl } n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:N } #1 + { \keys_variable_set:NnN #1 { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:c } #1 + { \keys_variable_set:cnN {#1} { tl } x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:N } #1 + { \keys_variable_set:NnNN #1 { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g n } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:N } #1 + { \keys_variable_set:NnNN #1 { tl } g x } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:c } #1 + { \keys_variable_set:cnNN {#1} { tl } g x } +% \end{macrocode} +% \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} +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_forbidden: } + { \keys_value_requirement:n { forbidden } } +\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_required: } + { \keys_value_requirement:n { required } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Setting keys} +% +% \begin{macro}{\keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:no} +% \begin{macro}[aux]{\keys_set_aux:nnn, \keys_set_aux:onn} +% A simple wrapper again. +% \begin{macrocode} +\cs_new_protected:Npn \keys_set:nn + { \keys_set_aux:onn { \l_keys_module_tl } } +\cs_new_protected:Npn \keys_set_aux:nnn #1#2#3 + { + \tl_set:Nn \l_keys_module_tl {#2} + \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3} + \tl_set:Nn \l_keys_module_tl {#1} + } +\cs_generate_variant:Nn \keys_set:nn { nV , nv , no } +\cs_generate_variant:Nn \keys_set_aux:nnn { o } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\keys_set_elt:n, \keys_set_elt:nn} +% \begin{macro}[aux]{\keys_set_elt_aux:nn} +% A shared system once again. 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_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} + } +\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} + \bool_if:nTF + { + \keys_if_value_p:n { required } && + \l_keys_no_value_bool + } + { + \msg_kernel_error:nnx { keys } { value-required } + { \l_keys_path_tl } + } + { + \bool_if:nTF + { + \keys_if_value_p:n { forbidden } && + ! \l_keys_no_value_bool + } + { + \msg_kernel_error:nnxx { keys } { value-forbidden } + { \l_keys_path_tl } { \l_keys_value_tl } + } + { \keys_execute: } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\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 + { + \quark_if_no_value:cF { \c_keys_vars_root_tl \l_keys_path_tl .default } + { + \tl_set_eq:Nc \l_keys_value_tl + { \c_keys_vars_root_tl \l_keys_path_tl .default } + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_if_value_p:n} +% To test if a value is required or forbidden. A simple check for +% the existence of the appropriate marker. +% \begin{macrocode} +\prg_new_conditional:Npnn \keys_if_value:n #1 { p } + { + \tl_if_eq:ccTF { c_keys_value_ #1 _tl } + { \c_keys_vars_root_tl \l_keys_path_tl .req } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\keys_execute:} +% \begin{macro}[aux]{\keys_execute_unknown:} +% \begin{macro}[aux]{\keys_execute: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_nopar:Npn \keys_execute: + { \keys_execute:nn { \l_keys_path_tl } { \keys_execute_unknown: } } +\cs_new_nopar:Npn \keys_execute_unknown: + { + \keys_execute:nn { \l_keys_module_tl / unknown } + { + \msg_kernel_error:nnxx { keys } { key-unknown } + { \l_keys_path_tl } { \l_keys_module_tl } + } + } +\cs_new_nopar:Npn \keys_execute:nn #1#2 + { + \cs_if_exist:cTF { \c_keys_code_root_tl #1 } + { + \exp_args:Nno \use:c { \c_keys_code_root_tl #1 } + \l_keys_value_tl + } + {#2} + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \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_nopar:Npn \keys_choice_find:n #1 + { + \keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} } + { \keys_execute:nn { \l_keys_path_tl / unknown } { } } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Utilities} +% +% \begin{macro}[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_keys_code_root_tl #1 / #2 } + { \prg_return_true:} + { \prg_return_false:} + } +% \end{macrocode} +% \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_code_root_tl #1 / \tl_to_str:n {#2} } } +% \end{macrocode} +% \end{macro} +% +% \subsection{Messages} +% +% For when there is a need to complain. +% \begin{macrocode} +\msg_kernel_new:nnnn { keys } { boolean-values-only } + { Key~'#1'~accepts~boolean~values~only. } + { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. } +\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'. } + { + \c_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~\keys_define:nn 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 } { option-unknown } + { Unknown~option~'#1'~for~package~#2. } + { + LaTeX~has~been~asked~to~set~an~option~called~'#1'~ + but~the~#2~package~has~not~created~an~option~with~this~name. + } +\msg_kernel_new:nnnn { keys } { property-requires-value } + { The~property~'#1'~requires~a~value. } + { + \c_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. } + { + \c_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} +% +%\PrintIndex \ No newline at end of file -- cgit v1.2.3