summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3keys.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3keys.dtx272
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>