5

Is there a way to give a "name" to the arguments of a command and use them in its definition? What I'd like to do is to be able to get the value of an argument with a "label" like #myargname instead of #<number>. For example, I'd like to define a \foocommand like

\newcommand{\foocommand}[#normal,#bold,#italics,#smallcaps,#emphasis]%
           {#normal \textbf{#bold} \textit{#italics} \textsc{#smallcaps} \emph{#emphasis}}

instead of

\newcommand{\foocommand}[5]%
           {#1 \textbf{#2} \textit{#3} \textsc{#4} \emph{#5}}
Ntakwetet
  • 631
  • 5
    But the same input should prevail? As in \foocommand{one}{two}{three}{four}{five}, with no indication of what their components mean? Or would you rather have \foocommand{bold=two, smallcaps=four, emphasis=five, italics=three, normal=one}? – Werner Jun 16 '20 at 16:34
  • 2
    see https://tex.stackexchange.com/a/549462/2388 – Ulrike Fischer Jun 16 '20 at 16:39
  • If you have an up-to-date TeXLive, you should have the namedef package installed, otherwise check it out here. Section 4.1 of the documentation (“Extended \newcommand”) features an interface like the one you want. – Phelype Oleinik Jun 22 '20 at 11:39

3 Answers3

2

You can. Here's a proof of concept.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn \NewDocumentCommand{\newparametercommand}{smO{}m} { \IfBooleanTF { #1 } { \ntakwetet_newparametercommand:Nnnn \cs_set_nopar:cV { #2 } { #3 } { #4 } } { \ntakwetet_newparametercommand:Nnnn \cs_set:cV { #2 } { #3 } { #4 } } }

\tl_new:N \l__ntakwetet_replacement_tl \int_new:N \l__ntakwetet_index_int \cs_generate_variant:Nn \cs_set:Nn { cV } \cs_generate_variant:Nn \cs_set_nopar:Nn { cV }

\cs_new_protected:Nn \ntakwetet_newparametercommand:Nnnn { \tl_set:Nn \l__ntakwetet_replacement_tl { #4 } % double the # \regex_replace_all:nnN { \cP. } { \cP#\cP# } \l__ntakwetet_replacement_tl % index for the parameters \int_zero:N \l__ntakwetet_index_int % substitute any item in the list of parameters with #<n> \clist_map_inline:nn { #3 } { \int_incr:N \l__ntakwetet_index_int \exp_args:Nne \regex_replace_all:nnN { ##1 } % search { \exp_not:n { \cP# } \int_eval:n { \l__ntakwetet_index_int } } % replace \l__ntakwetet_replacement_tl } % define a temporary macro with #1=\cs_set:cV or \cs_set_nopar:cV #1 {__ntakwetet_temp:\prg_replicate:nn { \l__ntakwetet_index_int } { n } } % name \l__ntakwetet_replacement_tl % replacement \cs_new_eq:Nc #2 {__ntakwetet_temp:\prg_replicate:nn { \l__ntakwetet_index_int } { n } } }

\ExplSyntaxOff

\newparametercommand\foo[#abc,#def]{#abc,#def}

\newparametercommand*\baz[#abc,#def]{#abc--#def}

\newparametercommand{\foocommand}[#normal,#bold,#italics,#smallcaps,#emphasis]{% #normal \textbf{#bold} \textit{#italics} \textsc{#smallcaps} \emph{#emphasis}% }

\begin{document}

\foo{a}{b}

\baz{a}{b}

\foocommand{normal}{bold}{italics}{smallcaps}{emphasis}

\end{document}

Each item in the comma separated list is searched for in the replacement text and substituted with #<n> for the current index.

Limitation: a keyword cannot have another keyword as initial segment. So #a and #aa would not work. Also one cannot use more than nine arguments, of course.

enter image description here

egreg
  • 1,121,712
1

Not automatic, but simple and easy.

\documentclass{article}

\newcommand{\foo}[2]% #1=\first, #2=\second {\bgroup% make definitions local \def\first{#1}% \def\second{#2}% Arguments are \first{} and \second. \egroup}

\begin{document} \foo{A}{B} \end{document}


Alternate, but prone to errors.

\documentclass{article}

\newcommand{\foo}[1]% #1 = TeX definitions {\bgroup% make definitions local #1 Arguments are \first{} and \second. \egroup}

\begin{document} \foo{\def\first{A}\def\second{B}} \end{document}

John Kormylo
  • 79,712
  • 3
  • 50
  • 120
0

EDITED to remove the deficiency of the prior approach.

If you don't mind changing your syntax in the following ways:

  1. Change your symbolic-argument identifier from # to something that is not cat 6, here done with !

  2. Define the new command with \symbolicnewcommand, since \newcommand is already defined with a different syntax.

Thus, the syntax is something like:

\symbolicnewcommand{\foocommand}%
  [!normal,!bold,!italics,!smallcaps,!emphasis,!boxed]%
  {!normal{} \textbf{!bold} \textit{!italics} 
   \textsc{!smallcaps} \emph{!emphasis} \fbox{!boxed}}

Unlike my prior approach, this approach doesn't merely mimic the \newcommand behavior, but recreates it, by converting the symbolic arguments into explicit #1, #2, etc., (i.e., NOT placed inside a \def).

Here is the MWE. Note that in the \meaning of the defined macro, the symbolic arguments, for example, !normal, is converted into an explicit #1.

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{listofitems,tokcycle}
\newtoks\mytoks
\newtoks\tmptoks
\def\OPENSgroup{\OPENSgroup}% quark
\def\CLOSEgroup{\CLOSEgroup}% quark
\def\SPACEquark{\SPACEquark}% quark

\newcommand{\addtotoks}[2]{#1\expandafter{\the#1#2}} \newcommand{\xaddtotoks}[2]{% \expandafter\addtotoks\expandafter#1\expandafter{#2}}

\makeatletter \long\def\symbolicnewcommand#1[#2]#3{% \readlist\arglist{#2}% \stripgroupingtrue% \tokcycle{\addcytoks{##1}}% {\addcytoks{\OPENSgroup}\processtoks{##1}\addcytoks{\CLOSEgroup}}% {\addcytoks{##1}}{\addcytoks{\SPACEquark}}{#3}% \mytoks\expandafter{\the\cytoks}% \foreachitem\z\in\arglist[]{% \expandafter\setsepchar\expandafter{\z}% \expandafter\def\expandafter\tmp\expandafter{\the\mytoks}% \readlist\cmdlist{\tmp}% \mytoks{}% \foreachitem\zz\in\cmdlist[]{% \ifnum\zzcnt=1\relax\else% \tmptoks{&}% \xaddtotoks\tmptoks{\zcnt}% \xaddtotoks\mytoks{\the\tmptoks}% \fi% \xaddtotoks\mytoks{\zz}% }% }% % \setsepchar{&}% \expandafter\readlist\expandafter\cmdlist\expandafter{\the\mytoks}% \mytoks{}% \foreachitem\z\in\cmdlist[]{% \ifnum\zcnt=1\relax\else\addtotoks\mytoks{####}\fi% \xaddtotoks\mytoks{\z}% }% % \expandafter\addBracesSpaces\expandafter{\the\mytoks}% % \def\tmp{\newcommand{#1}[\arglistlen]}% \expandafter\tmp\expandafter{\the\mytoks}% }

\newcommand\addBracesSpaces[1]{\mytoks{}\fooaux#1\endfoo} \def\fooaux#1{% \tctestifx{\endfoo#1}{} {\tctestifx{\OPENSgroup#1}{\Z} {\tctestifx{\SPACEquark#1}{\addtotoks\mytoks{ }} {\addtotoks\mytoks{#1}}\fooaux}}% } \makeatother

\def\Z#1\CLOSEgroup{\addtotoks\mytoks{{#1}}\fooaux}

\symbolicnewcommand{\foocommand}% [!normal,!bold,!italics,!smallcaps,!emphasis,!boxed]% {!normal{} \textbf{!bold} \textit{!italics} \textsc{!smallcaps} \emph{!emphasis} \fbox{!boxed}} \begin{document} \meaning\foocommand

\foocommand{To be,}{or not}{to be?}{That}{is the question.}{123} \end{document}

enter image description here