When you do \ShowCommand in a command defined with \NewDocumentCommand, LaTeX counts the number of arguments in the signature of the command and splits for pretty-printing. For example:
\NewDocumentCommand \foo { e{^_} E{^_}{{a}{b}} >{\SplitArgument}+O{} m }
{ do stuff }
\ShowCommand \foo
prints:
> \foo=document command:
#1:e^
#2:e_
#3:E^{a}
#4:E_{b}
#5:>{\SplitArgument }+O{}
#6:m
-> do stuff .
However, that is done by the internal \__cmd_split_signature:n, which counts the number of arguments and stores them in a token list for the pretty-printing, and there isn't a public interface for that. But you can copy the implementation and do something similar.
Here's an expandable version of that which just counts the arguments and returns the count (a shameless ripoff of the kernel command, with some limbs cut off because it just needs to count the arguments :)
\ExplSyntaxOn
\cs_new:Npn \usersixdigits_count_signature:n #1
{
\int_eval:n
{ 0 \__usersixdigits_split_signature_loop:Nw #1 \q_recursion_tail \q_recursion_stop }
}
\cs_new:Npn \__usersixdigits_split_signature_loop:Nw #1
{
\quark_if_recursion_tail_stop:N #1
\tl_if_exist:cTF { c__usersixdigits_show_type_#1_tl }
{
\use:c
{
__usersixdigits_show_
\if_case:w \tl_use:c { c__usersixdigits_show_type_#1_tl } \exp_stop_f:
delim \or: delims \or: delims_opt \or: opt \or:
e \or: E \or: prefix \or: processor \fi: :Nw
} #1
}
{ +1 \__usersixdigits_split_signature_loop:Nw }
}
\cs_set:Npn \__usersixdigits_tmp:w #1 #2
{
\quark_if_nil:nF {#1}
{ \tl_const:cn { c__usersixdigits_show_type_#1_tl } {#2} \__usersixdigits_tmp:w }
}
\__usersixdigits_tmp:w t0 r1 d1 R2 D2 O3 e4 E5 +6 !6 >7 \q_nil \q_nil
\cs_new:Npn \__usersixdigits_show_delim:Nw #1 #2
{ +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_delims:Nw #1 #2 #3
{ +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_delims_opt:Nw #1 #2 #3 #4
{ +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_opt:Nw #1 #2
{ +1 \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_e:Nw #1 #2
{ + \tl_count:n {#2} \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_E:Nw #1 #2 #3
{ + \tl_count:n {#2} \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_prefix:Nw #1
{ \__usersixdigits_split_signature_loop:Nw }
\cs_new:Npn \__usersixdigits_show_processor:Nw #1 #2
{ \__usersixdigits_split_signature_loop:Nw }
\typeout { \usersixdigits_count_signature:n { m } }
\typeout { \usersixdigits_count_signature:n { +m } }
\typeout { \usersixdigits_count_signature:n { +!m } }
\typeout { \usersixdigits_count_signature:n { +!O{x} } }
\typeout { \usersixdigits_count_signature:n { >{\SplitArgument}+!O{x} } }
\typeout
{
\usersixdigits_count_signature:n
{ e{^} E{^}{{a}{b}} >{\SplitArgument}+O{} m }
}
\stop
\ShowCommand, som I implemented something like that. After\__cmd_split_signature:n { <signature> }the int variable\l__cmd_current_arg_intwill hold the number of arguments in<signature>plus one. Of course you should not use those names in your code, since they are private to the kernel, but you can take inspiration in the implementation to write your own. – Phelype Oleinik Jul 03 '22 at 02:01\<cmd> codeis a reliable source. – muzimuzhi Z Jul 03 '22 at 02:38