3

When declaring a new command with multiple optional arguments next to each other, e.g.

\NewDocumentCommand{\mycmd}{ o o o }{}

one is implicitly excluding the option of passing a value for #2 without having one for #1, i.e. \mycmd[][2] will fail \IfNoValueT{#1}. This can be remediated by using \tl_if_blank:nTF, see \IfNoValueTF - How to force "no value" if there (are brackets but there) is no value for an argument. However, sometimes this is not an option (in my particular case, the xparse support of tcolorbox is limited to checking -NoValue-).

This, among other things, made me want to reprogram some commands (or, in my case, tcolorboxes) into a key-value system. My approach was to give the original command \mycmd extra mandatory arguments that would remain empty, as to ensure that any combination of empty or nonempty optional arguments is possible. E.g. \mycmd from above would be set with

\NewDocumentCommand{\mycmd}{ o m o m o }{}

With this version, I can pass a value to any of my three "real" arguments (the optional ones) without needing any of the others, while also being able to call \IfValueTF on any of them.

Next, I define keys for each of the optional arguments, e.g.

\keys_define:nn { mykeys } {
    a .tl_set:N = \l_mykeys_a_tl,
    b .tl_set:N = \l_mykeys_b_tl,
    c .tl_set:N = \l_mykeys_c_tl
}

Lastly, I define a wrapper command

\NewDocumentCommand{\wrapper}{ O{} }{
    \keys_set:nn{mykeys}{#1}
    \mycmd
    \tl_if_empty:NTF \l_mykeys_a_tl {} { [\l_mykeys_a_tl] }
    {}
    \tl_if_empty:NTF \l_mykeys_b_tl {} { [\l_mykeys_b_tl] }
    {}
    \tl_if_empty:NTF \l_mykeys_c_tl {} { [\l_mykeys_c_tl] }
}

with the intention that e.g. \wrapper[a=13, c=2] would be equivalent to \mycmd[13]{}{}[2].

This last point is where my approach fails completely. I tried to play around with \exp_not:n or \use:n, explained in The LaTeX3 Interfaces, but to no avail. Hence, any help or guidance would be much appreciated. Thank you!


Full MWE:

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand{\mycmd}{ o m o m o }{ First real'' argument is \IfValueTF{#1}{#1}{not provided}.\par Secondreal'' argument is \IfValueTF{#3}{#3}{not provided}.\par Third ``real'' argument is \IfValueTF{#5}{#5}{not provided}.\par } \ExplSyntaxOn \keys_define:nn { mykeys } { a .tl_set:N = \l_mykeys_a_tl, b .tl_set:N = \l_mykeys_b_tl, c .tl_set:N = \l_mykeys_c_tl } \NewDocumentCommand{\wrapper}{ O{} }{ \keys_set:nn{mykeys}{#1} \mycmd \tl_if_empty:NTF \l_mykeys_a_tl {} { [\l_mykeys_a_tl] } {} \tl_if_empty:NTF \l_mykeys_b_tl {} { [\l_mykeys_b_tl] } {} \tl_if_empty:NTF \l_mykeys_c_tl {} { [\l_mykeys_c_tl] } } \ExplSyntaxOff

\begin{document}

\mycmd[13]{}{}[2]

\noindent\hrulefill

\wrapper[a=13, c=2]

\end{document}

Output of MWE

steve
  • 2,154
  • Then \mycmd would have a very weird usage requirements; do you really need it? – egreg Mar 15 '21 at 08:21
  • it would be far simpler (and conventional) to have the inner command just have three mandatory arguments. The optional arguments server no purpose if you are using a keyval interface at the top. – David Carlisle Mar 15 '21 at 09:39
  • as written when called from \wrapper , \mycmd is never called with an optional argument just two mandatory arguments \mycmd{\tl_if_empty:NTF}{\l_mykeys_a_tl} – David Carlisle Mar 15 '21 at 09:42
  • @DavidCarlisle The advantage of having the arguments be optional is that I can check if the value is empty without requiring \tl_if_blank:NTF, which isn't supported by tcolorbox. However, your second comment is really the crux of the question; how can I pass the (nonempty) keys to \mycmd? – steve Mar 15 '21 at 12:16
  • @steve no really there is no advantage at all you are making things weirdly complicated and doubling the number of arguments used (so you are lucky to stay below 9) your inner command doesn't need to test for if_blank because your key definition can specify a default so you can always pass three real arguments to the inner call. That is the point of the xparse parsing (actually xparse package not needed with current latex, it is built in) that sorting out defaults is done at that level and then call a standard command which does not deal with user-interface issues like default values – David Carlisle Mar 15 '21 at 12:37

0 Answers0