diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3keys.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3keys.dtx | 272 |
1 files changed, 168 insertions, 104 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx index 8797006f6b4..e5770e48c2b 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx @@ -37,7 +37,7 @@ \documentclass[full]{l3doc} %</driver> %<*driver|package> -\GetIdInfo$Id: l3keys.dtx 5629 2015-06-14 08:38:04Z joseph $ +\GetIdInfo$Id: l3keys.dtx 5665 2015-07-15 06:13:22Z joseph $ {L3 Key-value interfaces} %</driver|package> %<*driver> @@ -171,6 +171,28 @@ % discussion, each property is illustrated attached to an % arbitrary \meta{key}, which when used may be supplied with a % \meta{value}. All key \emph{definitions} are local. +% +% Key properties are applied in the reading order and so the ordering +% is significant. Key properties which define \enquote{actions}, such +% as |.code:n|, |.tl_set:N|, \emph{etc.}, will override one another. +% Some other properties are mutually exclusive, notably |.value_required:n| +% and |.value_forbidden:n|, and so will replace one another. However, +% properties covering non-exclusive behaviours may be given in any order. Thus +% for example the following defintions are equivalent. +% \begin{verbatim} +% \keys_define:nn { mymodule } +% { +% keyname .code:n = Some~code~using~#1, +% keyname .value_required:n = true +% } +% \keys_define:nn { mymodule } +% { +% keyname .value_required:n = true, +% keyname .code:n = Some~code~using~#1 +% } +% \end{verbatim} +% Note that with the exception of the special |.undefine:| property, all +% key properties will define the key within the current \TeX{} scope. % % \begin{function}[updated = 2013-07-08] % {.bool_set:N, .bool_set:c, .bool_gset:N, .bool_gset:c} @@ -220,7 +242,7 @@ % Choices are discussed in detail in section~\ref{sec:l3keys:choice}. % \end{function} % -% \begin{function}[added=2011-09-11] +% \begin{function}[added = 2011-09-11] % {.clist_set:N, .clist_set:c, .clist_gset:N, .clist_gset:c} % \begin{syntax} % \meta{key} .clist_set:N = \meta{comma list variable} @@ -263,6 +285,10 @@ % key = , % Prints 'Hello ' % } % \end{verbatim} +% The default does not affect keys where values are required or +% forbidden. Thus a required value cannot be supplied by a default +% value, and giving a default value for a key which cannot take a value +% will not trigger an error. % \end{function} % % \begin{function}{.dim_set:N, .dim_set:c, .dim_gset:N, .dim_gset:c} @@ -385,20 +411,29 @@ % it will be created globally at the point that the key is set up. % \end{function} % -% \begin{function}{.value_forbidden:} +% \begin{function}[added = 2015-07-14]{.undefine:} % \begin{syntax} -% \meta{key} .value_forbidden: +% \meta{key} .undefine: +% \end{syntax} +% Removes the definition of the \meta{key} within the current scope. +% \end{function} +% +% \begin{function}[added = 2015-07-14]{.value_forbidden:n} +% \begin{syntax} +% \meta{key} .value_forbidden:n = \texttt{true\string|false} % \end{syntax} % Specifies that \meta{key} cannot receive a \meta{value} when used. -% If a \meta{value} is given then an error will be issued. +% If a \meta{value} is given then an error will be issued. Setting +% the property \texttt{false} will cancel the restriction. % \end{function} % -% \begin{function}{.value_required:} +% \begin{function}[added = 2015-07-14]{.value_required:n} % \begin{syntax} -% \meta{key} .value_required: +% \meta{key} .value_required:n = \texttt{true\string|false} % \end{syntax} % Specifies that \meta{key} must receive a \meta{value} when used. -% If a \meta{value} is not given then an error will be issued. +% If a \meta{value} is not given then an error will be issued. Setting +% the property \texttt{false} will cancel the restriction. % \end{function} % % \section{Sub-dividing keys} @@ -575,7 +610,8 @@ % later. % \end{function} % -% \begin{variable}{\l_keys_key_tl, \l_keys_path_tl, \l_keys_value_tl} +% \begin{variable}[updated = 2015-07-14] +% {\l_keys_key_tl, \l_keys_path_tl, \l_keys_value_tl} % For each key processed, information of the full \emph{path} of the % key, the \emph{name} of the key and the \emph{value} of the key is % available within three token list variables. These may be used within @@ -590,19 +626,19 @@ % thus for example % \begin{verbatim} % \keys_set:nn { mymodule } { key-a = some-value } -% \end{verbatim} -% has path \texttt{mymodule/key-a} while +% \end{verbatim} +% has path \texttt{mymodule/key-a} while % \begin{verbatim} % \keys_set:nn { mymodule } { subset / key-a = some-value } -% \end{verbatim} -% has path \texttt{mymodule/subset/key-a}. This information is stored in -% \cs{l_keys_path_tl}, and will have been processed by \cs{tl_to_str:n}. -% -% The \emph{name} of the key is the part of the path after the last -% \texttt{/}, and thus is not unique. In the preceding examples, both keys -% have name \texttt{key-a} despite having different paths. This information -% is stored in \cs{l_keys_key_tl}, and will have been processed by -% \cs{tl_to_str:n}. +% \end{verbatim} +% has path \texttt{mymodule/subset/key-a}. This information is stored in +% \cs{l_keys_path_tl}, and will have been processed by \cs{tl_to_str:n}. +% +% The \emph{name} of the key is the part of the path after the last +% \texttt{/}, and thus is not unique. In the preceding examples, both keys +% have name \texttt{key-a} despite having different paths. This information +% is stored in \cs{l_keys_key_tl}, and will have been processed by +% \cs{tl_to_str:n}. % \end{variable} % % \section{Handling of unknown keys} @@ -1270,6 +1306,31 @@ % % \subsection{Turning properties into actions} % +% \begin{macro}[int]{\@@_ensure_exist:n, \@@_ensure_exist:V} +% Used to make sure that a key implementation and the related property +% list will exist whenever this is required. We cannot use for example +% \cs{prop_clear_new:c} here as that would affect the order in which key +% properties must be set. As key definitions are never global we use +% |\cs_set_protected:cpn| not |\cs_new_protected:cpn| here. For the +% same reason, to avoid issues if the key has been undefined in the +% current scope but exists at a higher level, we do not use \cs{prop_new:c} +% but rather \cs{prop_set_eq:cN}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_ensure_exist:n #1 + { + \prop_if_exist:cF { \c_@@_info_root_tl #1 } + { + \prop_set_eq:cN { \c_@@_info_root_tl #1 } \c_empty_prop + } + \cs_if_exist:cF { \c_@@_code_root_tl #1 } + { + \cs_set_protected:cpn { \c_@@_code_root_tl #1 } ##1 { } + } + } +\cs_generate_variant:Nn \@@_ensure_exist:n { V } +% \end{macrocode} +% \end{macro} +% % \begin{macro}[int]{\@@_bool_set:Nn, \@@_bool_set:cn} % Boolean keys are really just choices, but all done by hand. The % second argument here is the scope: either empty or \texttt{ g } for @@ -1406,13 +1467,13 @@ % % \begin{macro}[int] % {\@@_cmd_set:nn, \@@_cmd_set:nx, \@@_cmd_set:Vn, \@@_cmd_set:Vo} -% Creating a new command means tidying up the properties and then making -% the internal function which actually does the work. +% Setting the code for a key first checks that the basic data structures +% exist, then saves the code. % \begin{macrocode} \cs_new_protected:Npn \@@_cmd_set:nn #1#2 { - \prop_clear_new:c { \c_@@_info_root_tl #1 } - \cs_set:cpn { \c_@@_code_root_tl #1 } ##1 {#2} + \@@_ensure_exist:V \l_keys_path_tl + \cs_set_protected:cpn { \c_@@_code_root_tl #1 } ##1 {#2} } \cs_generate_variant:Nn \@@_cmd_set:nn { nx , Vn , Vo } % \end{macrocode} @@ -1423,7 +1484,12 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_default_set:n #1 { - \prop_if_exist:cT { \c_@@_info_root_tl \l_keys_path_tl } + \@@_ensure_exist:V \l_keys_path_tl + \tl_if_blank:nTF {#1} + { + \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } + { default } + } { \prop_put:cnn { \c_@@_info_root_tl \l_keys_path_tl } { default } {#1} @@ -1439,9 +1505,14 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_groups_set:n #1 { - \prop_if_exist:cT { \c_@@_info_root_tl \l_keys_path_tl } + \@@_ensure_exist:V \l_keys_path_tl + \clist_set:Nn \l_@@_groups_clist {#1} + \clist_if_empty:NTF \l_@@_groups_clist + { + \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } + { groups } + } { - \clist_set:Nn \l_@@_groups_clist {#1} \prop_put:cnV { \c_@@_info_root_tl \l_keys_path_tl } { groups } \l_@@_groups_clist } @@ -1456,7 +1527,10 @@ % \cs{l_keys_path_tl} will contain \texttt{/} so a split is easy to do. % \begin{macrocode} \cs_new_protected:Npn \@@_initialise:n #1 - { \exp_after:wN \@@_initialise:wn \l_keys_path_tl \q_stop {#1} } + { + \@@_ensure_exist:V \l_keys_path_tl + \exp_after:wN \@@_initialise:wn \l_keys_path_tl \q_stop {#1} + } \cs_new_protected:Npn \@@_initialise:wn #1 / #2 \q_stop #3 { \keys_set:nn {#1} { #2 = {#3} } } % \end{macrocode} @@ -1481,21 +1555,41 @@ % \end{macro} % \end{macro} % -% \begin{macro}[int]{\@@_value_requirement:n} +% \begin{macro}[int]{\@@_undefine:} +% Undefining a key has to be done without \cs{cs_undefine:c} as that +% function acts globally. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_undefine: + { + \cs_set_eq:cN { \c_@@_code_root_tl \l_keys_path_tl } \tex_undefined:D + \cs_set_eq:cN { \c_@@_info_root_tl \l_keys_path_tl } \tex_undefined:D + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_value_requirement:nn} % Values can be required or forbidden by having the appropriate marker % set. First, both the required and forbidden ones are clear, just in case! % \begin{macrocode} -\cs_new_protected:Npn \@@_value_requirement:n #1 +\cs_new_protected:Npn \@@_value_requirement:nn #1#2 { - \prop_if_exist:cT { \c_@@_info_root_tl \l_keys_path_tl } + \@@_ensure_exist:V \l_keys_path_tl + \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } + { required } + \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } + { forbidden } + \str_if_eq:nnTF {#2} { true } { - \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } - { required } - \prop_remove:cn { \c_@@_info_root_tl \l_keys_path_tl } - { forbidden } \prop_put:cnn { \c_@@_info_root_tl \l_keys_path_tl } {#1} { true } - } + } + { + \str_if_eq:nnF {#2} { false } + { + \__msg_kernel_error:nnx { kernel } { property-boolean-values-only } + { .value_ #1 :n } + } + } } % \end{macrocode} % \end{macro} @@ -1780,14 +1874,22 @@ % \end{macro} % \end{macro} % -% \begin{macro}{.value_forbidden:} -% \begin{macro}{.value_required:} +% \begin{macro}{.undefine:} +% TAnother simple wrapper. +% \begin{macrocode} +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .undefine: } + { \@@_undefine: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{.value_forbidden:n} +% \begin{macro}{.value_required:n} % These are very similar, so both call the same function. % \begin{macrocode} -\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_forbidden: } - { \@@_value_requirement:n { forbidden } } -\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_required: } - { \@@_value_requirement:n { required } } +\cs_new_protected:cpn { \c_@@_props_root_tl .value_forbidden:n } #1 + { \@@_value_requirement:nn { forbidden } {#1} } +\cs_new_protected:cpn { \c_@@_props_root_tl .value_required:n } #1 + { \@@_value_requirement:nn { required } {#1} } % \end{macrocode} % \end{macro} % \end{macro} @@ -1909,6 +2011,7 @@ % % \begin{macro}[int]{\@@_set_elt:n, \@@_set_elt:nn} % \begin{macro}[aux]{\@@_set_elt_aux:nn} +% \begin{macro}[aux, EXP]{\@@_key_find:w} % \begin{macro}[aux]{\@@_set_elt_aux:, \@@_set_elt_selective:} % A shared system once again. First, set the current path and add a % default if needed. There are then checks to see if the a value is @@ -1927,13 +2030,20 @@ } \cs_new_protected:Npn \@@_set_elt_aux:nn #1#2 { - \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} } - \tl_set:Nx \l_keys_path_tl { \l_@@_module_tl / \l_keys_key_tl } + \tl_set:Nx \l_keys_path_tl { \l_@@_module_tl / \tl_to_str:n {#1} } + \tl_set:Nx \l_keys_key_tl + { \exp_after:wN \@@_key_find:w \l_keys_path_tl / \q_stop } \@@_value_or_default:n {#2} \bool_if:NTF \l_@@_selective_bool { \@@_set_elt_selective: } { \@@_set_elt_aux: } } +\cs_new:Npn \@@_key_find:w #1 / #2 \q_stop + { + \tl_if_blank:nTF {#2} + { #1 } + { \@@_key_find:w #2 \q_stop } + } \cs_new_protected_nopar:Npn \@@_set_elt_aux: { \bool_if:nTF @@ -2019,6 +2129,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}[int]{\@@_value_or_default:n} % If a value is given, return it as |#1|, otherwise send a default if @@ -2195,6 +2306,12 @@ The~key~'#1'~cannot~be~defined~as~a~choice~as~the~parent~key~'#2'~is~ itself~a~choice. } +\__msg_kernel_new:nnnn { kernel } { property-boolean-values-only } + { The~property~'#1'~accepts~boolean~values~only. } + { + \c__msg_coding_error_text_tl + The~property~'#1'~only~accepts~the~values~'true'~and~'false'. + } \__msg_kernel_new:nnnn { kernel } { property-requires-value } { The~property~'#1'~requires~a~value. } { @@ -2225,70 +2342,17 @@ % % \subsection{Deprecated functions} % -% \begin{macro}[int]{\@@_choice_code_store:n, \@@_choice_code_store:x} -% \begin{macro}{.choice_code:n, .choice_code:x} -% \begin{macro}[int]{\@@_choices_generate:n} -% \begin{macro}[aux]{\@@_choices_generate_aux:n} -% \begin{macro}{.generate_choices:n} -% Deprecated on 2013-07-09. +% \begin{macro}{.value_forbidden:} +% \begin{macro}{.value_required:} +% Deprecated 2015-07-14. % \begin{macrocode} -\cs_new_protected:Npn \@@_choice_code_store:n #1 - { - \cs_if_exist:cF - { \c_@@_info_root_tl \l_keys_path_tl .choice~code } - { - \tl_new:c - { \c_@@_info_root_tl \l_keys_path_tl .choice~code } - } - \tl_set:cn { \c_@@_info_root_tl \l_keys_path_tl .choice~code } - {#1} - } -\cs_generate_variant:Nn \@@_choice_code_store:n { x } -\cs_new_protected:cpn { \c_@@_props_root_tl .choice_code:n } #1 - { \@@_choice_code_store:n {#1} } -\cs_new_protected:cpn { \c_@@_props_root_tl .choice_code:x } #1 - { \@@_choice_code_store:x {#1} } -\cs_new_protected:Npn \@@_choices_generate:n #1 - { - \cs_if_exist:cTF - { \c_@@_info_root_tl \l_keys_path_tl .choice~code } - { - \@@_choice_make: - \int_zero:N \l_keys_choice_int - \clist_map_function:nN {#1} \@@_choices_generate_aux:n - } - { - \__msg_kernel_error:nnx { kernel } - { generate-choices-before-code } { \l_keys_path_tl } - } - } -\cs_new_protected:Npn \@@_choices_generate_aux:n #1 - { - \int_incr:N \l_keys_choice_int - \@@_cmd_set:nx { \l_keys_path_tl / #1 } - { - \tl_set:Nn \exp_not:N \l_keys_choice_tl {#1} - \int_set:Nn \exp_not:N \l_keys_choice_int - { \int_use:N \l_keys_choice_int } - \exp_not:v - { \c_@@_info_root_tl \l_keys_path_tl .choice~code } - } - } -\__msg_kernel_new:nnnn { kernel } { generate-choices-before-code } - { No~code~available~to~generate~choices~for~key~'#1'. } - { - \c__msg_coding_error_text_tl - Before~using~.generate_choices:n~the~code~should~be~defined~ - with~'.choice_code:n'~or~'.choice_code:x'. - } -\cs_new_protected:cpn { \c_@@_props_root_tl .generate_choices:n } #1 - { \@@_choices_generate:n {#1} } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_forbidden: } + { \@@_value_requirement:nn { forbidden } { true } } +\cs_new_protected_nopar:cpn { \c_@@_props_root_tl .value_required: } + { \@@_value_requirement:nn { required } { true } } % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % \begin{macrocode} %</initex|package> |