I too believe you're better using two commands; but, just for showing the power of expl3
, here's a (complicated) solution for \cftpagenumbersoff
(and also for the complementary \cftpagenumberson
)
\documentclass{book}
\usepackage{tocloft,xparse}
\ExplSyntaxOn
% A table of equivalents: \cftchapname (=chapter) -> chap and so on
\prop_new:N \g_cft_names_prop
\cs_generate_variant:Nn \prop_gput:Nnn { Nv }
\clist_map_inline:nn
{chap,sec,subsec,subsubsec,para,subpara,fig,subfig,tab,subtab}
{
\prop_gput:Nvn \g_cft_names_prop { cft#1name } { #1 }
}
\NewDocumentCommand{\xcftpagenumbersoff}{m}
{
\clist_map_inline:nn { #1 } { \cft_pagenumbersoff:n { ##1 } }
}
% \cftpagenumbersoff is a gigantic sequence of \ifx, using \@cftpnumoff
% If the argument is section, it is compared to all known \cftXname commands
% and action is taken; with a property list it's easier
% First we store a copy of \@cftpnumoff
\cs_set_eq:Nc \cft_pnumoff:n { @cftpnumoff }
% We also define a variant that does complete expansion
\cs_generate_variant:Nn \cft_pnumoff:n { x }
\cs_new_protected:Npn \cft_pagenumbersoff:n #1
{
\prop_if_in:NnTF \g_cft_names_prop { #1 }
{% if the argument is in the table, we get from it the abbreviation (chapter->chap)
\cft_pnumoff:x { \prop_get:Nn \g_cft_names_prop { #1 } }
}
{% otherwise we use directly the argument
\cft_pnumoff:n { #1 }
}
}
\NewDocumentCommand{\xcftpagenumberson}{m}
{
\clist_map_inline:nn { #1 } { \cft_pagenumberson:n { ##1 } }
}
\cs_set_eq:Nc \cft_pnumon:n { @cftpnumon }
\cs_generate_variant:Nn \cft_pnumon:n { x }
\cs_new_protected:Npn \cft_pagenumberson:n #1
{
\prop_if_in:NnTF \g_cft_names_prop { #1 }
{
\cft_pnumon:x { \prop_get:Nn \g_cft_names_prop { #1 } }
}
{
\cft_pnumon:n { #1 }
}
}
\ExplSyntaxOff
\xcftpagenumbersoff{subsection,section}
\begin{document}
\tableofcontents
\chapter{A chapter title}
\section{A section title}
\subsection{A subsection title}
\addtocontents{toc}{\xcftpagenumberson{section,subsection}}
\section{X}
\subsection{Y}
\end{document}
Let's tackle the problem from a more general point of view. Given a macro \foo
that takes an argument and does some background action with it, define \xfoo
that does the same actions on multiple arguments specified as a comma separated list.
Note that this wouldn't make sense for commands such as \textbf
that typeset their argument.
\usepackage{xparse} % access to expl3
\ExplSyntaxOn
\NewDocumentCommand{\xfoo}{m}
{
\clist_map_inline:nn { #1 } { \foo {##1} }
}
\ExplSyntaxOff
would be just enough.
The previous solution could so have simply been written
\ExplSyntaxOn
\NewDocumentCommand{\xcftpagenumbersoff}{m}
{
\clist_map_inline:nn { #1 } { \cftpagenumbersoff {##1} }
}
\ExplSyntaxOff
but I preferred to avoid using too many layers over the basic \@cftpnumoff
command, presenting some ideas about LaTeX3 programming.
One might think to save a copy of \foo
and redefining it, but this opens new problems, because \foo
might be defined with \DeclareRobustCommand
and a simple \let\originalfoo\foo
wouldn't be sufficient. There would be a way to do it also in this case (with \LetLtxMacro
), but in general it's better not to change drastically the syntax of an existing command.
tocloft
has not implemented the\cftpagenumbersoff
to work that way, the code you'd need to add to allow it would be more than the extra lines needed to use the command for multiple document subdivisions.\cftpagenumbersoff{{section},{subsection}}
, etc., but to no avail. Or is the answer to my question simply that I do have to write the command twice?