I was looking for a way of grabbing sub and superscripts as optional arguments to a command in xparse. That is, \foo_{a}^{b}
would receive a
as an optional argument and b
as another optional argument. The nice thing of this is that we could have control over one of the primitive things of TeX that we have zero control right now.
1 Answer
Well, I asked on the LaTeX-L list, but then decided to give it a try, copying here and there from the package, I ended with this (if this has no errors, I will send a message to the list, but here at least I can edit and correct typos).
This code adds a new type of argument k
and K
(Why k? I don't really know, if you have a better suggestion you can tell me. For now grab, remove, token, etc. are taken, so I decided token —I didn't want to use the famous extra x from every xpackage—). First one must be followed by the token to check (exactly like t
arguments) and K
must be followed by the token and the default argument, e.g., K*{<default>}
. I tried to follow what I saw as standards in xparse (except the “don't gobble spaces looking for a trailing optional argument”). Ah, and there's no expandable one, because I didn't need it right now, so I just skipped that.
This argument type checks if a token exists, and, if it's there, removes it and takes the next argument (single token, or braced argument). For instance
\NewDocumentCommand\foo{mk*}
would grab\foo{a}
(#1
=a
,#2
=-NoValue-
), and\foo{a}*{b}
(#1
=a
,#2
=b
)
In particular, I wanted this for sub and superscripts, so I created two “shorthands” a
= k_
and b
= k^
(and the similar A
and B
).
Here's the code with a few examples.
\documentclass{scrartcl}
\usepackage{mathtools,amssymb,xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \__xparse_count_type_k:w #1
{
\__xparse_single_token_check:n { #1 }
\quark_if_recursion_tail_stop_do:Nn #1 { \__xparse_bad_arg_spec:wn }
\__xparse_count_mandatory:N
}
\cs_new_protected:Npn \__xparse_count_type_K:w #1 #2
{
\__xparse_single_token_check:n { #1 }
\quark_if_recursion_tail_stop_do:nn { #2 } { \__xparse_bad_arg_spec:wn }
\__xparse_count_mandatory:N
}
\cs_new_protected:Npn \__xparse_add_type_k:w #1
{ \exp_args:NNo \__xparse_add_type_K:w #1 { \c__xparse_no_value_tl } }
\cs_new_protected:Npn \__xparse_add_type_K:w #1 #2
{
\__xparse_flush_m_args:
\__xparse_add_grabber_optional:N K
\tl_put_right:Nn \l__xparse_signature_tl { #1 { #2 } }
\__xparse_prepare_signature:N
}
\cs_new_protected:Npn \__xparse_add_expandable_type_k:w #1
{
\exp_args:NNo \__xparse_add_expandable_type_K:w #1 { \c__xparse_no_value_tl }
}
\cs_new_protected_nopar:Npn \__xparse_add_expandable_type_K:w #1 #2
{
\__msg_kernel_error:nnx { xparse } { invalid-expandable-argument-type } { K }
\__xparse_add_expandable_type_m:w % May be create this?
}
\cs_new_protected:Npn \__xparse_grab_K:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected_nopar:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_long:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_trailing:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected_nopar:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_long_trailing:w #1 #2 #3 \l__xparse_args_tl
{
\__xparse_grab_K_aux:NnnNn #1 { #2 } { #3 } \cs_set_protected:Npn
{ _ignore_spaces }
}
\cs_new_protected:Npn \__xparse_grab_K_aux:NnnNn #1 #2 #3 #4 #5
{
\exp_after:wN #4 \l__xparse_fn_tl ##1
{
\__xparse_add_arg:n { ##1 }
#3 \l__xparse_args_tl
}
\use:c { peek_meaning_remove #5 :NTF } #1
{ \l__xparse_fn_tl }
{
\__xparse_add_arg:n { #2 }
#3 \l__xparse_args_tl
}
}
\prop_put:Nnn \c__xparse_shorthands_prop { a } { k \sb }
\prop_put:Nnn \c__xparse_shorthands_prop { b } { k \sp }
\prop_put:Nnn \c__xparse_shorthands_prop { A } { K \sb }
\prop_put:Nnn \c__xparse_shorthands_prop { B } { K \sp }
\prop_put:Nnn \c__xparse_shorthands_prop { 1 } { m }
\prop_put:Nnn \c__xparse_shorthands_prop { 2 } { m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 3 } { m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 4 } { m m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 5 } { m m m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 6 } { m m m m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 7 } { m m m m m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 8 } { m m m m m m m m }
\prop_put:Nnn \c__xparse_shorthands_prop { 9 } { m m m m m m m m m }
\ExplSyntaxOff
\NewDocumentCommand\foo{ O{bigg} 3 a b }
{
\csname#1l\endcsname(
#2 \csname#1m\endcsname| \frac{#3}{#4}
\csname#1r\endcsname)
\IfValueT{#5}{_{\mkern-5mu \mathrm{#5}}}
\IfValueT{#6}{^{\mkern-5mu \{#6\}}}
}
\NewDocumentCommand\baz{ a b }
{\iiiint\limits\IfValueT{#1}{_{#1}}\IfValueT{#2}{^{\quad#2}}}
\NewDocumentCommand\lint{ A{a} B{b} }{\underline{\int_{#1}^{#2}}}
\NewDocumentCommand\uint{ A{a} B{b} }{\overline{\int_{#1}^{#2}}}
\begin{document}
\[
\foo{X}{Y}{Z}_{min}^{bc} \quad
\lint f(t) \, dt \quad
\uint_{a(s)}^{b(s)} f(t) \, dt \quad
\iiiint\limits_{aaa}^{bbb} \xi \quad
\baz_{aaa}^{bbb} \zeta
\]
\end{document}
May be in the future I try to create something like t{*,-,+,!}
so that a command takes one token if it's there from the list \foo*
, \foo-
, \foo+
or \foo!
without the need ot t* t- t+ t!
.