The \newcommand
macro allows to use an optional argument for the first parameter #1
with:
\newcommand{\mycommand}[3][defaultfor1]{blah blah blah}
Is it possible to have more than one option with \newcommand
?
Try the LaTeX 3 package xparse
. For example:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\foocmd}{ O{default1} O{default2} m }{#1~#2~#3}
% ⤷ #1 ⤷ #2 ⤷ #3
\begin{document}
\foocmd{foo} \par
\foocmd[nondefault1]{foo} \par
\foocmd[nondefault2][notfoo2]{foo} \par
\end{document}
You may read the documents for more information.
xparse
even allows for an optional starred *
version of the command \foocmd
by using the s
parameter. See the xparse
documentation.
xparse
work properly when nested, so \foo[[bar]]{stuff}
works to parse [bar]
as the optional argument. That is not true for \newcommand
.
\DeclareDocumentCommand
and egreg already reached rep cap today anyway ;-)
You've got answers for other approaches, so here is the basics using the kernel only. You'll need to define your macros by hand, something like
\makeatletter
\def\mycommand{%
\@ifnextchar[%
{\mycommand@i}
{\mycommand@i[<default-for-1>]}%
}
\def\mycommand@i[#1]{%
\@ifnextchar[%
{\mycommand@ii{#1}}
{\mycommand@ii{#1}[<default-for-2>]}%
}
\def\mycommand@ii#1[#2]#3{%
% Do stuff
}
\makeatother
This can of course be extended to more complex cases. (Here, I'm leaving it up to you whether to make your function \long
or not. If you want part of it to be long, then all of the internal macros should be long. The xparse
approach allows this to vary between arguments, based on some internal shuffling.)
twoopt
and xparse
, when the other two answers popped up :-)
\usepackage{twoopt}
\newcommandtwoopt{\xyz}[3][Def1][Def2]{Something with #1, #2 and #3}
There are also \renewcommandtwoopt
and \providecommandtwoopt
.
However the xparse package (part of the LaTeX3 package tree, but works also with LaTeX2e) provides \DeclareDocumentCommand
that gives great flexibility in defining commands with optional arguments in every position and also *-versions.
Historical note
In TeX Live there is a newcommand.py
Python script accompanied by documentation accessible by texdoc newcommand
. For example, to obtain code for defining a command with two optional arguments and a mandatory one, one launches
python /usr/local/texlive/2011/texmf-dist/doc/latex/newcommand/newcommand.py
and at the prompt % Prototype:
answers with
MACRO twoopt OPT[#1={Def1}] OPT[#2={Def2}] #3
where \twoopt
is the macro we want to define. The script will build a skeleton for defining the macro:
\makeatletter
\newcommand{\twoopt}[1][Def1]{%
\@ifnextchar[{\twoopt@i[{#1}]}{\twoopt@i[{#1}][{Def2}]}%
}
\def\twoopt@i[#1][#2]#3{%
% Put your code here.
% You can refer to the arguments as #1 through #3.
}
\makeatother
The commented lines should be replaced by the actual code.
With the specification
MACRO finalopt #1 OPT[#2={default}]
one defines a macro with a mandatory argument followed by an optional one:
\makeatletter
\newcommand{\finalopt}[1]{%
\@ifnextchar[{\finalopt@i{#1}}{\finalopt@i{#1}[{default}]}%
}
\def\finalopt@i#1[#2]{%
% Put your code here.
% You can refer to the arguments as #1 and #2.
}
\makeatother
twoopt
is only limited to two optional arguments I guess?
One more resolution for several optional arguments problem.
\documentclass{article}
\usepackage{xargs}
\newcommandx{\foo}[4][1=defaultFirstArg, 3=defaultThirdArg]{#1~#2~#3~#4}
\begin{document}
\foo{B}{D}
\foo[A]{B}{D}
\foo{B}[C]{D}
\foo[A]{B}[C]{D}
\end{document}
I hope there is nothing to comment here. Also \renewcommandx
, \newenvironmentx
, \renewenvironmentx
, \providecommandx
, \DeclareRobustCommandx
, \CheckCommandx
and their starred versions are available.
Upd. As far as you can see in my example two optional arguments with madatory one in between give you possibility to specify any one of them.
There is a disadvantage using two or more optional arguments. If the user wants to change the default for the second argument, then he must specify the default value of the first argument explicitly. As an example, the optional depth argument of \raisebox
should be set, but the resulting height should not be changed. That makes the first optional argument cumbersome:
\raisebox{-1ex}[\dimexpr\height-1ex\relax][0pt]{foobar}
An alternative approach is to design the macro with one optional argument exactly, but supporting the key value interface. Nice would be:
\raisebox[depth=0pt]{foobar}
Also it is easy to define new keys to support new features without changing the signature of the command (number and type of options).
There are many packages that support defining and parsing keys (e.g., keyval
and similar packages, pgfkeys
, …).
I know I'm late on this. Another solution without requiring any additional packages might be:
First we define a command to check whether something is entered:
\newcommand{\ifNoWidthThenElse}[1]{%
\begingroup
\setbox0\hbox{#1}%
\ifdim\wd0>0pt
\endgroup
\expandafter\@firstoftwo
\else
\endgroup
\expandafter\@secondoftwo
\fi
}
The above is not expandable and checks the width, so entering something, which doesn't produce contents of any width, wouldn't end up as intended. So better would be:
\makeatletter
\newcommand{\MyIfEmtpyTF}[1]{%
\if\relax\detokenize{#1}\relax%
\expandafter\@firstoftwo%
\else%
\expandafter\@secondoftwo%
\fi}
\makeatother
Then we use this command to create our new command:
\newcommand{\mycommand}[2][]{%
\MyIfEmptyTF{#2}{\foo}{\bar}%
#1
}
With \foo
being the command which should be called if leave out the second argument and \bar
if you use it. This way you can use the first argument as a normal optional argument and the second argument behaves similar to an optional argument but you have to set the {}
.
Call the function like this:
\mycommand[optional1]{optional2}
if you use both,
\mycommand{optional2}
if you use only the second, and
\mycommand[optional1]{}
if you use only the first.
\setbox1
and not \setbox0
as the conventions about local vs. global assignments would dictate? (2) Are you sure you don’t actually mean \MyIfEmptyTF{#2}{\foo}{\bar{#2}}
?
\setbox1
, thanks, when I first wrote this answer I did not know those conventions to be honest. The \foo
and \bar
were intended to be anything OP wants, I therefore didn't forward the argument.
\sbox{0}{...}
rather than \setbox0=\hbox{...}
.
Is it possible to have more than one option with \newcommand?
appears to beNo, not without extra packages.