diff options
-rw-r--r-- | Master/texmf-dist/doc/latex/keys3/README | 26 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/keys3/keys3-test.tex | 378 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/keys3/keys3.pdf | bin | 444041 -> 476644 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/keys3/keys3opts2.pdf | bin | 313237 -> 313237 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/latex/keys3/keys3.dtx | 2572 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/keys3/keys3.sty | 860 |
6 files changed, 1273 insertions, 2563 deletions
diff --git a/Master/texmf-dist/doc/latex/keys3/README b/Master/texmf-dist/doc/latex/keys3/README index b79a089d7dc..02413bf1c9e 100644 --- a/Master/texmf-dist/doc/latex/keys3/README +++ b/Master/texmf-dist/doc/latex/keys3/README @@ -9,27 +9,25 @@ See http://www.latex-project.org/lppl.txt The keys3 package is an experimental implementation of key management for LaTeX3. The entire package is written in expl3 code rather than in traditional TeX/LaTeX. The key -module used by keys3 is based on that introduced by the -pgfkeys package from the pgf/TiKZ bundle. Keys are thus -addressed in a path-like manner, and are controlled by key -properties: +model used by keys3 is based on the idea that keys are created +by setting key properties: -/module/key/.code:n = <code>, -/module/key/.value_required:, -/module/key = <value> + \keys_define:nn { module } { + key .code:n = Hello #1, + key .value_required: + } The keys3 package is intended as a method for testing how key management might be implemented in LaTeX3. Both the methods used inside the package and the interface provided are intended to be discussed. Feedback is welcomed either by e-mail -(joseph.wright@morningstar2.co.uk) or at the package website -(http://keys3.berlios.de). +(joseph.wright@morningstar2.co.uk) or to the LaTeX-L mailing +list. -The experimental nature of keys3 and the underlying expl3 -system means that it should not be used in production -documents. However, programmers testing expl3, or keen to work -on improved key management systems, are encouraged to try the -package and provide feedback. +The experimental nature of keys3 means that it should not be +used in production documents. However, programmers testing +expl3, or keen to work on improved key management systems, +are encouraged to try the package and provide feedback. keys3 is *not* an official LaTeX3 team package. Whether any of the ideas explored here will be taken up by the team is diff --git a/Master/texmf-dist/doc/latex/keys3/keys3-test.tex b/Master/texmf-dist/doc/latex/keys3/keys3-test.tex index 2715d0f8a91..a3a2c5c3e26 100644 --- a/Master/texmf-dist/doc/latex/keys3/keys3-test.tex +++ b/Master/texmf-dist/doc/latex/keys3/keys3-test.tex @@ -10,21 +10,12 @@ \usepackage{keys3,xparse} \usepackage[parfill]{parskip} -% The document commands for creating keys is very simple. A generic -% one is created to set any modules keys, and one specific to the module -% used here. -\ExplSyntaxOn - -\DeclareDocumentCommand{\SetModuleKeys}{m}{ - \keys_manage:n{ - module~name/.cd:, - #1} -} +% The document commands for using keys is very simple. -\DeclareDocumentCommand{\SetKeys}{m}{ - \keys_manage:n{#1} +\ExplSyntaxOn +\DeclareDocumentCommand \SetModuleKeys { m } { + \keys_set:nn { module } {#1} } - \ExplSyntaxOff \begin{document} @@ -42,8 +33,17 @@ % You said: ` Hello World ' % You said: `' % ---------------------------------------------------------------------- +\ExplSyntaxOn +\keys_show:nn { module } {unknown} +\keys_set:nn { module } { + clive = india +} +\keys_define:nn { module } { + key .code:n = {You~said:~`#1'\\} +} +\ExplSyntaxOff + \SetModuleKeys{ - key/.code:n = {You said: `#1'\\}, key = Hello World , key = { Hello World }, key @@ -54,254 +54,178 @@ % ---------------------------------------------------------------------- % You said: `A', `B', `C', D'. % You said: `AAA', `BBB', `CCC', ` DDD'. -% You said: `', `', `', `'. % ---------------------------------------------------------------------- -\SetModuleKeys{ - key/.code:Nn = 4 {You said: `#1', `#2', `#3', `#4'.\\}, - key = ABCD, - key = {AAA}{BBB} {CCC} { DDD}, - key =, +\ExplSyntaxOn +\keys_define:nn { module } { + key .code:Nn = 4 {You said:~`#1',~`#2',~`#3',~`#4'.\\}, } +\ExplSyntaxOff -% Test three: The ability to change the key path is available with the -% .cd: property. The following moves from the key root to two separate -% paths, creating keys with the same names. -% ---------------------------------------------------------------------- -% A key in path one -% A key in path two -% A key in path two -% A key in path one -% ---------------------------------------------------------------------- -\SetKeys{ - /path one/.cd:, - key/.code:n = A key in path one\\, - /path two/.cd:, - key/.code:n = A key in path two\\, - /path one/key, - /path two/key, - key, - /path one/.cd:, - key +\SetModuleKeys{ + key = ABCD, + key = {AAA}{BBB} {CCC} { DDD} } -% Test four: Variants of .code:n and .code:Nn exist which carry out a +% Test three: Variants of .code:n and .code:Nn exist which carry out a % full expansion on code definition. First the :x variant is tested. % ---------------------------------------------------------------------- % Temp holds: ABC % Temp hold: 123 % ---------------------------------------------------------------------- \newcommand*{\temp}{123} -\SetModuleKeys{ - key one/.code:n = Temp holds: \temp\\, - key two/.code:x = Temp holds: \temp, + +\ExplSyntaxOn +\keys_define:nn { module } { + key-one .code:n = Temp~holds:~\temp\\, + key-two .code:x = Temp~holds:~\temp, } +\ExplSyntaxOff + \renewcommand*{\temp}{ABC} + \SetModuleKeys{ - key one, - key two + key-one, + key-two } + % Now the :Nx version % ---------------------------------------------------------------------- % Arguments: A, B. Temp holds: ABC % Arguments: 1, 2. Temp hold: 123 % ---------------------------------------------------------------------- \renewcommand*{\temp}{123} -\SetModuleKeys{ - key one/.code:Nn = 2 {Arguments: #1, #2. Temp holds: \temp\\}, - key two/.code:Nx = 2 {Arguments: #1, #2. Temp holds: \temp}, + +\ExplSyntaxOn +\keys_define:nn { module } { + key-one .code:Nn = 2 {Arguments:~#1,~#2.~Temp~holds:~\temp\\}, + key-two .code:Nx = 2 {Arguments:~#1,~#2.~Temp~holds:~\temp}, } +\ExplSyntaxOff \renewcommand*{\temp}{ABC} \SetModuleKeys{ - key one = {A} {B}, - key two = {1} {2} + key-one = {A} {B}, + key-two = {1} {2} } -% Test five: Values can be required and forbidden with the +% Test four: Values can be required and forbidden with the % .value_required: and .value_forbidden: properties. % ---------------------------------------------------------------------- % All okay % All okay % ---------------------------------------------------------------------- -% The key `/module name/key' cannot taken a value: +% The key `module/key-one' cannot taken a value: % the given input `Not allowed' is being ignored. % -% The key `/module name/key' requires a value +% The key `module/key-two' requires a value % and is being ignored. % ---------------------------------------------------------------------- +\ExplSyntaxOn +\keys_define:nn { module } { + key-one .code:n = All okay\\, + key-one .value_forbidden:, + key-two .code:n = #1, + key-two .value_required: +} +\ExplSyntaxOff + \SetModuleKeys{ - key/.code:n = {All okay\\}, - key/.value_forbidden:, - key, - key = Not allowed, - key/.code:n = #1, - key/.value_required:, - key = {All okay}, - key + key-one, + key-one = Not allowed, + key-two = All okay, + key-two } -% Test six: Keys can be given a default value, to be used if nothing is -% specified by the user. +% Test five: Keys can be given a default value, to be used if nothing is +% specified by the user. This can be done by name or by value. % ---------------------------------------------------------------------- % Default % Real -% Default +% Stuff +% Real +% Literal +% Real % ---------------------------------------------------------------------- +\ExplSyntaxOn +\renewcommand*{\temp}{Stuff} +\keys_define:nn { module } { + key-one .code:n = #1\\, + key-one .default:n = \temp, + key-two .code:n = #1\\, + key-two .default:V = \temp, + key-three .code:n = #1\\, + key-three .default:n = Literal, +} +\ExplSyntaxOff +\renewcommand*{\temp}{Default} + \SetModuleKeys{ - key/.code:n = {#1\\}, - key/.default:n = Default, - key, - key = Real, - key + key-one, + key-one = Real, + key-two, + key-two = Real, + key-three, + key-three = Real } -% Test seven: Keys can be created to store data tl variable both -% locally and globally. +% Test six: Keys can be created to store data both locally and +% globally. This is illustrated using token list variables. % ---------------------------------------------------------------------- % Some content % Outside % Some content % Some content % ---------------------------------------------------------------------- -\renewcommand*{\temp}{Outside} -\SetModuleKeys{ - key one/.tl_set:N = \temp, +\ExplSyntaxOn +\tl_new:Nn \l_temp_tl {Outside} +\tl_new:Nn \g_temp_tl {Outside} +\keys_define:nn { module } { + key-one .set:N = \l_temp_tl, + key-two .set:N = \g_temp_tl, } + \begingroup \SetModuleKeys{ - key = Some content + key-one = Some~content } -\temp\\ +\l_temp_tl\\ \endgroup -\temp\\ -\SetModuleKeys{ - key/.tl_gset:N = \temp -} +\l_temp_tl\\ + \begingroup \SetModuleKeys{ - key = Some content + key-two = Some~content } -\temp\\ +\g_temp_tl\\ \endgroup -\temp\\ +\g_temp_tl\\ +\ExplSyntaxOff -% Test eight: An expanded version of .tkp_set:N is available. +% Test seven: An expanded version of .set:N is available. % ---------------------------------------------------------------------- % Unexpanded % Expanded % ---------------------------------------------------------------------- -\renewcommand*{\temp}{Expanded} -\newcommand*{\tempa}{} -\newcommand*{\tempb}{} -\SetModuleKeys{ - key one/.tl_set:N = \tempa, - key two/.tl_set_x:N = \tempb, - key one = \temp, - key two = \temp, -} -\renewcommand*{\temp}{Unexpanded} -\tempa\\ -\tempb\\ - -% Test nine: Storage functions for int, skip and toks variables are also -% available. Both local and global setting is possible, although there -% are no "x" versions. -% ---------------------------------------------------------------------- -% 12345 -% 10.00002pt -% abc -% ---------------------------------------------------------------------- -\newcount\tempint -\newskip\tempskip -\newtoks\temptoks -\SetModuleKeys{ - key/.int_set:N = \tempint, - key = 12345, - key/.skip_set:N = \tempskip, - key = 1 em, - key/.toks_set:N = \temptoks, - key = abc -} -\the\tempint\\ -\the\tempskip\\ -\the\temptoks - -% Test ten: Variables can be identified only by the unique part of their -% name, provided that /keys/current_module:n has been set with the -% appropriate information. Both local and global names can be used in -% this way. -% ---------------------------------------------------------------------- -% Local -% Global -% ---------------------------------------------------------------------- \ExplSyntaxOn -\tl_new:N \l_module_local_tl -\tl_new:N \g_module_global_tl -\ExplSyntaxOff -\SetModuleKeys{ - /keys/current_module:n = module, - key one/.tl_set:n = local, - key two/.tl_gset:n = global, - key one = Local, - key two = Global +\tl_set:Nn \l_temp_tl {Expanded} +\tl_new:N \l_tempa_tl +\tl_new:N \l_tempb_tl +\keys_define:nn { module } { + key-one .set:N = \l_tempa_tl, + key-two .set_x:N = \l_tempb_tl, } -\ExplSyntaxOn -\l_module_local_tl \\ -\g_module_global_tl -\ExplSyntaxOff -% Test eleven: Boolean keys are created in the same way as other storage -% keys. However, the key will then only accept "true" and "false" as -% input. The key name can be given alone, resulting in the switch being -% set "true". -% ---------------------------------------------------------------------- -% Local switch true -% Global switch true -% ---------------------------------------------------------------------- -% Key `/module name/key one' takes the Boolean values -% `true' and `false' only. -% The given value `rubbish' is being ignored. -% ---------------------------------------------------------------------- -\ExplSyntaxOn -\bool_new:N \localbool -\bool_new:N \g_module_global_bool -\ExplSyntaxOff \SetModuleKeys{ - /keys/current_module:n = module, - key one/.bool_set:N = \localbool, - key two/.bool_gset:n = global, - key one = true, - key two = false, - key two, - key one = rubbish + key-one = \l_temp_tl, + key-two = \l_temp_tl, } -\ExplSyntaxOn -\bool_if:NTF \localbool { Local~switch~true } { Local~switch~false } \\ -\bool_if:NTF \g_module_global_bool - { Global~switch~true } { Global~switch~false } -\ExplSyntaxOff +\tl_set:Nn \l_temp_tl {Unxpanded} +\l_tempa_tl\\ +\l_tempb_tl\\ -% Test twelve: The logic for Boolean keys can be reversed using the -% .bool_set_inverse:N and related properties. This can be used with -% in concert with .bool_set:N to create complementary keys. -% ---------------------------------------------------------------------- -% Hello World -% Hello User -% ---------------------------------------------------------------------- -\SetModuleKeys{ - /keys/current_module:n = module, - key one/.bool_set_inverse:N = \localbool, - key two/.bool_gset_inverse:n = global, - key one, - key two = true, -} -\ExplSyntaxOn -\bool_if:NTF \localbool { Local~switch~true } { Local~switch~false } \\ -\bool_if:NTF \g_module_global_bool - { Global~switch~true } { Global~switch~false } \ExplSyntaxOff -% Test thirteen: Choices can be created either from a list of options or +% Test eight: Choices can be created either from a list of options or % one by one. Both are tested here by creating a list then adding to it % with an extra key. Unknown choices lead to an error message. % ---------------------------------------------------------------------- @@ -310,14 +234,19 @@ % Choice `c' is number 3 % An extra choice % ---------------------------------------------------------------------- -% Choice `e' unknown for key `/module name/key/e': +% Choice `e' unknown for key `module/key': % the key is being ignored. % ---------------------------------------------------------------------- +\ExplSyntaxOn +\keys_define:nn { module } { + key .generate_choices:nn = {a,b,c} { + Choice~`\l_keys_choice_tl'~is~number~\int_use:N \l_keys_choice_int\\ + }, + key/d .code:n = An~extra~choice \\ +} +\ExplSyntaxOff + \SetModuleKeys{ - key/.create_choices:nn = {a,b,c} - {Choice `\csname l_keys_current_choice_tl\endcsname' is number - \the\csname l_keys_current_choice_int\endcsname \\}, - key/d/.code:n = {An extra choice \\}, key = a, key = b, key = c, @@ -325,70 +254,29 @@ key = e } -% Test fourteen: Keys can be used to set other keys. One or more -% arguments can be accepted when this happens, allowing complex key -% setting to be carried out easily. There are expanded versions of these -% properties, which work similarly. +% Test nine: A completely unknown key should cause an error. % ---------------------------------------------------------------------- -% Hello Fred. -% How are you, Fred? -% Hello Fred. -% How are you, Ginger? +% The key `module/unknown key' is unknown and is being ignored. % ---------------------------------------------------------------------- \SetModuleKeys{ - key one/.code:n = {Hello #1.\\}, - key two/.code:n = {How are you, #1?\\}, - key three/.use_keys:n = { key one = #1, key two = #1}, - key three = Fred, - key three/.use_keys:Nn = 2 { key one = #1, key two = #2}, - key three = {Fred} {Ginger} + unknown key = some value } -% Test fifteen: The .try:w and .retry:w properties attempt to set a key -% only if it exists. The .try:w property does this for every key it -% is given, whereas .retry: only works if the previous .try:w failed. +% Test ten: If the special `unknown' key has been set up, however, +% unknown input can be re-directed. % ---------------------------------------------------------------------- -% Hello -% World -% Seen +% You tried to set key `unknown key' to `some value' % ---------------------------------------------------------------------- -\SetModuleKeys{ - key one/.code:n = {#1\\}, - key two/.code:n = {#1\\}, - key one/.try:n = Hello, - key ten/.try:n = Rubbish, - key two/.try:n = World, - key two/.retry:n = Not seen, - key ten/.try:n = Rubbish, - key two/.retry:n = Seen, +\ExplSyntaxOn +\keys_define:nn { module } { + unknown .code:n = You~tried~to~set~key~`\l_keys_key_tl'~to~`#1' } +\ExplSyntaxOff -% Test sixteen: Two programmers tools, .show_code: and .show_key:, do -% pretty much what might be expected. .show_key: is mainly useful for -% internal keys. -% ---------------------------------------------------------------------- -% a or b -% ---------------------------------------------------------------------- -% > \keys-root/module name/key one/._cmd:w=\long macro: -% #1#2->#1 or #2. -% -% > \keys-root/module name/key one/._num_args_tl=macro: -% ->2. -% ---------------------------------------------------------------------- \SetModuleKeys{ - key one/.code:Nn = 2 {#1 or #2}, - key one = ab, - key one/.show_code:, - key one/._num_args_tl/.show_key:, + unknown key = some~value } -% Test seventeen: A completely unknown key should cause an error. -% ---------------------------------------------------------------------- -% The key `/module name/unknown key' is unknown and is being ignored -% ---------------------------------------------------------------------- -\SetModuleKeys{ - unknown key = some value -} \end{document} diff --git a/Master/texmf-dist/doc/latex/keys3/keys3.pdf b/Master/texmf-dist/doc/latex/keys3/keys3.pdf Binary files differindex 3d26fd7fdfe..3c1831ca5e8 100644 --- a/Master/texmf-dist/doc/latex/keys3/keys3.pdf +++ b/Master/texmf-dist/doc/latex/keys3/keys3.pdf diff --git a/Master/texmf-dist/doc/latex/keys3/keys3opts2.pdf b/Master/texmf-dist/doc/latex/keys3/keys3opts2.pdf Binary files differindex cdc4783125a..a0cc876d6b6 100644 --- a/Master/texmf-dist/doc/latex/keys3/keys3opts2.pdf +++ b/Master/texmf-dist/doc/latex/keys3/keys3opts2.pdf diff --git a/Master/texmf-dist/source/latex/keys3/keys3.dtx b/Master/texmf-dist/source/latex/keys3/keys3.dtx index 6932050bb8c..919fee6ffa2 100644 --- a/Master/texmf-dist/source/latex/keys3/keys3.dtx +++ b/Master/texmf-dist/source/latex/keys3/keys3.dtx @@ -16,27 +16,25 @@ See http://www.latex-project.org/lppl.txt The keys3 package is an experimental implementation of key management for LaTeX3. The entire package is written in expl3 code rather than in traditional TeX/LaTeX. The key -module used by keys3 is based on that introduced by the -pgfkeys package from the pgf/TiKZ bundle. Keys are thus -addressed in a path-like manner, and are controlled by key -properties: +model used by keys3 is based on the idea that keys are created +by setting key properties: -/module/key/.code:n = <code>, -/module/key/.value_required:, -/module/key = <value> + \keys_define:nn { module } { + key .code:n = Hello #1, + key .value_required: + } The keys3 package is intended as a method for testing how key management might be implemented in LaTeX3. Both the methods used inside the package and the interface provided are intended to be discussed. Feedback is welcomed either by e-mail -(joseph.wright@morningstar2.co.uk) or at the package website -(http://keys3.berlios.de). +(joseph.wright@morningstar2.co.uk) or to the LaTeX-L mailing +list. -The experimental nature of keys3 and the underlying expl3 -system means that it should not be used in production -documents. However, programmers testing expl3, or keen to work -on improved key management systems, are encouraged to try the -package and provide feedback. +The experimental nature of keys3 means that it should not be +used in production documents. However, programmers testing +expl3, or keen to work on improved key management systems, +are encouraged to try the package and provide feedback. keys3 is *not* an official LaTeX3 team package. Whether any of the ideas explored here will be taken up by the team is @@ -117,7 +115,7 @@ This work consists of the file keys3.dtx %</internal> %<*driver|package> \RequirePackage{expl3} -\GetIdInfo$Id: keys3.dtx 101 2009-06-10 12:16:20Z josephwright $ +\GetIdInfo$Id: keys3.dtx 110 2009-06-12 21:27:24Z josephwright $ {Key management for LaTeX3} %</driver|package> %\fi @@ -134,115 +132,77 @@ This work consists of the file keys3.dtx %</driver> % \fi % -% \title{The \pkg{keys3} package^^A -% \thanks{This file has version number \fileversion, last -% revised \filedate.}\\ -% Key management for \LaTeX3} -% \author{Joseph Wright^^A -% \thanks{E-mail: joseph.wright@morningstar2.co.uk}} -% \date{\filedate} +%\title{The \pkg{keys3} package^^A +% \thanks{This file has version number \fileversion, last +% revised \filedate.}\\ +% Key management for \LaTeX3 +%} +%\author{Joseph Wright^^A +% \thanks{E-mail: joseph.wright@morningstar2.co.uk}} +%\date{\filedate} % -% \maketitle +%\maketitle % -% \begin{documentation} +%\begin{documentation} % %\section{Key management} % % The key--value method is a popular system for creating large numbers -% of settings for controlling macro or package behaviour. For the +% of settings for controlling function or package behaviour. For the % user, the system normally results in input of the form %\begin{verbatim} % \PackageControlMacro{ -% key = value, -% key two = value two +% key-one = value one, +% key-two = value two % } %\end{verbatim} % or %\begin{verbatim} % \PackageMacro[ -% key = value, -% key two = value two +% 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. However, the underlying model is rather inflexible. -% -% As an alternative, \pkg{pgfkeys} from the \pkg{pgf}/Ti\emph{k}z -% bundle uses a ``file-like'' model for keys. In this model, each key -% has one or more functions attached to define its action. In -% \pkg{pgfkeys} terminology, these are key \emph{handlers}. Keys can -% be created and used using a unified interface: +% 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{keys3} 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} -% \pgfkeys{ -% /path/key/.handler = code, -% /path/key = value +% \keys_define:nn { module } +% key-one .code:n = code including parameter #1, +% key-two .set = \l_module_store_tl % } %\end{verbatim} -% -% The \pkg{keys3} package is aimed at creating a high-level -% programmers interface for key--value controls in \LaTeX3. Key -% creation and control follows the \pkg{pgfkeys} closely, although -% changes have been made to adhere to the new coding ideas of \LaTeX3, -% and new functions have been added. The \pkg{keys3} package is -% \emph{not} a simple translation of \pkg{pgfkeys} to the new syntax. -% In package internals have been written from the ground up, to better -% enforce variable typing and to act in a know manner under failing -% circumstances. -% -% In the \pkg{keys3} model, each key belongs to a module, -% which may have one or more subdivisions. Each key then has -% one or more properties which define how the key acts. The idea -% of a single function for all key control is retained: -%\begin{verbatim} -% \keys_manage:n{ -% /module/key/.property = code, -% /module/sub/key/.property = more code, -% /module/key = value -% } -%\end{verbatim} -% The combination of all \m{module} parts up to the \m{key} is referred -% to as the \emph{path} of the key. -% -% Keys are created by assigning one or more properties to the key, -% most commonly a piece of code to execute when the key is used (this -% is the \texttt{.code:n} property). +% These values can then be set as with other key--value approaches: %\begin{verbatim} -% \keys_manage:n{ -% /module/key/.code:n = <code> +% \keys_set:nn { module } +% key-one = value one, +% key-two = value two % } %\end{verbatim} -% Keys are then used in the normal way, by assigning a value to the -% key. -%\begin{verbatim} -% \keys_manage:n{ -% /module/key = <value> -% } -%\end{verbatim} -% Here, \meta{value} is passed to the \meta{code} defined |#1|. The -% \meta{code} can then process it in whatever way is appropriate. -% -% At a document level, it is likely that \cs{keys_manage:n} would be -% wrapped up into a user macro or optional argument. For \LaTeXe, a -% generic set up macro might be created with: +% +% At a document level, the \cs{keys_set:nn} macro used within a +% document function. For \LaTeXe, a generic set up function could be +% created with %\begin{verbatim} % \newcommand*\SomePackageSetup[1]{% -% \@nameuse{keys_manage:n}{% -% /package name/.cd:, -% #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_manage:n}{ -% /package name/.cd:, -% #1 -% }% +% \@nameuse{keys_set:nn}{module}{#1}% % % Main code for \SomePackageMacro % \endgroup % } @@ -250,803 +210,469 @@ This work consists of the file keys3.dtx % The same concepts using \pkg{xparse} for \LaTeX3 use: %\begin{verbatim} % \DeclareDocumentCommand \SomePackageSetup { m } { -% \keys_manage:n { -% /package name/.cd:, -% #1 -% } +% \keys_set:nn { module } { #1 } % } % \DeclareDocumentCommand \SomePackageMacro { o m } { % \group_begin: -% \keys_manage:n { -% /package name/.cd:, -% #1 -% } +% \keys_set:nn { module } { #1 } % % Main code for \SomePackageMacro % \group_end: % } -%\end{verbatim} -% -%\subsection{Creating, retrieving and setting keys} -% -% The main interface for key management is the the \cs{keys_manage:n} -% macro. This can be used to create, retrieve and set keys, and is -% therefore the preferred interface for the package. -% -% \begin{function}{ -% \keys_manage:n| -% \keys_manage_quick:n -% } -% \begin{syntax} -% "\keys_manage:n" <keyval list> -% \end{syntax} -% The main key management function, which parses over the <keyval -% list> and processes each key. The standard version removes leading -% and trailing spaces and checks catcodes for ungrouped ``|,|'' and -% ``|=|'' tokens. The |_quick| version omits these tests for speed, -% and is therefore more suited to creating keys inside code blocks. -% \end{function} -% -% \begin{function}{ -% \keys_manage:nn| -% \keys_manage_quick:nn| -% } -% \begin{syntax} -% "\keys_manage:nn" <path> <keyval list> -% \end{syntax} -% Versions of the above which include a <path> as an argument. These -% are faster versions of the |:n| macros when setting lots of keys -% separately and with known paths. -% \end{function} -% -% Setting up and altering keys is carried out using one or more -% properties (in \pkg{pgfkeys}, these are called handlers). In all -% cases, \m{key} may be a full-qualified key with a path, or a partial -% key to which the default path will be added. Notice that when a -% single argument is required, the braces around the argument may be -% omitted without any error arising. -% -%\subsubsection{Storing values} -% -% A common use of key--value input is to store the values given in a -% variable for later use. \pkg{keys3} provides pre-defined -% properties for storing in integer, skip, token list variables and -% token registers. The method is similar in all cases: -%\begin{verbatim} -% \keys_manage:n{ -% /module/key~one/.int_set:N = \l_mod_data_int, -% /module/key~two/.skip_set:N = \l_mod_data_skip, -% /module/key~three/.tl_set:N = \l_mod_data_tl, -% /module/key~four/.toks_set:N = \l_mod_data_toks -% } -%\end{verbatim} -% These assignments are local: in each case, a global variant is -% available, with \texttt{set} replaced by \texttt{gset}. For example, -% \texttt{.tl_get:N} globally stores values in a token list variable. -% -% When using keys to store a value, it is often convenient to give only -% the unique part of the variable name. This is particularly true when -% creating a large number of related storage areas. To achieve this, -% \pkg{keys3} requires that the module prefix to be used is defined -% first. The special key \texttt{/keys/current_module:n} can be set with -% the name of the current module. -%\begin{verbatim} -% \keys_manage:n{ -% /keys/current_module:n = module, -% /module/key/.tl_set:n = my_data, -% } %\end{verbatim} -% This will use a variable called \cs{l_module_my_data_tl} to store the -% input. Thus the preceding code achieves the same effect as -%\begin{verbatim} -% \keys_manage:n{ -% /module/key/.tl_set:N = \l_module_my_data_tl -% } -%\end{verbatim} -% The same method applies to int, skip and toks variables. The -% appropriate prefix (\cs{l_} or \cs{g_}) and suffix (|_int|, |_skip|, -% |_tl| or |_toks|) is always added. -% -%\subsubsection{Multiple choice keys} % -% Multiple choice keys are created in \pkg{keys3} using the -% \texttt{.expects_choice:} property. Each choice is then a sub-key of -% the choice key. +% 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} -% \keys_manage:n{ -% /module/key/.expects_choice:, -% /module/key/choice~a/.code:n = Some code, -% /module/key/choice~b/.code:n = Some other code, -% } -%\end{verbatim} -% In this way, choices which execute arbitrary code can be created. -% Notice that the \m{code} should \emph{not} include a parameter (|#1|). -% -% Often it is desirable to create a family of similar choices, which -% only require either the text of the choice, or the position of the -% choice in a list, to be used. To create this type of simple choice, -% \pkg{keys3} provides the \texttt{.create_choices:nn} property. This -% applies the same code to a list of choice text. Inside the code, -% the name of the choice given is available as -% \cs{l_keys_current_choice_tl}. The position of the choice in the -% lists is also available, as \cs{l_keys_current_choice_int}. -%\begin{verbatim} -% \keys_manage:n { -% /module/key/.create_choices:nn = {choice~a, choice~b, choice~c} { -% You~gave~choice~``\l_keys_current_choice_tl'',~which~is~in~ -% position~\l_keys_current_choice_int\~in~the~list. -% } +% \tl_set:Nn \l_module_tmp_tl { key } +% \keys_define:nn { module } { +% \l_module_tmp_tl .code:n = code % } -%\end{verbatim} -% -%\subsection{Properties} +%\end{verbatim} +% will create a key called \cs{l_module_tmp_tl}, and not one called +% \texttt{key}. % -% \begin{function}{ -% .bool_set:N| -% .bool_gset:N| -% } -% \begin{syntax} -% <key>/.bool_set:N = <bool> -% \end{syntax} -% Defines <key> to set <bool> to <value> (which must be either -% \texttt{true} or \texttt{false}). -% \end{function} -% -% \begin{function}{ -% .bool_set:n| -% .bool_gset:n| -% } -% \begin{syntax} -% <key>/.bool_set:n = <name> -% \end{syntax} -% Defines <key> to set switch with unique <name> to <value> (which -% must be either \texttt{true} or \texttt{false}). The switch -% name will be constructed using the current <module> (if any), -% prefixed by |\l_| and ending with |_int|. -% \end{function} -% -% \begin{function}{ -% .bool_set_inverse:N| -% .bool_gset_inverse:N| -% } +%\subsection{Creating keys} +% +%\begin{function}{\keys_define:nn} % \begin{syntax} -% <key>/.bool_set_inverse:N = <bool> +% "\keys_define:nn" <module> <keyval list> % \end{syntax} -% Defines <key> to set <bool> to <value> (which must be either -% \texttt{true} or \texttt{false}), with reversed logic. -% \end{function} +% Parses the <keyval list> and defines the keys listed there for +% <module>. This function is designed for use in code, and therefore +% does not check the category codes of characters or ignore spaces. +%\end{function} % -% \begin{function}{ -% .bool_set_inverse:n| -% .bool_gset_inverse:n| -% } -% \begin{syntax} -% <key>/.bool_set_inverse:n = <name> -% \end{syntax} -% Defines <key> to set switch with unique <name> to <value> (which -% must be either \texttt{true} or \texttt{false}), with reversed logic. -% The switch name will be constructed using the current <module> (if -% any), prefixed by |\l_| and ending with |_int|. -% \end{function} -% -% \begin{function}{.cd:} +% Setting up and altering keys is carried out using one or more +% properties. The properties determine how a key acts, and may require +% zero, one or two argument: this is indicated by an argument specifier, +% in the same way as a standard \LaTeX3 function. If only a single +% argument is required, braces around \texttt{n} arguments can be +% omitted.\footnote{This is a general feature of key--value input +% methods.} +% +%\begin{function}{.choice:} % \begin{syntax} -% <key>/.cd: +% <key> .choice: % \end{syntax} -% Changes path to <key>. -% \end{function} +% Sets <key> to act as a multiple choice key. Creating choices +% is discussed in section~\ref{sec:choice}. +%\end{function} % -% \begin{function}{ +%\begin{function}{ % .code:n| % .code:x % } % \begin{syntax} -% <key>/.code:n = <code> +% <key> .code:n = <code> % \end{syntax} % Stores the <code> for execution when <key> is called. The <code> can % include one parameter (|#1|). -% \end{function} +%\end{function} % -% \begin{function}{ +%\begin{function}{ % .code:Nn| % .code:Nx % } % \begin{syntax} -% <key>/.code:Nn = <number> <code> +% <key> .code:Nn = <number> <code> % \end{syntax} % Stores the <code> for execution when <key> is called. The <code> can -% include <number> parameters, which can be in the range 0--9. -% \end{function} -% -% \begin{function}{ -% .create_choices:nn| -% .create_choices:nx| -% } -% \begin{syntax} -% <key>/.create_choices:nn = <list> <code> -% \end{syntax} -% Creates a sub-key of <key> for each <choice> in the comma-separated -% <list>. Each <choice> will have <code> associated with it. The -% current choice text is available as \cs{l_keys_current_choice_tl}, -% and its position in the <list> as \cs{l_keys_current_choice_int}. -% \end{function} +% include <number> parameters, which can be in the standard \TeX\ +% range 0--9. +%\end{function} % -% \begin{function}{.default:n} +%\begin{function}{ +% .default:n| +% .default:V| +% } % \begin{syntax} -% <key>/.default:n = <content> +% <key> .default:n = <content> % \end{syntax} % Creates a default value for <key>, which is used if no value is -% given. The <content> is stored as a token list variable, and so -% must be compatible with this variable type. -% \end{function} -% -% \begin{function}{.expects_choice:} -% \begin{syntax} -% <key>/.expects_choice: -% \end{syntax} -% Indicates that the <value> given for <key> should be a sub-key of -% <key>. In this way, <key> accepts one of a limited range of choices. -% \end{function} -% -% \begin{function}{ -% .int_set:N| -% .int_gset:N| -% } -% \begin{syntax} -% <key>/.int_set:N = <int> -% \end{syntax} -% Defines <key> to store <value> in the <int> named. -% \end{function} -% -% \begin{function}{ -% .int_set:n| -% .int_gset:n| -% } -% \begin{syntax} -% <key>/.int_set:n = <name> -% \end{syntax} -% Defines <key> to store <value> in a int with unique name <name>. The -% int name will be constructed using the current <module> (if any), -% prefixed by |\l_| and ending with |_int|. -% \end{function} -% -% \begin{function}{.retry:n} -% \begin{syntax} -% <key>/.retry:n = <data> -% \end{syntax} -% Executes <key> if it exists and if the previous \texttt{.try:n} -% failed. The <data> is passed to <key>, if successful. -% \end{function} -% -% \begin{function}{ -% .show_code:| -% .show_key:| -% } -% \begin{syntax} -% <key>/.show_code: -% <key>/.show_key: -% \end{syntax} -% Shows the function for the current key or the code associated with -% the current key. -% \end{function} -% -% \begin{function}{ -% .skip_set:N| -% .skip_gset:N| -% } -% \begin{syntax} -% <key>/.skip_set:N = <skip> -% \end{syntax} -% Defines <key> to store <value> in the <skip> named. -% \end{function} -% -% \begin{function}{ -% .skip_set:n| -% .skip_gset:n| -% } -% \begin{syntax} -% <key>/.skip_set:n = <name> -% \end{syntax} -% Defines <key> to store <value> in a skip with unique name <name>. The -% skip name will be constructed using the current <module> (if any), -% prefixed by |\l_| and ending with |_skip|. -% \end{function} -% -% \begin{function}{ -% .tl_set:N| -% .tl_set_x:N| -% .tl_gset:N| -% .tl_gset_x:N| -% } -% \begin{syntax} -% <key>/.tl_set:N = <tl> -% \end{syntax} -% Defines <key> to store <value> in the <tl> named. The \texttt{x} -% versions use \cs{tl_(g)set:Nx} for this process, the standard -% version \cs{tl_(g)set:Nn}. -% \end{function} -% -% \begin{function}{ -% .tl_set:n| -% .tl_set_x:n| -% .tl_gset:n| -% .tl_gset_x:n| -% } -% \begin{syntax} -% <key>/.tl_set:n = <name> -% \end{syntax} -% Defines <key> to store <value> in a tl with unique name <name>. The -% tl name will be constructed using the current <module> (if any), -% prefixed by |\l_| and ending with |_tl|. -% \end{function} -% -% \begin{function}{ -% .toks_set:N| -% .toks_gset:N| +% given. +% \begin{texnote} +% The <content> is stored as a token list variable, and this +% means that there are some restrictions on the nature of <content>. +% \end{texnote} +%\end{function} +% +%\begin{function}{ +% .generate_choices:nn| +% .generate_choices:nx| % } % \begin{syntax} -% <key>/.toks_set:N = <toks> +% <key> .generate_choices:nn = <comma list> <code> % \end{syntax} -% Defines <key> to store <value> in the <toks> named. -% \end{function} -% -% \begin{function}{ -% .toks_set:n| -% .toks_gset:n| -% } -% \begin{syntax} -% <key>/.toks_set:n = <name> -% \end{syntax} -% Defines <key> to store <value> in a toks with unique name <name>. The -% rest of the toks name will be constructed using the current <module> -% (if any), prefixes by |\l_| and ending with |_toks|. -% \end{function} -% -% \begin{function}{.try:n} -% \begin{syntax} -% <key>/.try:n = <data> -% \end{syntax} -% Executes <key> if defined, and does nothing otherwise. The <data> is -% passed to <key>, if successful. -% \end{function} -% -% \begin{function}{ -% .use_keys:n| -% .use_keys:x| -% } +% Makes <key> a multiple choice key, accepting the choices specified +% in <comma list>. Each choice will execute <code> if it given. Within +% <code>, the name of the current choice is available as +% \cs{l_keys_choice_tl}, and its position in the <comma list> as +% \cs{l_keys_choice_int}. Multiple choices are discussed further in +% section~\ref{sec:choice}. +%\end{function} +% +%\begin{function}{ +% .set:N| +% .set_x:N +%} % \begin{syntax} -% <key>/.use_keys:n = <keyval list> +% <key> .set:N = <variable> % \end{syntax} -% Calling <key> applies the <keyval list> as a block. Thus one <key> -% can make many related settings. As usual, |#1| is available in the -% <keyval list> as <key> will take one argument. -% \end{function} -% -% \begin{function}{ -% .use_keys:Nn| -% .use_keys:Nx| +% Defines <key> to store the value given in <variable>. The type and +% scope (local or global) of <variable> are determined from the +% name. The \texttt{x} version performs an expanded assignment. +% \begin{texnote} +% A \cs{<variable>_set:Nn} function must exist to allow setting +% of the <variable>. +% \end{texnote} +%\end{function} +% +%\begin{function}{ +% .set_bool:N| +% .set_bool_inverse:N| % } % \begin{syntax} -% <key>/.use_keys:Nn = <number> <keyval list> +% <key> .set_bool:N = <bool> +% <key> .set_bool_inverse:N = <bool> % \end{syntax} -% Calling <key> applies the <keyval list> as a block. Thus one <key> -% can make many related settings. The <key> will take <number> of -% arguments, which can be used inside the <keyval list>. -% \end{function} +% Defines <key> to set <bool> to <value> (which must be either +% \texttt{true} or \texttt{false}). The \texttt{inverse} version sets +% the switch to the opposite logical sense to the argument given. +%\end{function} % -% \begin{function}{ +%\begin{function}{ % .value_forbidden:| % .value_required:| % } % \begin{syntax} -% <key>/.value_forbidden: +% <key> .value_forbidden: % \end{syntax} % Flags for forbidding and requiring a <value> for <key>. -% \end{function} -% -%\subsection{Variables and constants} +%\end{function} % -% \begin{variable}{ -% \c_keys_0_empty_tl| -% \c_keys_1_empty_tl| -% \c_keys_2_empty_tl| -% \c_keys_3_empty_tl| -% \c_keys_4_empty_tl| -% \c_keys_5_empty_tl| -% \c_keys_6_empty_tl| -% \c_keys_7_empty_tl| -% \c_keys_8_empty_tl| -% \c_keys_9_empty_tl| -% } -% A set of token list variables containing empty groups. -% \end{variable} -% -% \begin{variable}{\c_keys_cs_prefix_tl} -% The prefix added to the fully-qualified key when saving them. -% \end{variable} -% -% \begin{variable}{ -% \c_keys_errors_path_tl| -% \c_keys_properties_path_tl| -% \c_keys_utilities_path_tl| -% } -% Paths for properties used by \pkg{l3keys} itself. -% \end{variable} -% -% \begin{variable}{\c_keys_root_tl} -% The root path for keys. -% \end{variable} -% -% \begin{variable}{\l_keys_choice_code_tl} -% The code to execute for each multiple choice when created \emph{en -% masse}. -% \end{variable} -% -% \begin{variable}{ -% \l_keys_current_choice_tl| -% \l_keys_current_choice_int| -% } -% Information on multiple choices. -% \end{variable} -% -% \begin{variable}{ -% \l_keys_current_key_full_tl| -% \l_keys_current_key_name_tl| -% } -% The current key name is stored both with and without a path. -% \end{variable} -% -% \begin{variable}{\l_keys_current_module_tl} -% Current module name used when creating csnames. -% \end{variable} -% -% \begin{variable}{ -% \l_keys_current_path_tl| -% \l_keys_default_path_tl| -% \l_keys_choice_path_tl| -% } -% Various key paths need to be stored. -% \end{variable} -% -% \begin{variable}{\l_keys_current_value_toks} -% The value given for the current key, stored as a token register. -% \end{variable} -% -% \begin{variable}{\l_keys_no_value_bool} -% A marker for ``no value'' as key input. -% \end{variable} -% -% \begin{variable}{\l_keys_success_bool} -% A marker used when trying keys without raising errors. -% \end{variable} -% -% \begin{variable}{\l_keys_tmpa_tl} -% A scratch variable. -% \end{variable} -% -%\subsection{Internal functions} +%\subsection{Sub-dividing keys} +%\label{sec:subdivision} % -% Notice that everything should be done using the keys system. Only -% \cs{keys_manage:n} and so on are intended for external use. In all -% cases, \m{key} is a fully-qualified key name. Functions created will -% be prefixed with \cs{c_keys_cs_prefix_tl}. -% -% \begin{function}{\keys_bool_new:n} -% \begin{syntax} -% "\keys_bool_new:n" <key> -% \end{syntax} -% Creates a switch <key>, which will be set to \texttt{true}. -% \end{function} -% -% \begin{function}{ -% \keys_bool_set:nN| -% \keys_bool_set:nnn| +% 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 % } -% \begin{syntax} -% "\keys_bool_set:nN" <function> <boolean> -% "\keys_bool_set:nnn" <function> <prefix> <name> -% \end{syntax} -% Uses <function> (either \texttt{set} or \texttt{gset}) to use -% <value> in setting <boolean>. If a <name> is given, it is used to -% construct a csname for the switch including the current <module>. -% The <prefix> should be |l_| or |g_|. -% \end{function} +%\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}. % -% \begin{function}{ -% \keys_bool_set_inverse:n| -% \keys_bool_set_inverse:nN| -% \keys_bool_set_inverse:nnn| +% As will be illustrated in the next section, this subdivision is +% particularly relevant to making multiple choices. +% +%\subsection{Multiple choices} +%\label{sec:choice} +% +% In \pkg{keys3}, multiple choices are created by setting the +% \texttt{.choice:} property: +%\begin{verbatim} +% \keys_define:nn { module } { +% key .choice: % } -% \begin{syntax} -% "\keys_bool_set:n" <switch> -% "\keys_bool_set:nN" <function> <boolean> -% "\keys_bool_set:nnn" <function> <prefix> <name> -% \end{syntax} -% Uses <function> (either \texttt{set} or \texttt{gset}) to use -% <value> in setting <boolean>. If a <name> is given, it is used to -% construct a csname for the switch including the current <module>. -% The <prefix> should be |l_| or |g_|. The logic of the setting is -% reversed compared to the \cs{keys_bool_set:} functions. -% \end{function} +%\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{.generate_choices:nn} +% property: +%\begin{verbatim} +% \keys_define:nn { module } { +% key .generate_choices:nn = { +% choice-a, choice-b, choice-c +% } { +% You~gave~choice~``\l_keys_choice_tl'',~ +% which~is~in~position~\l_keys_choice_int +% \~in~the~list. +% } +% } +%\end{verbatim} % -% \begin{function}{ -% \keys_check_exists:NN| -% \keys_check_exists:cN +%\begin{variable}{ +% \l_keys_choice_tl| +% \l_keys_choice_int| %} -% \begin{syntax} -% "\keys_check_exists:NN" <var> <new cmd> -% \end{syntax} -% Checks that <var> exists and if not used <new cmd> to create it. -% \end{function} -% -% \begin{function}{\keys_choice_create:n} -% \begin{syntax} -% "\keys_choice_create:n" <choice> -% \end{syntax} -% Creates <choice> as a sub-key of <key>. -% \end{function} -% -% \begin{function}{\keys_choices_create:Nnn} -% \begin{syntax} -% "\keys_choices_create:Nnn" <expansion> <list> <code> -% \end{syntax} -% Takes a comma separated <list> and makes a <choice> as a sub-key of -% the current <key> for each. The <choice> will execute <code>, which -% is processed according to <expansion> (either \texttt{n} or -% \texttt{x}). The <code> has access to \cs{l_keys_current_choice_tl} -% and \cs{l_keys_current_choice_int}, which indicate the choice given. -% \end{function} -% +% Inside the code block, the variables \cs{l_keys_choice_tl} and +% \cs{l_keys_choice_int} are available to indicate the name of the +% current choice, and its position in the comma list. The position +% is indexed from \(1\). +%\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 choices: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}. +% +%\subsection{Setting keys} +% +%\begin{function}{\keys_set:nn} +% \begin{syntax} +% "\keys_set:nn" <module> <keyval list> +% \end{syntax} +% Parses the <keyval list>, and sets those keys which are defined +% for <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_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} % -% \begin{function}{\keys_clear_properties:n} -% \begin{syntax} -% "\keys_clear_properties:n" <key> -% \end{syntax} -% Clears the internal properties of <key>. -% \end{function} +%\subsection{Examining keys: internal representation} +% +%\begin{function}{\keys_show:nn} +% \begin{syntax} +% "\keys_show:nn" <module> <key> +% \end{syntax} +% Shows the internal representation of a <key>. The function which +% executes a <key> is called \cs{keys > <module>/<key>.cmd:w}. +%\end{function} % -% \begin{function}{\keys_default_add:} +%\subsection{Internal functions} +% +%\begin{function}{ +% \keys_bool_set:N | +% \keys_bool_set_inverse:N +%} % \begin{syntax} -% "\keys_default_add:" +% "\keys_bool_set:N" <bool> % \end{syntax} -% If no value was given for the current key, and a default value is -% available, copies the default into \cs{l_keys_current_value_toks}. -% \end{function} -% -% \begin{function}{\keys_msg_new:nn} +% Creates code to set <bool> when <key> is given. +%\end{function} +% +%\begin{function}{\keys_choice_make:} % \begin{syntax} -% "\keys_msg_new:nn" <name> <text> +% "\keys_choice_make:" % \end{syntax} -% Creates a new message with <name> which produces <text>. -% \end{function} -% -% \begin{function}{ -% \keys_error:nn| -% \keys_error:n| -% } +% Makes <key> a choice key. +%\end{function} +% +%\begin{function}{\keys_choices_generate:nx} % \begin{syntax} -% "\keys_error:nn" <name> <arg> -% "\keys_error:n" <name> +% "\keys_choices_generate:nx" <comma list> <code> % \end{syntax} -% Issues error <name>, with or without <argument>. -% \end{function} -% -% \begin{function}{ -% \keys_find_code_full:| -% \keys_find_code_name: -% } +% Makes <comma list> choices for <key>, each using <code>. +%\end{function} +% +%\begin{function}{\keys_choice_find:n} % \begin{syntax} -% "\keys_find_code_full:" -% "\keys_find_code_name:" +% "\keys_choice_find:n" <choice> % \end{syntax} -% Find code to execute for the current fully qualified key -% (\texttt{full}) or key name only (\texttt{name}). -% \end{function} -% -% \begin{function}{\keys_if_cmd_exist:n / (TF)} +% Searches for <choice> as a sub-key of <key>. +%\end{function} +% +%\begin{function}{ +% \keys_cmd_set:nNn | +% \keys_cmd_set:nNx +%} % \begin{syntax} -% "\keys_if_cmd_exist:nTF" <key> <true code> -% ~~~~<false code> +% "\keys_cmd_set:nNn" <path> <num args> <code> % \end{syntax} -% Checks for the existence of a |._cmd:w| function for <key>. -% \end{function} -% -% \begin{function}{\keys_if_exist:n / (TF)} +% Creates a function for <path>, taking <num args> and using <code>. +%\end{function} +% +%\begin{function}{ +% \keys_default_set:n | +% \keys_default_set:V +%} % \begin{syntax} -% "\keys_if_exist:nTF" <key> <true code> -% ~~~~<false code> +% "\keys_default_set:n" <default> % \end{syntax} -% Checks for the existence of a <key>. -% \end{function} -% -% \begin{function}{\keys_if_value:n / (TF)} +% Sets <default> for <key>. +%\end{function} +% +%\begin{function}{ +% \keys_define_elt:n | +% \keys_define_elt:nn +%} % \begin{syntax} -% "\keys_if_value:nTF" <property> <true code> <false code> +% "\keys_define_elt:n" <key> <value> % \end{syntax} -% Checks for the <property> switch of a <key> (typically -% \texttt{required} or \texttt{forbidden}). -% \end{function} -% -% \begin{function}{\keys_manage_internal:n} +% Processing functions for key--value pairs when defining keys. +%\end{function} +% +%\begin{function}{\keys_define_key:n} % \begin{syntax} -% "\keys_manage_internal:n" <keyval list> +% "\keys_define_key:n" <key> % \end{syntax} -% An internal ``recycling'' version of \cs{keys_manage_quick:n}, which -% should not be called from outside. -% \end{function} -% -% \begin{function}{ -% \keys_no_value_elt:n| -% \keys_value_elt:nn -% } +% Defines <key>. +%\end{function} +% +%\begin{function}{\keys_execute:} % \begin{syntax} -% "\keys_no_value_elt:n" <elt> -% "\keys_value_elt:nn" <elt> <value> +% "\keys_execute:" % \end{syntax} -% Functions used by \pkg{l3keyval} for each <elt> of the <keyval -% list> being processed. -% \end{function} -% -% \begin{function}{\keys_parse:n} +% Executes <key>. +%\end{function} +% +%\begin{function}{\keys_execute_unknown:} % \begin{syntax} -% "\keys_parse:n" <keyval list> +% "\keys_execute_unknown:" % \end{syntax} -% Functions which actually parses <keyval list>. -% \end{function} -% -% \begin{function}{\keys_parse_list:n} +% Handles unknown <key> names. +%\end{function} +% +%\begin{function}{\keys_if_value_requirement:nTF} % \begin{syntax} -% "\keys_parse_list:n" <keyval list> +% "\keys_if_value_requirement:nTF" <requirement> +% ~~~~<true code> <false code> % \end{syntax} -% Set up macro for \cs{keys_parse:n}. -% \end{function} -% -% \begin{function}{ -% \keys_path_add:N| -% \keys_path_add:w -% } +% Check if <requirement> applies to <key>. +%\end{function} +% +%\begin{function}{\keys_property_find:n} % \begin{syntax} -% "\keys_path_add:N" <tl> -% "\keys_path_add:w" <tlist> "\q_stop" +% "\keys_property_find:n" <key> % \end{syntax} -% Adds a full path to key name stored in <tl> or given as <tlist>. -% \end{function} -% -% \begin{function}{\keys_process_elt:nn} +% Separates <key> from <property>. +%\end{function} +% +%\begin{function}{\keys_property_new:nn} % \begin{syntax} -% "\keys_process_elt:nn" <elt> <value> +% "\keys_property_new:nn" <property> <code> % \end{syntax} -% Lead-off processor for converting <elt> into a fully-qualified -% <key> and checking validity of <value>. -% \end{function} -% -% \begin{function}{ -% \keys_separate_path:| -% \keys_separate_path:w -% } +% Makes a new <property> expanding to <code> +%\end{function} +% +%\begin{function}{\keys_property_undefine:n} % \begin{syntax} -% "\keys_separate_path:" -% "\keys_separate_path:w" / <path 1> / <path 2> "\q_stop" +% "\keys_property_undefine:n" <property> % \end{syntax} -% Separates key into <path> and <key name>. -% \end{function} -% -% \begin{function}{ -% \keys_set:NN| -% \keys_set:Nnn| -% } +% Deletes <property> of <key>. +%\end{function} +% +%\begin{function}{ +% \keys_set_elt:n | +% \keys_set_elt:nn +%} % \begin{syntax} -% "\keys_set:NN" <function> <variable> -% "\keys_set:Nnn" <function> <prefix> <name> +% "\keys_set_elt:n" <key> <value> % \end{syntax} -% Uses <function> to store <value> in <variable>. If a <name> is -% given, it is used to construct a csname for the variable including -% the current <module>. The <prefix> should be |l_| or |g_|. -% \end{function} -% -% \begin{function}{ -% \keys_set_cmd:nn| -% \keys_set_cmd:nx| -% \keys_set_cmd:nNn| -% \keys_set_cmd:nNx| -% } +% Processing functions for key--value pairs when setting keys. +%\end{function} +% +%\begin{function}{\keys_tmp:w} % \begin{syntax} -% "\keys_set_cmd:nn" <key> <code> -% "\keys_set_cmd:nNn" <key> <number> <code> +% "\keys_tmp:w" <args> % \end{syntax} -% Creates a |._cmd:w| function for <key>, with definition <code>. The -% \texttt{N} variant can include <number> parameters. -% \end{function} -% -% \begin{function}{ -% \keys_store:nn| -% \keys_store:nx -% } +% Used to store <code> to execute a <key>. +%\end{function} +% +%\begin{function}{\keys_value_or_default:n} % \begin{syntax} -% "\keys_store:nn" <key> <data> +% "\keys_value_or_default:n" <value> % \end{syntax} -% Stores <data> in <key> function. -% \end{function} -% -% \begin{function}{\keys_toks_set:Nn} +% Sets \cs{l_keys_value_toks} to <value>, or <default> if +% <value> was not given and if <default> is available. +%\end{function} +% +%\begin{function}{\keys_value_requirement:n} % \begin{syntax} -% "\keys_toks_set:Nn" <toks> <key> +% "\keys_value_requirement:nn" <requirement> % \end{syntax} -% Sets <toks> equal to the content of <key> -% \end{function} -% -% \begin{function}{\keys_try:} +% Sets <key> to have <requirement> concerning <value>. +%\end{function} +% +%\begin{function}{\keys_variable_set:NN} % \begin{syntax} -% "\keys_try:" +% "\keys_variable_set:NN" <expansion> <var> % \end{syntax} -% Attempt to execute a key, with no error if the key is unknown. -% \end{function} +% Sets <key> to assign <value> to <variable> +%\end{function} % -% \begin{function}{\keys_undefine:n} +%\begin{function}{ +% \keys_variable_get_scope:N / (EXP) | +% \keys_variable_get_type:N / (EXP) +%} % \begin{syntax} -% "\keys_undefine:n" <key> +% "\keys_variable_get_scope:N" <var> % \end{syntax} -% Delete definition of <key>. -% \end{function} +% Returns the scope (\texttt{g} or blank) or the type of <var>. +%\end{function} % -% \begin{function}{\keys_use:n} -% \begin{syntax} -% "\keys_use:n" <key> -% \end{syntax} -% Use definition of <key>. -% \end{function} +%\subsection{Variables and constants} +% +%\begin{variable}{ +% \c_keys_properties_root_tl| +% \c_keys_root_tl +%} +% The root paths for keys and properties. +%\end{variable} % -% \begin{function}{ -% \keys_use_cmd:n| -% \keys_use_cmd:nn -% } -% \begin{syntax} -% "\keys_use_cmd:n" <key> -% "\keys_use_cmd:nn" <key> <arg> -% \end{syntax} -% Uses the |._cmd:w| function for <key>, passing <arg> if needed. -% \end{function} +%\begin{variable}{ +% \c_keys_value_forbidden_tl| +% \c_keys_value_required_tl +%} +% Marker text containers. +%\end{variable} % -%\subsubsection{Internal properties} -% -% The internal key properties should not be accessed directly. +%\begin{variable}{ +% \l_keys_module_tl| +% \l_keys_path_tl +%} +% Various key paths need to be stored. +%\end{variable} % -% \begin{function}{._cmd:w} -% \begin{syntax} -% \end{syntax} -% The function which is executed for a key with \texttt{.code}. -% \end{function} +%\begin{variable}{\l_keys_no_value_bool} +% A marker for ``no value'' as key input. +%\end{variable} % -% \begin{function}{._default_tl} -% \begin{syntax} -% \end{syntax} -% Holds the default value for a key. -% \end{function} +%\begin{variable}{\l_keys_value_toks} +% Holds the currently supplied value. +%\end{variable} % -% \begin{function}{._forbidden_bool} -% \begin{syntax} -% \end{syntax} -% Indicates that a value cannot be given for <key>. -% \end{function} -% -% \begin{function}{._num_args_tl} -% \begin{syntax} -% \end{syntax} -% For functions defined with \texttt{.code:Nn} and \texttt{.code:Nx}, -% contains the number of arguments the associated |._cmd:w| function -% takes. -% \end{function} -% -% \begin{function}{._required_bool} -% \begin{syntax} -% \end{syntax} -% Indicates that <key> must have a value provided. -% \end{function} -% -% \end{documentation} +%\end{documentation} % -% \begin{implementation} -% -%\subsection{Implementation} +%\begin{implementation} % % The usual preliminaries. % \begin{macrocode} @@ -1055,124 +681,53 @@ This work consists of the file keys3.dtx {\filename}{\filedate}{\fileversion}{\filedescription} % \end{macrocode} % -%\subsubsection{Variables and contrasts} -% -%\begin{macro}{\c_keys_0_empty_tl} -%\begin{macro}{\c_keys_1_empty_tl} -%\begin{macro}{\c_keys_2_empty_tl} -%\begin{macro}{\c_keys_3_empty_tl} -%\begin{macro}{\c_keys_4_empty_tl} -%\begin{macro}{\c_keys_5_empty_tl} -%\begin{macro}{\c_keys_6_empty_tl} -%\begin{macro}{\c_keys_7_empty_tl} -%\begin{macro}{\c_keys_8_empty_tl} -%\begin{macro}{\c_keys_9_empty_tl} -% A set of empty arguments. -% \begin{macrocode} -\tl_new:cn { c_keys_0_empty_tl } {} -\tl_new:cn { c_keys_1_empty_tl } { {} } -\tl_new:cn { c_keys_2_empty_tl } { {} {} } -\tl_new:cn { c_keys_3_empty_tl } { {} {} {} } -\tl_new:cn { c_keys_4_empty_tl } { {} {} {} {} } -\tl_new:cn { c_keys_5_empty_tl } { {} {} {} {} {} } -\tl_new:cn { c_keys_6_empty_tl } { {} {} {} {} {} {} } -\tl_new:cn { c_keys_7_empty_tl } { {} {} {} {} {} {} {} } -\tl_new:cn { c_keys_8_empty_tl } { {} {} {} {} {} {} {} {} } -\tl_new:cn { c_keys_9_empty_tl } { {} {} {} {} {} {} {} {} {} } -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -% -%\begin{macro}{\c_keys_cs_prefix_tl} -% First, the small number of constants needed are created. A prefix is -% used to keep all of the actual key macros in one place. -% \begin{macrocode} -\tl_new:Nn \c_keys_cs_prefix_tl { keys-root } -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\c_keys_errors_path_tl} -%\begin{macro}{\c_keys_properties_path_tl} -%\begin{macro}{\c_keys_utilities_path_tl} -% The locations of all of the keys used by \pkg{keys3} itself. -% \begin{macrocode} -\tl_new:Nn \c_keys_errors_path_tl { /keys/errors } -\tl_new:Nn \c_keys_properties_path_tl { /keys/properties } -\tl_new:Nn \c_keys_utilities_path_tl { /keys } -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} +%\subsubsection{Variables and constants} % %\begin{macro}{\c_keys_root_tl} -% The key root should have a clear name; like all of the key macros, -% this does not include the prefix. +%\begin{macro}{\c_keys_properties_root_tl} +% Where the keys are really stored. % \begin{macrocode} -\tl_new:Nn \c_keys_root_tl { / } +\tl_new:Nn \c_keys_root_tl { keys~>~ } +\tl_new:Nn \c_keys_properties_root_tl { keys_properties } % \end{macrocode} %\end{macro} -% -%\begin{macro}{\l_keys_choice_code_tl} -% When making choices, the code for each key has to be stored. -% \begin{macrocode} -\tl_new:N \l_keys_choice_code_tl -% \end{macrocode} %\end{macro} % -%\begin{macro}{\l_keys_current_choice_tl} -%\begin{macro}{\l_keys_current_choice_int} -% Multiple choices need some storage. +%\begin{macro}{\c_keys_value_forbidden_tl} +%\begin{macro}{\c_keys_value_required_tl} +% Two marker token lists. % \begin{macrocode} -\tl_new:N \l_keys_current_choice_tl -\int_new:N \l_keys_current_choice_int +\tl_new:Nn \c_keys_value_forbidden_tl { forbidden } +\tl_new:Nn \c_keys_value_required_tl { required } % \end{macrocode} %\end{macro} %\end{macro} % -%\begin{macro}{\l_keys_current_key_full_tl} -%\begin{macro}{\l_keys_current_key_name_tl} -% The current key name and the fully-qualified key are stored. +%\begin{macro}{\l_keys_choice_int} +%\begin{macro}{\l_keys_choice_tl} +% Used for the multiple choice system. % \begin{macrocode} -\tl_new:N \l_keys_current_key_full_tl -\tl_new:N \l_keys_current_default_tl +\int_new:N \l_keys_choice_int +\tl_new:N \l_keys_choice_tl % \end{macrocode} %\end{macro} %\end{macro} % -%\begin{macro}{\l_keys_current_module_tl} -% The module name of the current module is stored here. -% \begin{macrocode} -\tl_new:N \l_keys_current_module_tl -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\l_keys_current_path_tl} -%\begin{macro}{\l_keys_default_path_tl} -%\begin{macro}{\l_keys_choice_path_tl} -% The current and default paths can be stored as tls. The default path -% is then initialised as the key root. +%\begin{macro}{\l_keys_key_tl} +%\begin{macro}{\l_keys_path_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_current_path_tl -\tl_new:N \l_keys_default_path_tl -\tl_set_eq:NN \l_keys_default_path_tl \c_keys_root_tl -\tl_new:N \l_keys_choice_path_tl +\tl_new:N \l_keys_key_tl +\tl_new:N \l_keys_path_tl % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} % -%\begin{macro}{\l_keys_current_value_toks} -% The current value is stored in a token register. +%\begin{macro}{\l_keys_module_tl} +% The module for an entire set of keys. % \begin{macrocode} -\toks_new:N \l_keys_current_value_toks +\tl_new:N \l_keys_module_tl % \end{macrocode} %\end{macro} % @@ -1183,748 +738,466 @@ This work consists of the file keys3.dtx % \end{macrocode} %\end{macro} % -%\begin{macro}{\l_keys_success_bool} -% A switch for trying keys. +%\begin{macro}{\l_keys_value_toks} +% A token register for the given value. % \begin{macrocode} -\bool_new:N \l_keys_success_bool +\toks_new:N \l_keys_value_toks % \end{macrocode} %\end{macro} % -%\begin{macro}{\l_keys_tmpa_tl} -% A scratch area. -% \begin{macrocode} -\tl_new:N \l_keys_tmpa_tl -% \end{macrocode} -%\end{macro} -% -%\subsubsection{Functions} -% -%\begin{macro}{\keys_manage:n} -%\begin{macro}{\keys_manage_quick:n} -%\begin{macro}{\keys_manage_internal:n} -%\begin{macro}[aux]{\keys_manage_aux:nn} -%\begin{macro}[aux]{\keys_manage_aux:Vn} -% The main key management macros both call the auxiliary function after -% setting up the parser. The expansion trick means a literal path is -% sent to the later function, and so the default path can be redefined. -% \begin{macrocode} -\cs_new:Nn \keys_manage:n { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_removal_sanitize:n - \tl_clear:N \l_keys_current_module_tl - \keys_manage_internal:n {#1} -} -\cs_new:Nn \keys_manage_quick:n { - \cs_set_eq:NN \keys_parse:n \KV_parse_no_space_removal_no_sanitize:n - \tl_clear:N \l_keys_current_module_tl - \keys_manage_internal:n {#1} -} -\cs_new:Nn \keys_manage_internal:n { - \keys_manage_aux:Vn \l_keys_default_path_tl {#1} -} -\cs_new:Nn \keys_manage_aux:nn { - \tl_set_eq:NN \l_keys_default_path_tl \c_keys_root_tl - \keys_parse_list:n {#2} - \tl_set:Nn \l_keys_default_path_tl {#1} -} -\cs_generate_variant:Nn \keys_manage_aux:nn { Vn } -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\begin{macro}{\keys_manage:nn} -%\begin{macro}{\keys_manage_quick:nn} -%\begin{macro}[aux]{\keys_manage_aux:nnn} -%\begin{macro}[aux]{\keys_manage_aux:Vnn} -% This version uses the same tricks but includes the path as a second -% argument. When setting lots of keys separately, this is a little -% faster than the key-based method. -% \begin{macrocode} -\cs_new:Nn \keys_manage:nn { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_removal_sanitize:n - \keys_manage_aux:Vnn \l_keys_default_path_tl {#1} {#2} -} -\cs_new:Nn \keys_manage_quick:nn { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_no_removal_no_sanitize:n - \keys_manage_aux:Vnn \l_keys_default_path_tl {#1} {#2} -} -\cs_new:Nn \keys_manage_aux:nnn { - \tl_set:Nn \l_keys_default_path_tl {#2} - \tl_clear:N \l_keys_current_module_tl - \keys_parse_list:n {#3} - \tl_set:Nn \l_keys_default_path_tl {#1} -} -\cs_generate_variant:Nn \keys_manage_aux:nnn { Vnn } -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -% %\subsubsection{Internal functions} % -%\begin{macro}{\keys_bool_new:n} -% To create a new switch, which will be true (as the existence of the -% switch is the flag here). +%\begin{macro}{\keys_bool_set:N} +%\begin{macro}{\keys_bool_set_inverse:N} +%\begin{macro}[aux]{\keys_bool_set_aux:N} +% Boolean keys are really just choices, but all done by hand. % \begin{macrocode} -\cs_new_nopar:Nn \keys_bool_new:n { - \bool_new:c { \c_keys_cs_prefix_tl #1 } - \bool_set_true:c { \c_keys_cs_prefix_tl #1 } -} -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\keys_bool_set:nN} -%\begin{macro}{\keys_bool_set:nnn} -% Boolean keys are created by using the fact that only \texttt{true} and -% \texttt{false} give the right result when looking for a setting -% function. A default is also set, so that the key name alone can be -% given. -% \begin{macrocode} -\cs_new_nopar:Nn \keys_bool_set:nN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - \cs_if_exist:cTF { bool_ #1 _ ##1 :N } { - \use:c { bool_ #1 _ ##1 :N } #2 - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true +\cs_new_nopar:Nn \keys_bool_set:N { + \keys_cmd_set:nNx { \l_keys_path_tl / true } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_true:N } + \exp_not:N #1 } -} -\cs_new_nopar:Nn \keys_bool_set:nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N \cs_if_exist:cTF { bool_ #1 _ ##1 :c } { - \exp_not:N \use:c { bool_ #1 _ ##1 :c } - { #2 \l_keys_current_module_tl #3 _bool } - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true + \keys_cmd_set:nNx { \l_keys_path_tl / false } 1 { + \exp_not:N \use:c + { bool_ \keys_variable_get_scope:N #1 set_false:N } + \exp_not:N #1 } + \keys_bool_set_aux:N #1 } -% \end{macrocode} -%\end{macro} -%\end{macro} -% -%\begin{macro}{\keys_bool_set_inverse:n} -%\begin{macro}{\keys_bool_set_inverse:nN} -%\begin{macro}{\keys_bool_set_inverse:nnn} -% To set keys with reversed logic, the basics can be done in the same -% way as for the standard switches. The only thing needed is a -% reversal of \texttt{true}/\texttt{false}. -% \begin{macrocode} -\cs_new_nopar:Nn \keys_bool_set_inverse:n { - \tl_if_eq:nnTF {#1} { true } { false } { true } -} -\cs_new_nopar:Nn \keys_bool_set_inverse:nN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - \cs_if_exist:cTF { bool_ #1 _ ##1 :N } { - \use:c { bool_ #1 _ \keys_bool_set_inverse:n {##1} :N } #2 - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true +\cs_new_nopar:Nn \keys_bool_set_inverse:N { + \keys_cmd_set:nNx { \l_keys_path_tl / true } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_false:N } + \exp_not:N #1 } -} -\cs_new_nopar:Nn \keys_bool_set_inverse:nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N \cs_if_exist:cTF { bool_ #1 _ ##1 :c } { - \exp_not:N \use:c { - bool_ #1 _ \exp_not:N \keys_bool_set_inverse:n {##1} :c - } { #2 \l_keys_current_module_tl #3 _bool } - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true + \keys_cmd_set:nNx { \l_keys_path_tl / false } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_true:N } + \exp_not:N #1 } + \keys_bool_set_aux:N #1 } -% \end{macrocode} -%\end{macro} -%\end{macro} -%\end{macro} -% -%\begin{macro}{\keys_check_exists:NN} -%\begin{macro}{\keys_check_exists:cN} -% A check function to avoid problems later. -% \begin{macrocode} -\cs_new_nopar:Nn \keys_check_exists:NN { +\cs_new_nopar:Nn \keys_bool_set_aux:N { + \keys_choice_make: \cs_if_exist:NF #1 { - #2 #1 + \bool_new:N #1 } + \keys_default_set:n { true } } -\cs_generate_variant:Nn \keys_check_exists:NN { cN } % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} % -%\begin{macro}{\keys_choices_create:Nnn} -%\begin{macro}[aux]{\keys_choices_create_aux:n} -%\begin{macro}[aux]{\keys_choices_create_aux:x} -%\begin{macro}{\keys_choice_create:n} -% When making multiple choices, the code for each choice is the same. -% Only the path and counter need to be altered. +%\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:Nn \keys_choices_create:Nnn { - \tl_set_eq:NN \l_keys_choice_path_tl \l_keys_current_path_tl - \int_zero:N \l_keys_current_choice_int - \use:c { keys_choices_create_aux: #1 } {#3} - \clist_map_function:nN {#2} \keys_choice_create:n - \keys_manage_internal:n { \l_keys_choice_path_tl /.expects_choice: } -} -\cs_new:Nn \keys_choices_create_aux:n { - \tl_set:Nn \l_keys_choice_code_tl { \exp_not:n {#1} } -} -\cs_new:Nn \keys_choices_create_aux:x { - \tl_set:Nn \l_keys_choice_code_tl {#1} -} -\cs_new_nopar:Nn \keys_choice_create:n { - \int_incr:N \l_keys_current_choice_int - \keys_parse_list:n { - \l_keys_choice_path_tl / #1 /.code:x = { - \exp_not:n { \int_set:Nn \l_keys_current_choice_int } - { \int_use:N \l_keys_current_choice_int } - \exp_not:n { \tl_set:Nn \l_keys_current_choice_tl } {#1} - \l_keys_choice_code_tl - } +\cs_new_nopar:Nn \keys_choice_find:n { + \keys_execute_aux:nn { \l_keys_path_tl / #1 } { + \keys_execute_aux:nn { \l_keys_path_tl / unknown } { } } } % \end{macrocode} %\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{\keys_clear_properties:n} -% To avoid problem on redefinition, all properties are removed. +%\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_nopar:Nn \keys_clear_properties:n { - \keys_undefine:n { #1 /._cmd:w } - \keys_undefine:n { #1 /._default_tl } - \keys_undefine:n { #1 /._forbidden_bool } - \keys_undefine:n { #1 /._num_args_tl } - \keys_undefine:n { #1 /._required_bool } +\cs_new_nopar:Nn \keys_choice_make: { + \keys_cmd_set:nNn { \l_keys_path_tl } 1 { + \keys_choice_find:n {##1} + } + \keys_cmd_set:nNn { \l_keys_path_tl / unknown } 1 { + \msg_error:nnxx { keys } { choice~unknown } + { \l_keys_path_tl } {##1} + } } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_default_add:} -% Copies the default value to the current one if needed. +%\begin{macro}{\keys_choices_generate:nx} +%\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_nopar:Nn \keys_default_add: { - \bool_if:NT \l_keys_no_value_bool { - \keys_if_exist:nT - { \l_keys_current_key_full_tl /._default_tl } { - \keys_toks_set:Nn \l_keys_current_value_toks - { \l_keys_current_key_full_tl /._default_tl } - \bool_set_false:N \l_keys_no_value_bool +\cs_new:Nn \keys_choices_generate:nx { + \keys_choice_make: + \int_zero:N \l_keys_choice_int + \cs_set_nopar:Nn \keys_choices_generate_aux:n { + \int_incr:N \l_keys_choice_int + \keys_cmd_set:nNx { \l_keys_path_tl / ##1 } 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 } + #2 } } + \clist_map_function:nN {#1} \keys_choices_generate_aux:n } +\cs_new_nopar:Nn \keys_choices_generate_aux:n { } % \end{macrocode} %\end{macro} +%\end{macro} % -%\begin{macro}{\keys_find_code_full:} -%\begin{macro}{\keys_find_code_name:} -% Two functions to find something to process the key value given. First, -% a search is made for either a command property for the key, or a -% function for the key itself. If that fails, the generic handlers are -% used after separating out the key name and key path. +%\begin{macro}{\keys_cmd_set:nNn} +%\begin{macro}{\keys_cmd_set:nNx} +%\begin{macro}[aux]{\keys_cmd_set_aux:nN} +% Creating a new command means setting properties and then creating +% a function with the correct number of arguments. % \begin{macrocode} -\cs_new_nopar:Nn \keys_find_code_full: { - \keys_if_cmd_exist:nTF { \l_keys_current_key_full_tl } { - \keys_use_cmd:n { \l_keys_current_key_full_tl } - }{ - \keys_if_exist:nTF { \l_keys_current_key_full_tl } { - \bool_if:NTF \l_keys_no_value_bool { - \keys_use:n { \l_keys_current_key_full_tl } - }{ - \keys_store:nx { \l_keys_current_key_full_tl } - { \toks_use:N \l_keys_current_value_toks } - } - }{ - \keys_find_code_name: - } - } +\cs_new:Nn \keys_cmd_set:nNn { + \keys_cmd_set_aux:nN {#1} #2 + \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:w } + \cs_set:Npn #2 {#3} } -\cs_new_nopar:Nn \keys_find_code_name: { - \keys_separate_path: - \keys_if_cmd_exist:nTF - { \c_keys_properties_path_tl / \l_keys_current_key_name_tl } { - \keys_use_cmd:n - {\c_keys_properties_path_tl / \l_keys_current_key_name_tl} - }{ - \keys_if_cmd_exist:nTF - { \l_keys_current_path_tl / unknown } { - \keys_use_cmd:n { \l_keys_current_path_tl / unknown } - }{ - \keys_error:n { unknown~key } - } - } +\cs_new:Nn \keys_cmd_set:nNx { + \keys_cmd_set_aux:nN {#1} #2 + \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:w } + \cs_set:Npx #2 {#3} +} +\cs_new_nopar:Nn \keys_cmd_set_aux:nN { + \keys_property_undefine:n { #1 .default_tl } + \num_set:cn { \c_keys_root_tl #1 .args_num } {#2} + \tl_set:cn { \c_keys_root_tl #1 .req_tl } { } } % \end{macrocode} %\end{macro} %\end{macro} -% -%\begin{macro}[TF]{\keys_if_cmd_exist:n} -% A dedicated check for the |._cmd:w| property key. -% \begin{macrocode} -\prg_new_conditional:Nnn \keys_if_cmd_exist:n {TF,T,F} { - \if_cs_exist:w \c_keys_cs_prefix_tl #1 /._cmd:w \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: -} -% \end{macrocode} %\end{macro} % -%\begin{macro}[TF]{\keys_if_exist:n} -% Check if a key exists without adding to the hash table. +%\begin{macro}{\keys_default_set:n} +%\begin{macro}{\keys_default_set:V} +% Setting a default value is easy. % \begin{macrocode} -\prg_new_conditional:Nnn \keys_if_exist:n {TF,T,F} { - \if_cs_exist:w \c_keys_cs_prefix_tl #1 \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: +\cs_new:Nn \keys_default_set:n { + \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}[TF]{\keys_if_value:n} -% Used for required and forbidden values. +%\begin{macro}{\keys_define:nn} +% The main key-defining function mainly sets up things for \pkg{l3keyval} +% to use. % \begin{macrocode} -\prg_new_conditional:Nnn \keys_if_value:n {TF,T,F} { - \if_cs_exist:w - \c_keys_cs_prefix_tl \l_keys_current_key_full_tl /._ #1 _bool - \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: +\cs_new:Nn \keys_define:nn { + \tl_set:Nn \l_keys_module_tl {#1} + \cs_set_eq:NN \KV_key_no_value_elt:n \keys_define_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \keys_define_elt:nn + \KV_parse_no_space_removal_no_sanitize:n {#2} } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_no_value_elt:n} -%\begin{macro}{\keys_value_elt:nn} -% The two functions passed to \pkg{l3keyval} to actually act on each -% key found. +%\begin{macro}{\keys_define_elt:n} +%\begin{macro}{\keys_define_elt:nn} +% The element processors for defining keys. % \begin{macrocode} -\cs_new:Nn \keys_no_value_elt:n { +\cs_new:Nn \keys_define_elt:n { \bool_set_true:N \l_keys_no_value_bool - \keys_process_elt:nn {#1} { } + \keys_define_elt_aux:nn {#1} { } } -\cs_new:Nn \keys_value_elt:nn { +\cs_new:Nn \keys_define_elt:nn { \bool_set_false:N \l_keys_no_value_bool - \keys_process_elt:nn {#1} {#2} + \keys_define_elt_aux:nn {#1} {#2} } % \end{macrocode} %\end{macro} %\end{macro} -% -%\begin{macro}{\keys_parse:n} -% The macro used to actually process the key--value input is taken from -% \pkg{l3keyval}. There are two possible options, and so at this -% stage the macro is simply reserved. -% \begin{macrocode} -\cs_new:Nn \keys_parse:n { \ERROR } -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\keys_parse_list:n} -% All of the management macros call this common parser. First, the key -% processing macros are defined, then the appropriate parser is called. -% \begin{macrocode} -\cs_new:Nn \keys_parse_list:n { - \cs_set_eq:NN \KV_key_value_elt:nn \keys_value_elt:nn - \cs_set_eq:NN \KV_key_no_value_elt:n \keys_no_value_elt:n - \keys_parse:n {#1} -} -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\keys_path_add:N} -%\begin{macro}{\keys_path_add:w} -%\begin{macro}[aux]{\keys_path_add_aux:w} -% The code to check for a path looks for a |/| at the start of the key. +%\begin{macro}[aux]{\keys_define_elt_aux:nn} +% The auxiliary function does most of the work. % \begin{macrocode} -\cs_new_nopar:Nn \keys_path_add:N { - \exp_after:wN \keys_path_add:w #1 \q_stop -} -\cs_new_nopar:Npn \keys_path_add:w { - \exp_after:wN \peek_meaning:NTF \c_keys_root_tl { - \use_none_delimit_by_q_stop:w +\cs_new:Nn \keys_define_elt_aux:nn { + \keys_property_find:n {#1} + \cs_set_eq:Nc \keys_tmp:w + { \c_keys_properties_root_tl \l_keys_key_tl } + \cs_if_exist:NTF \keys_tmp:w { + \keys_define_key:n {#2} }{ - \keys_path_add_aux:w + \msg_error:nnx { keys } { property~unknown } + { \l_keys_key_tl } } } -\cs_new_nopar:Npn \keys_path_add_aux:w #1 \q_stop { - \tl_set:Nx \l_keys_current_key_full_tl {\l_keys_default_path_tl #1} -} % \end{macrocode} %\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{\keys_process_elt:nn} -%\begin{macro}[aux]{\keys_process_elt_aux:} -% The key processor starts by storing the given key name and value, and -% adding a path to the former if necessary. There is then potentially a -% need to fill in a default value before checking for required or -% forbidden values. +%\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:Nn \keys_process_elt:nn { - \tl_set:Nx \l_keys_current_key_full_tl {#1} - \toks_set:Nn \l_keys_current_value_toks {#2} - \keys_path_add:N \l_keys_current_key_full_tl - \keys_default_add: - \keys_if_value:nTF { required } { - \bool_if:NTF \l_keys_no_value_bool { - \keys_error:n { value~required } +\cs_new:Nn \keys_define_key:n { + \bool_if:NTF \l_keys_no_value_bool { + \intexpr_compare:nTF { + \exp_args:Nc \cs_get_arg_count_from_signature:N + { \l_keys_key_tl } = \c_zero + } { + \keys_tmp:w }{ - \keys_process_elt_aux: - } + \msg_error:nnx { keys } { property~value~required } + { \l_keys_key_tl } + } }{ - \keys_process_elt_aux: - } -} -\cs_new:Nn \keys_process_elt_aux: { - \keys_if_value:nTF { forbidden } { - \bool_if:NTF \l_keys_no_value_bool { - \keys_find_code_full: + \intexpr_compare:nTF { + \exp_args:Nc \cs_get_arg_count_from_signature:N + { \l_keys_key_tl } = \c_one + } { + \keys_tmp:w {#1} }{ - \keys_error:nn { value~forbidden } - { \toks_use:N \l_keys_current_value_toks } + \keys_tmp:w #1 } - }{ - \keys_find_code_full: } } % \end{macrocode} %\end{macro} -%\end{macro} % -%\begin{macro}{\keys_separate_path:} -%\begin{macro}{\keys_separate_path:w} -% A simple piece of recursion to find the key name and path. +%\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_nopar:Nn \keys_separate_path: { - \tl_clear:N \l_keys_current_path_tl - \exp_after:wN \keys_separate_path:w \l_keys_current_key_full_tl - / \q_stop +\cs_new_nopar:Nn \keys_execute: { + \keys_execute_aux:nn { \l_keys_path_tl } { + \keys_execute_unknown: + } } -\cs_new_nopar:Npn \keys_separate_path:w / #1 / #2 \q_stop { - \tl_if_empty:nTF {#2} { - \tl_set:Nn \l_keys_current_key_name_tl {#1} - }{ - \tl_put_right:Nn \l_keys_current_path_tl { / #1 } - \keys_separate_path:w /#2 \q_stop +\cs_new_nopar:Nn \keys_execute_unknown: { + \keys_execute_aux:nn { \l_keys_module_tl / unknown } { + \msg_error:nnx { keys } { key~unknown } { \l_keys_path_tl } } } % \end{macrocode} -%\end{macro} -%\end{macro} -% -%\begin{macro}{\keys_set:NN} -%\begin{macro}{\keys_set:Nnn} -% Storage of data in outside of keys. +% 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! % \begin{macrocode} -\cs_new_nopar:Nn \keys_set:NN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - #1 #2 {##1} - } - } -} -\cs_new_nopar:Nn \keys_set:Nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N #1 { #2 \l_keys_current_module_tl #3 } {##1} +\cs_new_nopar:Nn \keys_execute_aux:nn { + \cs_set_eq:Nc \keys_tmp:w { \c_keys_root_tl #1 .cmd:w } + \cs_if_exist:NTF \keys_tmp:w { + \intexpr_compare:nTF { + \num_use:c { \c_keys_root_tl #1 .args_num } = \c_one + } { + \exp_args:NV \keys_tmp:w \l_keys_value_toks + }{ + \exp_after:wN \keys_tmp:w \toks_use:N \l_keys_value_toks } + }{ + #2 } } % \end{macrocode} %\end{macro} %\end{macro} +%\end{macro} % -%\begin{macro}{\keys_set_cmd:nn} -%\begin{macro}{\keys_set_cmd:nx} -%\begin{macro}{\keys_set_cmd:nNn} -%\begin{macro}{\keys_set_cmd:nNx} -%\begin{macro}{._cmd:w} -%\begin{macro}{._num_args_tl} -% Creation of the key |._cmd:w| macros happens here. For the -% multiple-argument versions, the number of arguments is stored for -% use later on. +%\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:Nn \keys_set_cmd:nn { - \keys_clear_properties:n {#1} - \cs_set:cpn { \c_keys_cs_prefix_tl #1 /._cmd:w } ##1 {#2} -} -\cs_new:Nn \keys_set_cmd:nx { - \keys_clear_properties:n {#1} - \cs_set:cpx { \c_keys_cs_prefix_tl #1 /._cmd:w } ##1 {#2} -} -\cs_new:Nn \keys_set_cmd:nNn { - \keys_clear_properties:n {#1} - \cs_generate_from_arg_count:cNnn { \c_keys_cs_prefix_tl #1 /._cmd:w } - \cs_set:Npn #2 {#3} - \keys_store:nn { #1 /._num_args_tl} {#2} -} -\cs_new:Nn \keys_set_cmd:nNx { - \keys_clear_properties:n {#1} - \cs_generate_from_arg_count:cNnn { \c_keys_cs_prefix_tl #1 /._cmd:w } - \cs_set:Npx #2 {#3} - \keys_store:nn { #1 /._num_args_tl} {#2} +\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} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{\keys_store:nn} -%\begin{macro}{\keys_store:nx} -% Direct storage of data in keys. +%\begin{macro}{\keys_property_find: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:Nn \keys_store:nn { - \tl_set:cn { \c_keys_cs_prefix_tl #1 } {#2} +\cs_new_nopar:Nn \keys_property_find:n { + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } + \tl_if_in:nnTF {#1} {.} { + \keys_property_find_aux:n {#1} + }{ + \msg_error:nnx { keys } { no~property } { #1 } + } } -\cs_new:Nn \keys_store:nx { - \tl_set:cx { \c_keys_cs_prefix_tl #1 } {#2} +\cs_new_nopar:Nn \keys_property_find_aux:n { + \keys_property_find_aux:w #1 \q_stop +} +\cs_new_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 . #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_key_tl { . #2 } + } } % \end{macrocode} %\end{macro} %\end{macro} % -%\begin{macro}{\keys_toks_set:Nn} -% Sets a toks to the content of a key. +%\begin{macro}{\keys_property_new:nn} +% Creating a new propery is simply a case of making the correctly-named +% function. % \begin{macrocode} -\cs_new_nopar:Nn \keys_toks_set:Nn { - \exp_args:NNv \toks_set:Nn #1 { \c_keys_cs_prefix_tl #2 } +\cs_new_nopar:Nn \keys_property_new:nn { + \cs_new:cn { \c_keys_properties_root_tl #1 } {#2} } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_try:} -% A function to look for the |._cmd:w| property of a key, and executes -% it if found. +%\begin{macro}{\keys_property_undefine:n} +% Removing a property means undefining it. % \begin{macrocode} -\cs_new_nopar:Nn \keys_try: { - \bool_set_false:N \l_keys_success_bool - \keys_if_cmd_exist:nT { \l_keys_current_path_tl } { - \bool_set_true:N \l_keys_success_bool - \bool_if:NT \l_keys_no_value_bool { - \keys_if_exist:nT - { \l_keys_current_path_tl /._default_tl } { - \keys_toks_set:Nn \l_keys_current_value_toks - { \l_keys_current_path_tl /._default_tl } - } - } - \cs_set_eq:NN \l_keys_current_key_full_tl \l_keys_current_path_tl - \keys_use_cmd:n { \l_keys_current_path_tl } - } +\cs_new_nopar:Nn \keys_property_undefine:n { + \cs_set_eq:cN { \c_keys_root_tl #1 } \c_undefined } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_undefine:n} -% To remove a key. +%\begin{macro}{\keys_set:nn} +% The main setting function just does the set up to get \pkg{l3keyval} +% to do the hard work. % \begin{macrocode} -\cs_new_nopar:Nn \keys_undefine:n { - \cs_set_eq:cN { \c_keys_cs_prefix_tl #1 } \c_undefined +\cs_new:Nn \keys_set:nn { + \tl_set:Nn \l_keys_module_tl {#1} + \cs_set_eq:NN \KV_key_no_value_elt:n \keys_set_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \keys_set_elt:nn + \KV_parse_space_removal_sanitize:n {#2} } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_use:n} -% Use whatever is stored in a key. +%\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_nopar:Nn \keys_use:n { - \use:c { \c_keys_cs_prefix_tl #1 } +\cs_new:Nn \keys_set_elt:n { + \bool_set_true:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} { } +} +\cs_new:Nn \keys_set_elt:nn { + \bool_set_false:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} {#2} } % \end{macrocode} %\end{macro} -% -%\begin{macro}{\keys_use_cmd:n} -%\begin{macro}{\keys_use_cmd:nn} -%\begin{macro}[aux]{\keys_use_cmd_aux:nn} -%\begin{macro}[aux]{\keys_use_cmd_aux:w} -% Some care is needed when using command keys. For commands with -% multiple arguments a check is made in case none were given, and if -% so a series of empty values is given instead. +%\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_nopar:Nn \keys_use_cmd:n { - \exp_args:Nno \keys_use_cmd:nn {#1} - { \toks_use:N \l_keys_current_value_toks } -} -\cs_new_nopar:Nn \keys_use_cmd:nn { - \keys_if_exist:nTF { #1 /._num_args_tl } { - \keys_use_cmd_aux:nn {#1} {#2} +\cs_new:Nn \keys_set_elt_aux:nn { + \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_error:nnx { keys } { key~value~required } + { \l_keys_path_tl } + }{ + \keys_set_elt_aux: + } }{ - \keys_use:n {#1/._cmd:w} {#2} - } + \keys_set_elt_aux: + } } -\cs_new_nopar:Nn \keys_use_cmd_aux:nn { - \tl_if_empty:nTF {#2} { - \cs_set:Npn \keys_use_cmd_aux:w { - \keys_use:n { #1 /._cmd:w } +\cs_new_nopar:Nn \keys_set_elt_aux: { + \keys_if_value_requirement:nTF { forbidden } { + \bool_if:NTF \l_keys_no_value_bool { + \keys_execute: + }{ + \msg_error:nnxx { keys} { key~value~forbidden } + { \l_keys_path_tl } + { \toks_use:N \l_keys_value_toks } } - \exp_after:wN \exp_after:wN \exp_after:wN \keys_use_cmd_aux:w - \cs:w - c_keys_ \keys_use:n { #1 /._num_args_tl } _empty_tl - \cs_end: }{ - \keys_use:n { #1 /._cmd:w } #2 + \keys_execute: } } % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} % -%\subsubsection{Error handling code} -% -% The \LaTeX3 approach is to have named errors called separately and -% defined separately. To make life a little easier here, some custom -% functions are used to keep repetition down. -% -%\begin{macro}{\keys_msg_new:nn} -% To create new error messages, a utility function is created. +%\begin{macro}{\keys_show:nn} +% Showing a key is just a question of using the correct name. % \begin{macrocode} -\cs_new_nopar:Npn \keys_msg_new:nn #1 { - \msg_new:nnn { keys } {#1} +\cs_new_nopar:Nn \keys_show:nn { + \cs_show:c { \c_keys_root_tl #1 / \tl_to_str:n {#2} .cmd:w } } % \end{macrocode} %\end{macro} % -%\begin{macro}{\keys_error:n} -%\begin{macro}{\keys_error:nn} -% Utilities for using errors, which always have -% \cs{l_keys_current_key_full_tl} as the first argument. +%\begin{macro}{\keys_tmp:w} +% This scratch function is used to actually execute keys. % \begin{macrocode} -\cs_new_protected_nopar:Nn \keys_error:nn { - \msg_error:nnxx { keys } {#1} { \l_keys_current_key_full_tl } {#2} -} -\cs_new_protected_nopar:Nn \keys_error:n { - \msg_error:nnx { keys } {#1} { \l_keys_current_key_full_tl } -} +\cs_new:Npn \keys_tmp:w {} % \end{macrocode} %\end{macro} -%\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} -\keys_msg_new:nn - { unknown~key } - {The key `#1' is unknown and is being ignored.} -\keys_msg_new:nn - { value~required } - {The key `#1' requires a value\\% - and is being ignored.} -\keys_msg_new:nn - { value~forbidden } - {The key `#1' cannot taken a value:\\% - the given input `#2' is being ignored.} -\keys_msg_new:nn - { Boolean~expected } - {Key `#1' takes the Boolean values\\% - `true' and `false'~only.\\% - The given value `#2' is being ignored.} -\keys_msg_new:nn - { not_boolean } - {Key `#1' is not a Boolean key: you cannot create a complement.} -\keys_msg_new:nn - { unknown~choice } - {Choice `#2' unknown for key `#1':\\% - the key is being ignored.} -% \end{macrocode} -% -%\subsubsection{Property definitions} -% -%\begin{macro}{.code:n} -%\begin{macro}{.code:Nn} -% The \texttt{.code:n} and \texttt{.code:Nn} properties have to be -% defined directly. -% \begin{macrocode} -\keys_set_cmd:nn { \c_keys_properties_path_tl /.code:n } { - \keys_set_cmd:nn { \l_keys_current_path_tl } {#1} -} -\keys_set_cmd:nNn { \c_keys_properties_path_tl /.code:Nn } 2 { - \keys_set_cmd:nNn { \l_keys_current_path_tl } #1 {#2} -} -% \end{macrocode} -%\end{macro} -%\end{macro} -% -% The remaining definitions can all be carried out using the package -% itself. As category codes and spaces are not an issue here, the -% |_quick| version of \cs{keys_manage} is used. -% -% First, an error is created for unknown keys: this is done early to -% catch any internal errors. -% \begin{macrocode} -\keys_manage_quick:n { - \c_keys_errors_path_tl /unknown/.code:n = { - \keys_error:n { unknown~key } - } -} -% \end{macrocode} -% -%\begin{macro}{.code:x} -%\begin{macro}{.code:Nx} -% Fully-expanded versions of the basic \texttt{.code} properties. -% \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.code:x/.code:n = { - \keys_set_cmd:nx { \l_keys_current_path_tl } {#1} - }, - \c_keys_properties_path_tl /.code:Nx/.code:Nn = 2 { - \keys_set_cmd:nNx { \l_keys_current_path_tl } {#1} {#2} +\cs_new:Nn \keys_value_or_default:n { + \toks_set:Nn \l_keys_value_toks {#1} + \bool_if:NT \l_keys_no_value_bool { + \cs_if_exist:cT { \c_keys_root_tl \l_keys_path_tl .default_tl } { + \toks_set:Nv \l_keys_value_toks { + \c_keys_root_tl \l_keys_path_tl .default_tl + } + } } } % \end{macrocode} %\end{macro} -%\end{macro} -% -%\begin{macro}{.cd:} -% The change-directory property simply alters the value of the default -% path. +% +%\begin{macro}{\keys_value_requirement:n} +% Values can be required or forbidden by having the appropriate marker +% set. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.cd:/.code:n = { - \tl_set:Nx \l_keys_default_path_tl { \l_keys_current_path_tl / } - } +\cs_new_nopar:Nn \keys_value_requirement:n { + \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}{.value_forbidden:} -%\begin{macro}{._required_bool} -%\begin{macro}{.value_required:} -%\begin{macro}{._forbidden_bool} -% Values are required or forbidden by creating the appropriate flags. +%\begin{macro}{\keys_variable_get_scope:N} +%\begin{macro}[aux]{\keys_variable_get_scope_aux:N} +%\begin{macro}{\keys_variable_get_type:N} +%\begin{macro}[aux]{\keys_variable_get_type:w} +% Expandable functions to find the type of a variable, and to +% return \texttt{g} if the variable is global. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.value_required:/.code:n = { - \keys_bool_new:n { \l_keys_current_path_tl /._required_bool } - \keys_undefine:n { \l_keys_current_path_tl /._forbidden_bool } - }, - \c_keys_properties_path_tl /.value_forbidden:/.code:n = { - \keys_bool_new:n { \l_keys_current_path_tl /._forbidden_bool } - \keys_undefine:n { \l_keys_current_path_tl /._required_bool } +\cs_new_nopar:Nn \keys_variable_get_scope:N { + \tl_if_eq:xxT { \token_to_str:N g } + { \keys_variable_get_scope_aux:N #1 } + { g } +} +\cs_new_nopar:Nn \keys_variable_get_scope_aux:N { + \exp_last_unbraced:NNo \use_i:nn \use_i_delimit_by_q_stop:nw + \token_to_str:N #1 \q_stop +} +\group_begin: + \char_set_lccode:nn {`\&} {`\_} + \char_make_other:N \& +\tl_to_lowercase:n { + \group_end: + \cs_new_nopar:Nn \keys_variable_get_type:N { + \exp_after:wN \keys_variable_get_type_aux:w + \token_to_str:N #1 & \q_nil \q_stop + } + \cs_new_nopar:Npn \keys_variable_get_type_aux:w #1 & #2 \q_stop { + \quark_if_nil:nTF {#2} { + #1 + }{ + \keys_variable_get_type_aux:w #2 \q_stop + } } } % \end{macrocode} @@ -1933,335 +1206,166 @@ This work consists of the file keys3.dtx %\end{macro} %\end{macro} % -%\begin{macro}{.default:n} -%\begin{macro}{._default_tl} -% The default value for a key is stored in the |._default_tl| -% private property. +%\begin{macro}{\keys_variable_set:NN} +% To set a variable, there is first a check so that it must exist. +% The setting function is then created by recovering the type and +% scope from the variable name. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.default:n/.code:n = { - \keys_store:nn { \l_keys_current_path_tl /._default_tl } {#1} - \keys_undefine:n { \l_keys_current_path_tl /._required_bool } +\cs_new_nopar:Nn \keys_variable_set:NN { + \cs_if_exist:NF #2 { + \use:c { \keys_variable_get_type:N #2 _new:N } #2 + } + \keys_cmd_set:nNx { \l_keys_path_tl } 1 { + \exp_not:c { + \keys_variable_get_type:N #2 _ + \keys_variable_get_scope:N #2 set:N #1 + } \exp_not:N #2 {##1} } } % \end{macrocode} %\end{macro} -%\end{macro} % -%\begin{macro}{.tl_set:N} -%\begin{macro}{.tl_set_x:N} -%\begin{macro}{.tl_gset:N} -%\begin{macro}{.tl_gset_x:N} -% Storage of the value in a tl, as given or expanded, local or global. +%\begin{macro}{.choice:} +% Making a choice is handled internally, as it is also needed by +% \texttt{.generate_choices:nn}. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.tl_set:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_set:Nn #1 - }, - \c_keys_properties_path_tl /.tl_set_x:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_set:Nx #1 - }, - \c_keys_properties_path_tl /.tl_gset:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_gset:Nn #1 - }, - \c_keys_properties_path_tl /.tl_gset_x:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_gset:Nx #1 - } +\keys_property_new:nn { .choice: } { + \keys_choice_make: } % \end{macrocode} %\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{.int_set:N} -%\begin{macro}{.int_gset:N} -%\begin{macro}{.skip_set:N} -%\begin{macro}{.skip_gset:N} -%\begin{macro}{.toks_set:N} -%\begin{macro}{.toks_gset:N} -% For int, skip and toks storage, no expansion to worry about. +%\begin{macro}{.code:n} +%\begin{macro}{.code:x} +%\begin{macro}{.code:Nn} +%\begin{macro}{.code:Nx} +% Creating code is simply a case of passing through to the underlying +% \texttt{set} function. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.int_set:N/.code:n = { - \keys_check_exists:NN #1 \int_new:N - \keys_set:NN \int_set:Nn #1 - }, - \c_keys_properties_path_tl /.int_gset:N/.code:n = { - \keys_check_exists:NN #1 \int_new:N - \keys_set:NN \int_gset:Nn #1 - }, - \c_keys_properties_path_tl /.skip_set:N/.code:n = { - \keys_check_exists:NN #1 \skip_new:N - \keys_set:NN \skip_set:Nn #1 - }, - \c_keys_properties_path_tl /.skip_gset:N/.code:n = { - \keys_check_exists:NN #1 \skip_new:N - \keys_set:NN \skip_gset:Nn #1 - }, - \c_keys_properties_path_tl /.toks_set:N/.code:n = { - \keys_check_exists:NN #1 \toks_new:N - \keys_set:NN \toks_set:Nn #1 - }, - \c_keys_properties_path_tl /.toks_gset:N/.code:n = { - \keys_check_exists:NN #1 \toks_new:N - \keys_set:NN \toks_gset:Nn #1 - } +\keys_property_new:nn { .code:n } { + \keys_cmd_set:nNn { \l_keys_path_tl } 1 {#1} +} +\keys_property_new:nn { .code:Nn } { + \keys_cmd_set:nNn { \l_keys_path_tl } #1 {#2} +} +\keys_property_new:nn { .code:x } { + \keys_cmd_set:nNx { \l_keys_path_tl } 1 {#1} +} +\keys_property_new:nn { .code:Nx } { + \keys_cmd_set:nNx { \l_keys_path_tl } #1 {#2} } % \end{macrocode} %\end{macro} %\end{macro} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} % -% The prefix for the current module is needed when storing material -% by csname. +%\begin{macro}{.default:n} +%\begin{macro}{.default:V} +% Expansion is left to the internal functions. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_utilities_path_tl /current_module:n/.code:n = { - \tl_if_empty:nTF {#1} { - \tl_clear:N \l_keys_current_module_tl - }{ - \tl_set:Nn \l_keys_current_module_tl { #1 _ } - } - } +\keys_property_new:nn { .default:n } { + \keys_default_set:n {#1} } -% \end{macrocode} -% -%\begin{macro}{.tl_set:n} -%\begin{macro}{.tl_set_x:n} -%\begin{macro}{.tl_gset:n} -%\begin{macro}{.tl_gset_x:n} -%\begin{macro}{.int_set:n} -%\begin{macro}{.int_gset:n} -%\begin{macro}{.skip_set:n} -%\begin{macro}{.skip_gset:n} -%\begin{macro}{.toks_set:n} -%\begin{macro}{.toks_gset:n} -% With the module available, storage properties that only need the -% unique part of the variable name are created. -% \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.tl_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_set:cn { l_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_set_x:n/.code:n = { - \keys_check_exists:cN { l_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_set:cx { l_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_gset:cn { g_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_gset_x:n/.code:n = { - \keys_check_exists:cN { g_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_gset:cx { g_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.int_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _int } \int_new:N - \keys_set:Nnn \int_set:cn { l_ } { #1 _int } - }, - \c_keys_properties_path_tl /.int_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _int } \int_new:N - \keys_set:Nnn \int_gset:cn { g_ } { #1 _int } - }, - \c_keys_properties_path_tl /.skip_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _skip } \skip_new:N - \keys_set:Nnn \skip_set:cn { l_ } { #1 _skip } - }, - \c_keys_properties_path_tl /.skip_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _skip } \skip_new:N - \keys_set:Nnn \skip_gset:cn { g_ } { #1 _skip } - }, - \c_keys_properties_path_tl /.toks_set:n/.code:n = { - \keys_check_exists:cN { g_ #1 _toks } \toks_new:N - \keys_set:Nnn \toks_set:cn { l_ } { #1 _toks } - }, - \c_keys_properties_path_tl /.toks_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _toks } \toks_new:N - \keys_set:Nnn \toks_gset:cn { g_ } { #1 _toks } - }, +\keys_property_new:nn { .default:V } { + \keys_default_set:V #1 } % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{.bool_set:N} -%\begin{macro}{.bool_gset:N} -%\begin{macro}{.bool_set:n} -%\begin{macro}{.bool_gset:n} -% The properties for switches look similar, although internally things -% are rather different. +%\begin{macro}{.generate_choices:nn} +%\begin{macro}{.generate_choices:nx} +% Making choices is expansion-dependent. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.bool_set:N/.code:n = { - \keys_bool_set:nN { set } #1 - }, - \c_keys_properties_path_tl /.bool_gset:N/.code:n = { - \keys_bool_set:nN { gset } #1 - }, - \c_keys_properties_path_tl /.bool_set:n/.code:n = { - \keys_bool_set:nnn { set } { l_ } { #1 } - }, - \c_keys_properties_path_tl /.bool_gset:n/.code:n = { - \keys_bool_set:nnn { gset } { g_ } { #1 } - }, +\keys_property_new:nn { .generate_choices:nn } { + \keys_choices_generate:nx {#1} { \exp_not:n {#2} } +} +\keys_property_new:nn { .generate_choices:nx } { + \keys_choices_generate:nx {#1} {#2} } % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{.bool_set_inverse:N} -%\begin{macro}{.bool_gset_inverse:N} -%\begin{macro}{.bool_set_inverse:n} -%\begin{macro}{.bool_gset_inverse:n} -% The inverse versions of the switches are handled in the same way -% here. +%\subsubsection{Properties} +% +%\begin{macro}{.set:N} +%\begin{macro}{.set_x:N} +% Setting a variable is very easy: just pass the data along. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.bool_set_inverse:N/.code:n = { - \keys_bool_set_inverse:nN { set } #1 - }, - \c_keys_properties_path_tl /.bool_gset_inverse:N/.code:n = { - \keys_bool_set_inverse:nN { gset } #1 - }, - \c_keys_properties_path_tl /.bool_set_inverse:n/.code:n = { - \keys_bool_set_inverse:nnn { set } { l_ } { #1 } - }, - \c_keys_properties_path_tl /.bool_gset_inverse:n/.code:n = { - \keys_bool_set_inverse:nnn { gset } { g_ } { #1 } - }, +\keys_property_new:nn { .set:N } { + \keys_variable_set:NN n #1 +} +\keys_property_new:nn { .set_x:N } { + \keys_variable_set:NN x #1 } % \end{macrocode} %\end{macro} %\end{macro} -%\end{macro} -%\end{macro} % -%\begin{macro}{.expects_choice:} -% Multiple choice keys are created by searching sub-keys. So the -% code to make a key into a multiple choice is quite simple. +%\begin{macro}{.set_bool:N} +%\begin{macro}{.set_bool_inverse:N} +% One function for each of these, but this keeps the key functions +% themselves short. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.expects_choice:/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.cd:, - .code:n = { - \tl_set:Nn \l_keys_current_choice_tl {##1} - \int_zero:N \l_keys_current_choice_int - \exp_args:No \keys_parse_list:n - { \l_keys_current_key_full_tl / ##1 } - }, - unknown/.code:n = { - \keys_error:nn { unknown~choice } - { \l_keys_current_key_name_tl } - } - } - }, +\keys_property_new:nn { .set_bool:N } { + \keys_bool_set:N #1 } -% \end{macrocode} -%\end{macro} -%\begin{macro}{.create_choices:nn} -%\begin{macro}{.create_choices:nx} -% Creating choices as a block. -% \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.create_choices:nn/.code:Nn = 2 { - \keys_choices_create:Nnn n {#1} {#2} - }, - \c_keys_properties_path_tl /.create_choices:nx/.code:Nn = 2 { - \keys_choices_create:Nnn x {#1} {#2} - }, +\keys_property_new:nn { .set_bool_inverse:N } { + \keys_bool_set_inverse:N #1 } % \end{macrocode} %\end{macro} %\end{macro} % -%\begin{macro}{.use_keys:n} -%\begin{macro}{.use_keys:x} -%\begin{macro}{.use_keys:Nn} -%\begin{macro}{.use_keys:Nx} -% Keys calling other keys is actually quite easy. +%\begin{macro}{.value_forbidden:} +%\begin{macro}{.value_required:} +% These are very similar, so both call the same function. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.use_keys:n/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:n = { \keys_parse_list:n {#1} } - } - }, - \c_keys_properties_path_tl /.use_keys:x/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:x = { - \exp_not:N \keys_parse_list:n {#1} - } - } - }, - \c_keys_properties_path_tl /.use_keys:Nn/.code:Nn = 2 { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:Nn = #1 { \keys_parse_list:n {#2} } - } - }, - \c_keys_properties_path_tl /.use_keys:Nx/.code:Nn = 2 { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:Nx = - #1 { \exp_not:N \keys_parse_list:n {#2} } - } - } +\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} -%\end{macro} -%\end{macro} % -%\begin{macro}{.try:n} -%\begin{macro}{.retry:n} -% For attempting to set keys without assuming they exist. +%\subsubsection{Messages} +% +% For when the package needs to complain. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.try:n/.code:n = { \keys_try: }, - \c_keys_properties_path_tl /.retry:n/.code:n = { - \bool_if:NF \l_keys_success_bool { \keys_try: } - } +\msg_new:nnn { keys } { choice~unknown } {% + Choice `#2' unknown for key `#1':\\% + the key is being ignored.% +} +\msg_new:nnn { keys } { key~unknown } {% + The key `#1' is unknown and is being ignored.% +} +\msg_new:nnn { keys } { key~value~forbidden }{% + The key `#1' cannot taken a value:\\% + the given input `#2' is being ignored.% +} +\msg_new:nnn { keys } { key~value~required } {% + The key `#1' requires a value\\% + and is being ignored.% +} +\msg_new:nnn { keys } { no~property } {% + No property given in definition of key `#1'.% +} +\msg_new:nnn { keys } { property~unknown } {% + The key property `#1' is unknown.% +} +\msg_new:nnn { keys } { property~value~required } {% + The property `#1' requires a value\\% + and is being ignored.% } % \end{macrocode} -%\end{macro} -%\end{macro} % -%\begin{macro}{.show_code:} -%\begin{macro}{.show_key:} -% Finally, two keys for debugging problems. % \begin{macrocode} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.show_code:/.code:n = { - \cs_show:c { - \c_keys_cs_prefix_tl \l_keys_current_path_tl /._cmd:w - } - }, - \c_keys_properties_path_tl /.show_key:/.code:n = { - \cs_show:c { \c_keys_cs_prefix_tl \l_keys_current_path_tl } - } -} %</package> % \end{macrocode} -%\end{macro} -%\end{macro} % -% \end{implementation} +%\end{implementation}
\ No newline at end of file diff --git a/Master/texmf-dist/tex/latex/keys3/keys3.sty b/Master/texmf-dist/tex/latex/keys3/keys3.sty index 140e038463e..d6881765f8d 100644 --- a/Master/texmf-dist/tex/latex/keys3/keys3.sty +++ b/Master/texmf-dist/tex/latex/keys3/keys3.sty @@ -21,647 +21,367 @@ %% Do not distribute a modified version of this file. %% \RequirePackage{expl3} -\GetIdInfo$Id: keys3.dtx 101 2009-06-10 12:16:20Z josephwright $ +\GetIdInfo$Id: keys3.dtx 110 2009-06-12 21:27:24Z josephwright $ {Key management for LaTeX3} \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} -\tl_new:cn { c_keys_0_empty_tl } {} -\tl_new:cn { c_keys_1_empty_tl } { {} } -\tl_new:cn { c_keys_2_empty_tl } { {} {} } -\tl_new:cn { c_keys_3_empty_tl } { {} {} {} } -\tl_new:cn { c_keys_4_empty_tl } { {} {} {} {} } -\tl_new:cn { c_keys_5_empty_tl } { {} {} {} {} {} } -\tl_new:cn { c_keys_6_empty_tl } { {} {} {} {} {} {} } -\tl_new:cn { c_keys_7_empty_tl } { {} {} {} {} {} {} {} } -\tl_new:cn { c_keys_8_empty_tl } { {} {} {} {} {} {} {} {} } -\tl_new:cn { c_keys_9_empty_tl } { {} {} {} {} {} {} {} {} {} } -\tl_new:Nn \c_keys_cs_prefix_tl { keys-root } -\tl_new:Nn \c_keys_errors_path_tl { /keys/errors } -\tl_new:Nn \c_keys_properties_path_tl { /keys/properties } -\tl_new:Nn \c_keys_utilities_path_tl { /keys } -\tl_new:Nn \c_keys_root_tl { / } -\tl_new:N \l_keys_choice_code_tl -\tl_new:N \l_keys_current_choice_tl -\int_new:N \l_keys_current_choice_int -\tl_new:N \l_keys_current_key_full_tl -\tl_new:N \l_keys_current_default_tl -\tl_new:N \l_keys_current_module_tl -\tl_new:N \l_keys_current_path_tl -\tl_new:N \l_keys_default_path_tl -\tl_set_eq:NN \l_keys_default_path_tl \c_keys_root_tl -\tl_new:N \l_keys_choice_path_tl -\toks_new:N \l_keys_current_value_toks +\tl_new:Nn \c_keys_root_tl { keys~>~ } +\tl_new:Nn \c_keys_properties_root_tl { keys_properties } +\tl_new:Nn \c_keys_value_forbidden_tl { forbidden } +\tl_new:Nn \c_keys_value_required_tl { required } +\int_new:N \l_keys_choice_int +\tl_new:N \l_keys_choice_tl +\tl_new:N \l_keys_key_tl +\tl_new:N \l_keys_path_tl +\tl_new:N \l_keys_module_tl \bool_new:N \l_keys_no_value_bool -\bool_new:N \l_keys_success_bool -\tl_new:N \l_keys_tmpa_tl -\cs_new:Nn \keys_manage:n { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_removal_sanitize:n - \tl_clear:N \l_keys_current_module_tl - \keys_manage_internal:n {#1} -} -\cs_new:Nn \keys_manage_quick:n { - \cs_set_eq:NN \keys_parse:n \KV_parse_no_space_removal_no_sanitize:n - \tl_clear:N \l_keys_current_module_tl - \keys_manage_internal:n {#1} -} -\cs_new:Nn \keys_manage_internal:n { - \keys_manage_aux:Vn \l_keys_default_path_tl {#1} -} -\cs_new:Nn \keys_manage_aux:nn { - \tl_set_eq:NN \l_keys_default_path_tl \c_keys_root_tl - \keys_parse_list:n {#2} - \tl_set:Nn \l_keys_default_path_tl {#1} -} -\cs_generate_variant:Nn \keys_manage_aux:nn { Vn } -\cs_new:Nn \keys_manage:nn { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_removal_sanitize:n - \keys_manage_aux:Vnn \l_keys_default_path_tl {#1} {#2} -} -\cs_new:Nn \keys_manage_quick:nn { - \cs_set_eq:NN \keys_parse:n \KV_parse_space_no_removal_no_sanitize:n - \keys_manage_aux:Vnn \l_keys_default_path_tl {#1} {#2} -} -\cs_new:Nn \keys_manage_aux:nnn { - \tl_set:Nn \l_keys_default_path_tl {#2} - \tl_clear:N \l_keys_current_module_tl - \keys_parse_list:n {#3} - \tl_set:Nn \l_keys_default_path_tl {#1} -} -\cs_generate_variant:Nn \keys_manage_aux:nnn { Vnn } -\cs_new_nopar:Nn \keys_bool_new:n { - \bool_new:c { \c_keys_cs_prefix_tl #1 } - \bool_set_true:c { \c_keys_cs_prefix_tl #1 } -} -\cs_new_nopar:Nn \keys_bool_set:nN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - \cs_if_exist:cTF { bool_ #1 _ ##1 :N } { - \use:c { bool_ #1 _ ##1 :N } #2 - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true +\toks_new:N \l_keys_value_toks +\cs_new_nopar:Nn \keys_bool_set:N { + \keys_cmd_set:nNx { \l_keys_path_tl / true } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_true:N } + \exp_not:N #1 } -} -\cs_new_nopar:Nn \keys_bool_set:nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N \cs_if_exist:cTF { bool_ #1 _ ##1 :c } { - \exp_not:N \use:c { bool_ #1 _ ##1 :c } - { #2 \l_keys_current_module_tl #3 _bool } - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true + \keys_cmd_set:nNx { \l_keys_path_tl / false } 1 { + \exp_not:N \use:c + { bool_ \keys_variable_get_scope:N #1 set_false:N } + \exp_not:N #1 } + \keys_bool_set_aux:N #1 } -\cs_new_nopar:Nn \keys_bool_set_inverse:n { - \tl_if_eq:nnTF {#1} { true } { false } { true } -} -\cs_new_nopar:Nn \keys_bool_set_inverse:nN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - \cs_if_exist:cTF { bool_ #1 _ ##1 :N } { - \use:c { bool_ #1 _ \keys_bool_set_inverse:n {##1} :N } #2 - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true +\cs_new_nopar:Nn \keys_bool_set_inverse:N { + \keys_cmd_set:nNx { \l_keys_path_tl / true } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_false:N } + \exp_not:N #1 } -} -\cs_new_nopar:Nn \keys_bool_set_inverse:nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N \cs_if_exist:cTF { bool_ #1 _ ##1 :c } { - \exp_not:N \use:c { - bool_ #1 _ \exp_not:N \keys_bool_set_inverse:n {##1} :c - } { #2 \l_keys_current_module_tl #3 _bool } - }{ - \keys_error:nn { Boolean~expected } {##1} - } - }, - \l_keys_current_path_tl /.default:n = true + \keys_cmd_set:nNx { \l_keys_path_tl / false } 1 { + \exp_not:c { bool_ \keys_variable_get_scope:N #1 set_true:N } + \exp_not:N #1 } + \keys_bool_set_aux:N #1 } -\cs_new_nopar:Nn \keys_check_exists:NN { +\cs_new_nopar:Nn \keys_bool_set_aux:N { + \keys_choice_make: \cs_if_exist:NF #1 { - #2 #1 + \bool_new:N #1 } + \keys_default_set:n { true } } -\cs_generate_variant:Nn \keys_check_exists:NN { cN } -\cs_new:Nn \keys_choices_create:Nnn { - \tl_set_eq:NN \l_keys_choice_path_tl \l_keys_current_path_tl - \int_zero:N \l_keys_current_choice_int - \use:c { keys_choices_create_aux: #1 } {#3} - \clist_map_function:nN {#2} \keys_choice_create:n - \keys_manage_internal:n { \l_keys_choice_path_tl /.expects_choice: } -} -\cs_new:Nn \keys_choices_create_aux:n { - \tl_set:Nn \l_keys_choice_code_tl { \exp_not:n {#1} } -} -\cs_new:Nn \keys_choices_create_aux:x { - \tl_set:Nn \l_keys_choice_code_tl {#1} -} -\cs_new_nopar:Nn \keys_choice_create:n { - \int_incr:N \l_keys_current_choice_int - \keys_parse_list:n { - \l_keys_choice_path_tl / #1 /.code:x = { - \exp_not:n { \int_set:Nn \l_keys_current_choice_int } - { \int_use:N \l_keys_current_choice_int } - \exp_not:n { \tl_set:Nn \l_keys_current_choice_tl } {#1} - \l_keys_choice_code_tl - } +\cs_new_nopar:Nn \keys_choice_find:n { + \keys_execute_aux:nn { \l_keys_path_tl / #1 } { + \keys_execute_aux:nn { \l_keys_path_tl / unknown } { } } } -\cs_new_nopar:Nn \keys_clear_properties:n { - \keys_undefine:n { #1 /._cmd:w } - \keys_undefine:n { #1 /._default_tl } - \keys_undefine:n { #1 /._forbidden_bool } - \keys_undefine:n { #1 /._num_args_tl } - \keys_undefine:n { #1 /._required_bool } +\cs_new_nopar:Nn \keys_choice_make: { + \keys_cmd_set:nNn { \l_keys_path_tl } 1 { + \keys_choice_find:n {##1} + } + \keys_cmd_set:nNn { \l_keys_path_tl / unknown } 1 { + \msg_error:nnxx { keys } { choice~unknown } + { \l_keys_path_tl } {##1} + } } -\cs_new_nopar:Nn \keys_default_add: { - \bool_if:NT \l_keys_no_value_bool { - \keys_if_exist:nT - { \l_keys_current_key_full_tl /._default_tl } { - \keys_toks_set:Nn \l_keys_current_value_toks - { \l_keys_current_key_full_tl /._default_tl } - \bool_set_false:N \l_keys_no_value_bool +\cs_new:Nn \keys_choices_generate:nx { + \keys_choice_make: + \int_zero:N \l_keys_choice_int + \cs_set_nopar:Nn \keys_choices_generate_aux:n { + \int_incr:N \l_keys_choice_int + \keys_cmd_set:nNx { \l_keys_path_tl / ##1 } 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 } + #2 } } + \clist_map_function:nN {#1} \keys_choices_generate_aux:n +} +\cs_new_nopar:Nn \keys_choices_generate_aux:n { } +\cs_new:Nn \keys_cmd_set:nNn { + \keys_cmd_set_aux:nN {#1} #2 + \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:w } + \cs_set:Npn #2 {#3} +} +\cs_new:Nn \keys_cmd_set:nNx { + \keys_cmd_set_aux:nN {#1} #2 + \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:w } + \cs_set:Npx #2 {#3} +} +\cs_new_nopar:Nn \keys_cmd_set_aux:nN { + \keys_property_undefine:n { #1 .default_tl } + \num_set:cn { \c_keys_root_tl #1 .args_num } {#2} + \tl_set:cn { \c_keys_root_tl #1 .req_tl } { } +} +\cs_new:Nn \keys_default_set:n { + \tl_set:cn { \c_keys_root_tl \l_keys_path_tl .default_tl } {#1} +} +\cs_generate_variant:Nn \keys_default_set:n { V } +\cs_new:Nn \keys_define:nn { + \tl_set:Nn \l_keys_module_tl {#1} + \cs_set_eq:NN \KV_key_no_value_elt:n \keys_define_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \keys_define_elt:nn + \KV_parse_no_space_removal_no_sanitize:n {#2} +} +\cs_new:Nn \keys_define_elt:n { + \bool_set_true:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} { } } -\cs_new_nopar:Nn \keys_find_code_full: { - \keys_if_cmd_exist:nTF { \l_keys_current_key_full_tl } { - \keys_use_cmd:n { \l_keys_current_key_full_tl } +\cs_new:Nn \keys_define_elt:nn { + \bool_set_false:N \l_keys_no_value_bool + \keys_define_elt_aux:nn {#1} {#2} +} +\cs_new:Nn \keys_define_elt_aux:nn { + \keys_property_find:n {#1} + \cs_set_eq:Nc \keys_tmp:w + { \c_keys_properties_root_tl \l_keys_key_tl } + \cs_if_exist:NTF \keys_tmp:w { + \keys_define_key:n {#2} }{ - \keys_if_exist:nTF { \l_keys_current_key_full_tl } { - \bool_if:NTF \l_keys_no_value_bool { - \keys_use:n { \l_keys_current_key_full_tl } - }{ - \keys_store:nx { \l_keys_current_key_full_tl } - { \toks_use:N \l_keys_current_value_toks } - } - }{ - \keys_find_code_name: - } + \msg_error:nnx { keys } { property~unknown } + { \l_keys_key_tl } } } -\cs_new_nopar:Nn \keys_find_code_name: { - \keys_separate_path: - \keys_if_cmd_exist:nTF - { \c_keys_properties_path_tl / \l_keys_current_key_name_tl } { - \keys_use_cmd:n - {\c_keys_properties_path_tl / \l_keys_current_key_name_tl} +\cs_new:Nn \keys_define_key:n { + \bool_if:NTF \l_keys_no_value_bool { + \intexpr_compare:nTF { + \exp_args:Nc \cs_get_arg_count_from_signature:N + { \l_keys_key_tl } = \c_zero + } { + \keys_tmp:w + }{ + \msg_error:nnx { keys } { property~value~required } + { \l_keys_key_tl } + } }{ - \keys_if_cmd_exist:nTF - { \l_keys_current_path_tl / unknown } { - \keys_use_cmd:n { \l_keys_current_path_tl / unknown } + \intexpr_compare:nTF { + \exp_args:Nc \cs_get_arg_count_from_signature:N + { \l_keys_key_tl } = \c_one + } { + \keys_tmp:w {#1} }{ - \keys_error:n { unknown~key } + \keys_tmp:w #1 } } } -\prg_new_conditional:Nnn \keys_if_cmd_exist:n {TF,T,F} { - \if_cs_exist:w \c_keys_cs_prefix_tl #1 /._cmd:w \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: -} -\prg_new_conditional:Nnn \keys_if_exist:n {TF,T,F} { - \if_cs_exist:w \c_keys_cs_prefix_tl #1 \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: -} -\prg_new_conditional:Nnn \keys_if_value:n {TF,T,F} { - \if_cs_exist:w - \c_keys_cs_prefix_tl \l_keys_current_key_full_tl /._ #1 _bool - \cs_end: - \prg_return_true: - \else: - \prg_return_false: - \fi: -} -\cs_new:Nn \keys_no_value_elt:n { - \bool_set_true:N \l_keys_no_value_bool - \keys_process_elt:nn {#1} { } +\cs_new_nopar:Nn \keys_execute: { + \keys_execute_aux:nn { \l_keys_path_tl } { + \keys_execute_unknown: + } } -\cs_new:Nn \keys_value_elt:nn { - \bool_set_false:N \l_keys_no_value_bool - \keys_process_elt:nn {#1} {#2} +\cs_new_nopar:Nn \keys_execute_unknown: { + \keys_execute_aux:nn { \l_keys_module_tl / unknown } { + \msg_error:nnx { keys } { key~unknown } { \l_keys_path_tl } + } +} +\cs_new_nopar:Nn \keys_execute_aux:nn { + \cs_set_eq:Nc \keys_tmp:w { \c_keys_root_tl #1 .cmd:w } + \cs_if_exist:NTF \keys_tmp:w { + \intexpr_compare:nTF { + \num_use:c { \c_keys_root_tl #1 .args_num } = \c_one + } { + \exp_args:NV \keys_tmp:w \l_keys_value_toks + }{ + \exp_after:wN \keys_tmp:w \toks_use:N \l_keys_value_toks + } + }{ + #2 + } } -\cs_new:Nn \keys_parse:n { \ERROR } -\cs_new:Nn \keys_parse_list:n { - \cs_set_eq:NN \KV_key_value_elt:nn \keys_value_elt:nn - \cs_set_eq:NN \KV_key_no_value_elt:n \keys_no_value_elt:n - \keys_parse:n {#1} +\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 + } +} +\cs_new_nopar:Nn \keys_property_find:n { + \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / } + \tl_if_in:nnTF {#1} {.} { + \keys_property_find_aux:n {#1} + }{ + \msg_error:nnx { keys } { no~property } { #1 } + } } -\cs_new_nopar:Nn \keys_path_add:N { - \exp_after:wN \keys_path_add:w #1 \q_stop +\cs_new_nopar:Nn \keys_property_find_aux:n { + \keys_property_find_aux:w #1 \q_stop } -\cs_new_nopar:Npn \keys_path_add:w { - \exp_after:wN \peek_meaning:NTF \c_keys_root_tl { - \use_none_delimit_by_q_stop:w +\cs_new_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 . #1 } + \keys_property_find_aux:w #2 \q_stop }{ - \keys_path_add_aux:w + \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} } + \tl_set:Nn \l_keys_key_tl { . #2 } } } -\cs_new_nopar:Npn \keys_path_add_aux:w #1 \q_stop { - \tl_set:Nx \l_keys_current_key_full_tl {\l_keys_default_path_tl #1} +\cs_new_nopar:Nn \keys_property_new:nn { + \cs_new:cn { \c_keys_properties_root_tl #1 } {#2} +} +\cs_new_nopar:Nn \keys_property_undefine:n { + \cs_set_eq:cN { \c_keys_root_tl #1 } \c_undefined +} +\cs_new:Nn \keys_set:nn { + \tl_set:Nn \l_keys_module_tl {#1} + \cs_set_eq:NN \KV_key_no_value_elt:n \keys_set_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \keys_set_elt:nn + \KV_parse_space_removal_sanitize:n {#2} +} +\cs_new:Nn \keys_set_elt:n { + \bool_set_true:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} { } +} +\cs_new:Nn \keys_set_elt:nn { + \bool_set_false:N \l_keys_no_value_bool + \keys_set_elt_aux:nn {#1} {#2} } -\cs_new:Nn \keys_process_elt:nn { - \tl_set:Nx \l_keys_current_key_full_tl {#1} - \toks_set:Nn \l_keys_current_value_toks {#2} - \keys_path_add:N \l_keys_current_key_full_tl - \keys_default_add: - \keys_if_value:nTF { required } { +\cs_new:Nn \keys_set_elt_aux:nn { + \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 { - \keys_error:n { value~required } + \msg_error:nnx { keys } { key~value~required } + { \l_keys_path_tl } }{ - \keys_process_elt_aux: + \keys_set_elt_aux: } }{ - \keys_process_elt_aux: + \keys_set_elt_aux: } } -\cs_new:Nn \keys_process_elt_aux: { - \keys_if_value:nTF { forbidden } { +\cs_new_nopar:Nn \keys_set_elt_aux: { + \keys_if_value_requirement:nTF { forbidden } { \bool_if:NTF \l_keys_no_value_bool { - \keys_find_code_full: + \keys_execute: }{ - \keys_error:nn { value~forbidden } - { \toks_use:N \l_keys_current_value_toks } + \msg_error:nnxx { keys} { key~value~forbidden } + { \l_keys_path_tl } + { \toks_use:N \l_keys_value_toks } } }{ - \keys_find_code_full: + \keys_execute: } } -\cs_new_nopar:Nn \keys_separate_path: { - \tl_clear:N \l_keys_current_path_tl - \exp_after:wN \keys_separate_path:w \l_keys_current_key_full_tl - / \q_stop -} -\cs_new_nopar:Npn \keys_separate_path:w / #1 / #2 \q_stop { - \tl_if_empty:nTF {#2} { - \tl_set:Nn \l_keys_current_key_name_tl {#1} - }{ - \tl_put_right:Nn \l_keys_current_path_tl { / #1 } - \keys_separate_path:w /#2 \q_stop - } +\cs_new_nopar:Nn \keys_show:nn { + \cs_show:c { \c_keys_root_tl #1 / \tl_to_str:n {#2} .cmd:w } } -\cs_new_nopar:Nn \keys_set:NN { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:n = { - #1 #2 {##1} +\cs_new:Npn \keys_tmp:w {} +\cs_new:Nn \keys_value_or_default:n { + \toks_set:Nn \l_keys_value_toks {#1} + \bool_if:NT \l_keys_no_value_bool { + \cs_if_exist:cT { \c_keys_root_tl \l_keys_path_tl .default_tl } { + \toks_set:Nv \l_keys_value_toks { + \c_keys_root_tl \l_keys_path_tl .default_tl + } } } } -\cs_new_nopar:Nn \keys_set:Nnn { - \keys_parse_list:n { - \c_keys_properties_path_tl /.code:x = { - \exp_not:N #1 { #2 \l_keys_current_module_tl #3 } {##1} +\cs_new_nopar:Nn \keys_value_requirement:n { + \tl_set_eq:cc { \c_keys_root_tl \l_keys_path_tl .req_tl } + { c_keys_value_ #1 _tl } +} +\cs_new_nopar:Nn \keys_variable_get_scope:N { + \tl_if_eq:xxT { \token_to_str:N g } + { \keys_variable_get_scope_aux:N #1 } + { g } +} +\cs_new_nopar:Nn \keys_variable_get_scope_aux:N { + \exp_last_unbraced:NNo \use_i:nn \use_i_delimit_by_q_stop:nw + \token_to_str:N #1 \q_stop +} +\group_begin: + \char_set_lccode:nn {`\&} {`\_} + \char_make_other:N \& +\tl_to_lowercase:n { + \group_end: + \cs_new_nopar:Nn \keys_variable_get_type:N { + \exp_after:wN \keys_variable_get_type_aux:w + \token_to_str:N #1 & \q_nil \q_stop + } + \cs_new_nopar:Npn \keys_variable_get_type_aux:w #1 & #2 \q_stop { + \quark_if_nil:nTF {#2} { + #1 + }{ + \keys_variable_get_type_aux:w #2 \q_stop } } } -\cs_new:Nn \keys_set_cmd:nn { - \keys_clear_properties:n {#1} - \cs_set:cpn { \c_keys_cs_prefix_tl #1 /._cmd:w } ##1 {#2} -} -\cs_new:Nn \keys_set_cmd:nx { - \keys_clear_properties:n {#1} - \cs_set:cpx { \c_keys_cs_prefix_tl #1 /._cmd:w } ##1 {#2} -} -\cs_new:Nn \keys_set_cmd:nNn { - \keys_clear_properties:n {#1} - \cs_generate_from_arg_count:cNnn { \c_keys_cs_prefix_tl #1 /._cmd:w } - \cs_set:Npn #2 {#3} - \keys_store:nn { #1 /._num_args_tl} {#2} -} -\cs_new:Nn \keys_set_cmd:nNx { - \keys_clear_properties:n {#1} - \cs_generate_from_arg_count:cNnn { \c_keys_cs_prefix_tl #1 /._cmd:w } - \cs_set:Npx #2 {#3} - \keys_store:nn { #1 /._num_args_tl} {#2} -} -\cs_new:Nn \keys_store:nn { - \tl_set:cn { \c_keys_cs_prefix_tl #1 } {#2} -} -\cs_new:Nn \keys_store:nx { - \tl_set:cx { \c_keys_cs_prefix_tl #1 } {#2} -} -\cs_new_nopar:Nn \keys_toks_set:Nn { - \exp_args:NNv \toks_set:Nn #1 { \c_keys_cs_prefix_tl #2 } -} -\cs_new_nopar:Nn \keys_try: { - \bool_set_false:N \l_keys_success_bool - \keys_if_cmd_exist:nT { \l_keys_current_path_tl } { - \bool_set_true:N \l_keys_success_bool - \bool_if:NT \l_keys_no_value_bool { - \keys_if_exist:nT - { \l_keys_current_path_tl /._default_tl } { - \keys_toks_set:Nn \l_keys_current_value_toks - { \l_keys_current_path_tl /._default_tl } - } - } - \cs_set_eq:NN \l_keys_current_key_full_tl \l_keys_current_path_tl - \keys_use_cmd:n { \l_keys_current_path_tl } +\cs_new_nopar:Nn \keys_variable_set:NN { + \cs_if_exist:NF #2 { + \use:c { \keys_variable_get_type:N #2 _new:N } #2 + } + \keys_cmd_set:nNx { \l_keys_path_tl } 1 { + \exp_not:c { + \keys_variable_get_type:N #2 _ + \keys_variable_get_scope:N #2 set:N #1 + } \exp_not:N #2 {##1} } } -\cs_new_nopar:Nn \keys_undefine:n { - \cs_set_eq:cN { \c_keys_cs_prefix_tl #1 } \c_undefined +\keys_property_new:nn { .choice: } { + \keys_choice_make: } -\cs_new_nopar:Nn \keys_use:n { - \use:c { \c_keys_cs_prefix_tl #1 } +\keys_property_new:nn { .code:n } { + \keys_cmd_set:nNn { \l_keys_path_tl } 1 {#1} } -\cs_new_nopar:Nn \keys_use_cmd:n { - \exp_args:Nno \keys_use_cmd:nn {#1} - { \toks_use:N \l_keys_current_value_toks } +\keys_property_new:nn { .code:Nn } { + \keys_cmd_set:nNn { \l_keys_path_tl } #1 {#2} } -\cs_new_nopar:Nn \keys_use_cmd:nn { - \keys_if_exist:nTF { #1 /._num_args_tl } { - \keys_use_cmd_aux:nn {#1} {#2} - }{ - \keys_use:n {#1/._cmd:w} {#2} - } +\keys_property_new:nn { .code:x } { + \keys_cmd_set:nNx { \l_keys_path_tl } 1 {#1} } -\cs_new_nopar:Nn \keys_use_cmd_aux:nn { - \tl_if_empty:nTF {#2} { - \cs_set:Npn \keys_use_cmd_aux:w { - \keys_use:n { #1 /._cmd:w } - } - \exp_after:wN \exp_after:wN \exp_after:wN \keys_use_cmd_aux:w - \cs:w - c_keys_ \keys_use:n { #1 /._num_args_tl } _empty_tl - \cs_end: - }{ - \keys_use:n { #1 /._cmd:w } #2 - } +\keys_property_new:nn { .code:Nx } { + \keys_cmd_set:nNx { \l_keys_path_tl } #1 {#2} } -\cs_new_nopar:Npn \keys_msg_new:nn #1 { - \msg_new:nnn { keys } {#1} -} -\cs_new_protected_nopar:Nn \keys_error:nn { - \msg_error:nnxx { keys } {#1} { \l_keys_current_key_full_tl } {#2} -} -\cs_new_protected_nopar:Nn \keys_error:n { - \msg_error:nnx { keys } {#1} { \l_keys_current_key_full_tl } -} -\keys_msg_new:nn - { unknown~key } - {The key `#1' is unknown and is being ignored.} -\keys_msg_new:nn - { value~required } - {The key `#1' requires a value\\% - and is being ignored.} -\keys_msg_new:nn - { value~forbidden } - {The key `#1' cannot taken a value:\\% - the given input `#2' is being ignored.} -\keys_msg_new:nn - { Boolean~expected } - {Key `#1' takes the Boolean values\\% - `true' and `false'~only.\\% - The given value `#2' is being ignored.} -\keys_msg_new:nn - { not_boolean } - {Key `#1' is not a Boolean key: you cannot create a complement.} -\keys_msg_new:nn - { unknown~choice } - {Choice `#2' unknown for key `#1':\\% - the key is being ignored.} -\keys_set_cmd:nn { \c_keys_properties_path_tl /.code:n } { - \keys_set_cmd:nn { \l_keys_current_path_tl } {#1} -} -\keys_set_cmd:nNn { \c_keys_properties_path_tl /.code:Nn } 2 { - \keys_set_cmd:nNn { \l_keys_current_path_tl } #1 {#2} -} -\keys_manage_quick:n { - \c_keys_errors_path_tl /unknown/.code:n = { - \keys_error:n { unknown~key } - } +\keys_property_new:nn { .default:n } { + \keys_default_set:n {#1} } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.code:x/.code:n = { - \keys_set_cmd:nx { \l_keys_current_path_tl } {#1} - }, - \c_keys_properties_path_tl /.code:Nx/.code:Nn = 2 { - \keys_set_cmd:nNx { \l_keys_current_path_tl } {#1} {#2} - } +\keys_property_new:nn { .default:V } { + \keys_default_set:V #1 } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.cd:/.code:n = { - \tl_set:Nx \l_keys_default_path_tl { \l_keys_current_path_tl / } - } +\keys_property_new:nn { .generate_choices:nn } { + \keys_choices_generate:nx {#1} { \exp_not:n {#2} } } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.value_required:/.code:n = { - \keys_bool_new:n { \l_keys_current_path_tl /._required_bool } - \keys_undefine:n { \l_keys_current_path_tl /._forbidden_bool } - }, - \c_keys_properties_path_tl /.value_forbidden:/.code:n = { - \keys_bool_new:n { \l_keys_current_path_tl /._forbidden_bool } - \keys_undefine:n { \l_keys_current_path_tl /._required_bool } - } +\keys_property_new:nn { .generate_choices:nx } { + \keys_choices_generate:nx {#1} {#2} } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.default:n/.code:n = { - \keys_store:nn { \l_keys_current_path_tl /._default_tl } {#1} - \keys_undefine:n { \l_keys_current_path_tl /._required_bool } - } +\keys_property_new:nn { .set:N } { + \keys_variable_set:NN n #1 } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.tl_set:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_set:Nn #1 - }, - \c_keys_properties_path_tl /.tl_set_x:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_set:Nx #1 - }, - \c_keys_properties_path_tl /.tl_gset:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_gset:Nn #1 - }, - \c_keys_properties_path_tl /.tl_gset_x:N/.code:n = { - \keys_check_exists:NN #1 \tl_new:N - \keys_set:NN \tl_gset:Nx #1 - } +\keys_property_new:nn { .set_x:N } { + \keys_variable_set:NN x #1 } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.int_set:N/.code:n = { - \keys_check_exists:NN #1 \int_new:N - \keys_set:NN \int_set:Nn #1 - }, - \c_keys_properties_path_tl /.int_gset:N/.code:n = { - \keys_check_exists:NN #1 \int_new:N - \keys_set:NN \int_gset:Nn #1 - }, - \c_keys_properties_path_tl /.skip_set:N/.code:n = { - \keys_check_exists:NN #1 \skip_new:N - \keys_set:NN \skip_set:Nn #1 - }, - \c_keys_properties_path_tl /.skip_gset:N/.code:n = { - \keys_check_exists:NN #1 \skip_new:N - \keys_set:NN \skip_gset:Nn #1 - }, - \c_keys_properties_path_tl /.toks_set:N/.code:n = { - \keys_check_exists:NN #1 \toks_new:N - \keys_set:NN \toks_set:Nn #1 - }, - \c_keys_properties_path_tl /.toks_gset:N/.code:n = { - \keys_check_exists:NN #1 \toks_new:N - \keys_set:NN \toks_gset:Nn #1 - } +\keys_property_new:nn { .set_bool:N } { + \keys_bool_set:N #1 } -\keys_manage_quick:n { - \c_keys_utilities_path_tl /current_module:n/.code:n = { - \tl_if_empty:nTF {#1} { - \tl_clear:N \l_keys_current_module_tl - }{ - \tl_set:Nn \l_keys_current_module_tl { #1 _ } - } - } +\keys_property_new:nn { .set_bool_inverse:N } { + \keys_bool_set_inverse:N #1 } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.tl_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_set:cn { l_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_set_x:n/.code:n = { - \keys_check_exists:cN { l_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_set:cx { l_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_gset:cn { g_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.tl_gset_x:n/.code:n = { - \keys_check_exists:cN { g_ #1 _tl } \tl_new:N - \keys_set:Nnn \tl_gset:cx { g_ } { #1 _tl } - }, - \c_keys_properties_path_tl /.int_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _int } \int_new:N - \keys_set:Nnn \int_set:cn { l_ } { #1 _int } - }, - \c_keys_properties_path_tl /.int_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _int } \int_new:N - \keys_set:Nnn \int_gset:cn { g_ } { #1 _int } - }, - \c_keys_properties_path_tl /.skip_set:n/.code:n = { - \keys_check_exists:cN { l_ #1 _skip } \skip_new:N - \keys_set:Nnn \skip_set:cn { l_ } { #1 _skip } - }, - \c_keys_properties_path_tl /.skip_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _skip } \skip_new:N - \keys_set:Nnn \skip_gset:cn { g_ } { #1 _skip } - }, - \c_keys_properties_path_tl /.toks_set:n/.code:n = { - \keys_check_exists:cN { g_ #1 _toks } \toks_new:N - \keys_set:Nnn \toks_set:cn { l_ } { #1 _toks } - }, - \c_keys_properties_path_tl /.toks_gset:n/.code:n = { - \keys_check_exists:cN { g_ #1 _toks } \toks_new:N - \keys_set:Nnn \toks_gset:cn { g_ } { #1 _toks } - }, -} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.bool_set:N/.code:n = { - \keys_bool_set:nN { set } #1 - }, - \c_keys_properties_path_tl /.bool_gset:N/.code:n = { - \keys_bool_set:nN { gset } #1 - }, - \c_keys_properties_path_tl /.bool_set:n/.code:n = { - \keys_bool_set:nnn { set } { l_ } { #1 } - }, - \c_keys_properties_path_tl /.bool_gset:n/.code:n = { - \keys_bool_set:nnn { gset } { g_ } { #1 } - }, -} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.bool_set_inverse:N/.code:n = { - \keys_bool_set_inverse:nN { set } #1 - }, - \c_keys_properties_path_tl /.bool_gset_inverse:N/.code:n = { - \keys_bool_set_inverse:nN { gset } #1 - }, - \c_keys_properties_path_tl /.bool_set_inverse:n/.code:n = { - \keys_bool_set_inverse:nnn { set } { l_ } { #1 } - }, - \c_keys_properties_path_tl /.bool_gset_inverse:n/.code:n = { - \keys_bool_set_inverse:nnn { gset } { g_ } { #1 } - }, -} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.expects_choice:/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.cd:, - .code:n = { - \tl_set:Nn \l_keys_current_choice_tl {##1} - \int_zero:N \l_keys_current_choice_int - \exp_args:No \keys_parse_list:n - { \l_keys_current_key_full_tl / ##1 } - }, - unknown/.code:n = { - \keys_error:nn { unknown~choice } - { \l_keys_current_key_name_tl } - } - } - }, -} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.create_choices:nn/.code:Nn = 2 { - \keys_choices_create:Nnn n {#1} {#2} - }, - \c_keys_properties_path_tl /.create_choices:nx/.code:Nn = 2 { - \keys_choices_create:Nnn x {#1} {#2} - }, -} -\keys_manage_quick:n { - \c_keys_properties_path_tl /.use_keys:n/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:n = { \keys_parse_list:n {#1} } - } - }, - \c_keys_properties_path_tl /.use_keys:x/.code:n = { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:x = { - \exp_not:N \keys_parse_list:n {#1} - } - } - }, - \c_keys_properties_path_tl /.use_keys:Nn/.code:Nn = 2 { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:Nn = #1 { \keys_parse_list:n {#2} } - } - }, - \c_keys_properties_path_tl /.use_keys:Nx/.code:Nn = 2 { - \keys_manage_internal:n { - \l_keys_current_path_tl /.code:Nx = - #1 { \exp_not:N \keys_parse_list:n {#2} } - } - } +\keys_property_new:nn { .value_forbidden: } { + \keys_value_requirement:n { forbidden } } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.try:n/.code:n = { \keys_try: }, - \c_keys_properties_path_tl /.retry:n/.code:n = { - \bool_if:NF \l_keys_success_bool { \keys_try: } - } +\keys_property_new:nn { .value_required: } { + \keys_value_requirement:n { required } } -\keys_manage_quick:n { - \c_keys_properties_path_tl /.show_code:/.code:n = { - \cs_show:c { - \c_keys_cs_prefix_tl \l_keys_current_path_tl /._cmd:w - } - }, - \c_keys_properties_path_tl /.show_key:/.code:n = { - \cs_show:c { \c_keys_cs_prefix_tl \l_keys_current_path_tl } - } +\msg_new:nnn { keys } { choice~unknown } {% + Choice `#2' unknown for key `#1':\\% + the key is being ignored.% +} +\msg_new:nnn { keys } { key~unknown } {% + The key `#1' is unknown and is being ignored.% +} +\msg_new:nnn { keys } { key~value~forbidden }{% + The key `#1' cannot taken a value:\\% + the given input `#2' is being ignored.% +} +\msg_new:nnn { keys } { key~value~required } {% + The key `#1' requires a value\\% + and is being ignored.% +} +\msg_new:nnn { keys } { no~property } {% + No property given in definition of key `#1'.% +} +\msg_new:nnn { keys } { property~unknown } {% + The key property `#1' is unknown.% +} +\msg_new:nnn { keys } { property~value~required } {% + The property `#1' requires a value\\% + and is being ignored.% } %% %% Copyright (C) 2008-2009 by |