13

I would like to define a command that accepts a variable number of arguments:

\menu{foo}
% would result in \emph{foo}

\menu{foo}{bar}
% would result in \emph{foo} $\to$ \emph{bar}

\menu{foo}{bar}{baz}
% would result in \emph{foo} $\to$ \emph{bar} $\to$ \emph{baz}

and so on. Is this possible, and if it is, how can I do this?

Tobi
  • 56,353
vwegert
  • 2,875
  • 5
    Doing it in complete generality is impossible; you need a terminator. A better syntax would be to provide one argument as a comma separated list of values. – egreg Mar 07 '13 at 14:41
  • 2
    Note that in LaTeX you really shouldn't do this as it breaks the syntax rules that latex tries to make consistent. All LaTeX commands always have a fixed number of {} argumnets, optional arguments should be [] or here probably better a comma separated list within a single argument. – David Carlisle Mar 07 '13 at 14:49
  • @egreg and DavidCarlisle, I can see we all had the same idea. I wrote my answer before reading your comments – JLDiaz Mar 07 '13 at 14:52
  • I don't think it's a duplicate: the linked question is about a completely different need. – egreg Mar 07 '13 at 15:06
  • @Tobi You can vote for reopening – egreg Mar 07 '13 at 15:19
  • @egreg "Doing it in complete generality is impossible". What about my answer here then? http://tex.stackexchange.com/questions/305383/how-to-write-macro-with-variable-amount-of-text-variables – User Apr 21 '16 at 09:59
  • @User You're not defining a macro with a variable number of arguments, but a macro with a possibly large, but fixed, number of arguments. – egreg Apr 21 '16 at 10:30
  • @egreg. In what sense "fixed"? I don't think so. What do you mean than with a "variable number of argument macro"? – User Apr 21 '16 at 10:37
  • @User In the question, the OP wants a macro that continues to absorb arguments, with no predetermined limit. – egreg Apr 21 '16 at 10:38
  • @egreg. My macro does exactly this. Where have you found the predetermined limit in it? – User Apr 21 '16 at 10:42
  • @User \ifnum\NUMARGS=4\endgraf: this I call a predetermined limit. – egreg Apr 21 '16 at 10:48
  • @egreg. Of course, because we already know that the number of arguments of\sigblock can vary only between three and four. But what about the first example called \mymacro? Does the same hold there? I see no predetermined limit in it – User Apr 21 '16 at 10:54
  • @User You're using a terminator; precisely, you end when a { is not scanned after having absorbed the last braced group as argument. This doesn't make for “full generality”. And it also gobbles spaces at the end of the job. – egreg Apr 21 '16 at 11:31

3 Answers3

15

Use menukeys … I guess it’s what your looking for ;-)

\documentclass{article}

\usepackage{menukeys}

% create a new simple style to add arrwos between the items
\newmenustylesimple*{arrows}{\CurrentMenuElement}[ $\to$ ]{blacknwhite}

\begin{document}
\menu{foo > bar > baz}

\bigskip

% apply the new style to the old macro. The optional arguments
% defines the separator, the default is a comma
\renewmenumacro{\menu}[>]{arrows}
\menu{foo > bar > baz}
\end{document}

menukeys

The first line shows the default style of \menu, but it’s possible to change it in many ways. The example shows a very simple style. More predefined styles can be found in the manual …

Tobi
  • 56,353
13

Not exactly what you requested, but with the same functionality could be the following:

\documentclass{article}
\usepackage{pgffor}   % you don't need this if tikz is already included
\begin{document}
\def\menu#1{%
 \gdef\firstelement{1}
 \foreach \e in {#1}{%
   \ifnum\firstelement=0$\to$\fi\emph{\e}%
   \gdef\firstelement{0}%
 }
}

\menu{foo}\par
\menu{foo,bar}\par
\menu{foo,bar,baz}\par
\end{document}

Result

JLDiaz
  • 55,732
9

With LaTeX3 macros, using a list of items instead of a variable number of arguments (which is not recommended in LaTeX) is rather easy.

Why not using a variable number of arguments? The main reason has been explained by David in a comment; another reason is in awkwardness of the implementation; one should start a recursion, store the last found argument and check for a left brace; if found continue the recursion, otherwise stop and output the result. Since the arguments need to be stored anyway, it's better to use one argument and implement the command by cycling over the entries.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\menu}{m}
 {
  \vwegert_menu:nnn { , } { #1 } { \emph }
 }
\NewDocumentCommand{\xmenu}{O{,}mO{\emph}}
 {
  \vwegert_menu:nnn { #1 } { #2 } { #3 }
 }
\cs_new_protected:Npn \vwegert_menu:nnn #1 #2 #3
 {
  % split the list at the chosen separator
  \seq_set_split:Nnn \l_vwegert_input_seq { #1 } { #2 }
  \seq_clear:N \l_vwegert_output_seq
  % add `\emph` around the items (or what's desired)
  \seq_map_inline:Nn \l_vwegert_input_seq
   { \seq_put_right:Nn \l_vwegert_output_seq { #3{ ##1 } } }
  % print the result
  \seq_use:Nnnn \l_vwegert_output_seq { $\to$ } { $\to$ } { $\to$ }
 }
\seq_new:N \l_vwegert_input_seq
\seq_new:N \l_vwegert_output_seq

\ExplSyntaxOff

\begin{document}
\menu{foo}

\menu{foo,bar}

\xmenu[;]{foo;bar;baz}[\textbf]

\end{document}

We have a simple command \menu without options and a more powerful one \xmenu with which you can change the separator (leading optional argument) or the formatting (trailing optional argument); the trailing optional argument should be a command taking exactly one argument.

The working is:

  1. Split the list into components; leading and trailing spaces will be removed.

  2. Add to each element the chosen formatting (default \emph).

  3. Produce each element of the list, with $\to$ between any two elements.

enter image description here

egreg
  • 1,121,712