I'm trying to create an option with l3keys
such that, if it receives a value, even if an empty one, it gets added to a property list, but if it receives no value, it gets removed from the property list.
However, I don't seem to be able do distinguish key
from key=
in a .code:n
"action". I know that .default:n
captures that situation, but it cannot receive a code block, just a value. I also know that I can distinguish the situation in \keyval_parse:nnn
, but I'd like this behavior in some options among the whole set, and using \keyval_parse:nnn
for the whole thing would become complicated.
The MWE illustrates the situation:
\documentclass{article}
\ExplSyntaxOn
\prop_new:N \l__myprops_prop
\keys_define:nn { options }
{
mykey .code:n =
{
\tl_if_novalue:nTF {#1}
{ \prop_remove:Nn \l__myprops_prop { mykey } }
{ \prop_put:Nnn \l__myprops_prop { mykey } {#1} }
\prop_show:N \l__myprops_prop
} ,
mykey2 .code:n =
{
\tl_if_empty:nTF {#1}
{ \prop_remove:Nn \l__myprops_prop { mykey2 } }
{ \prop_put:Nnn \l__myprops_prop { mykey2 } {#1} }
\prop_show:N \l__myprops_prop
}
}
\ExplSyntaxOff
\begin{document}
\ExplSyntaxOn
\keys_set:nn { options } { mykey }
\keys_set:nn { options } { mykey= }
\keys_set:nn { options } { mykey=val }
\prop_clear:N \l__myprops_prop
\keys_set:nn { options } { mykey2 }
\keys_set:nn { options } { mykey2= }
\keys_set:nn { options } { mykey2=val }
\ExplSyntaxOff
\end{document}
The log for this document contains:
The property list \l__myprops_prop contains the pairs (without outer braces):
> {mykey} => {}.
<recently read> }
l.27 \keys_set:nn { options } { mykey }
The property list \l__myprops_prop contains the pairs (without outer braces):
> {mykey} => {}.
<recently read> }
l.28 \keys_set:nn { options } { mykey= }
The property list \l__myprops_prop contains the pairs (without outer braces):
> {mykey} => {val}.
<recently read> }
l.29 \keys_set:nn { options } { mykey=val }
The property list \l__myprops_prop is empty
> .
<recently read> }
l.31 \keys_set:nn { options } { mykey2 }
The property list \l__myprops_prop is empty
> .
<recently read> }
l.32 \keys_set:nn { options } { mykey2= }
The property list \l__myprops_prop contains the pairs (without outer braces):
> {mykey2} => {val}.
<recently read> }
l.33 \keys_set:nn { options } { mykey2=val }
Which shows that neither key
nor key=
pass the "no value" test, and both key
and key=
pass the emptiness test. Unfortunately, I cannot use emptiness to "signal" the removal, since "empty" is a valid value for the key in question. Is indeed \keyval_parse:nnn
the only choice here?
\keys_set:nn
(using documented interfaces). There is a private boolean variable that holds the value/no-value state, but it's not used when the.code:n
handler is used. It would be nice to distinguish these cases, but I don't think a change is feasible at this point...l3keys
works on the idea that keys are properties, and thus there is no such thing as 'not having a value' for any key - once you create a key, it always has some value even if that value is 'empty'.key
andkey=
in a.code:n
handler. So I might have expressed myself poorly, but since\keyval_parse:nnn
recognizes this difference, I was hoping to grab that piece of information in\keys_set:nn
too. And indeed, Skillmon provided a way which seems to be the proper one to do it.key
andkey=
, I should not use that distinction at the user level?