Open main menu

Changes

Add pitfall with nested macro calls
< [[Inside ConTeXt]] | [[Commands with KeyVal arguments]] >
In LaTeX you define a new command with an optional argument with "newcommand": <texcode>\newcommand{\MyCommand}[2][World]{{#2Hello #1!}}\MyCommand{\bfseries}\MyCommand[Hans]{\scshape}</texcode> <context>{\bf Hello World!}{\sc Hello Hans!}</context> In ConTeXt, the optional argument processing is handled as a two-step process. First, we write the command for the end-user as a wrapper command, which calls <{{cmd|dosingleempty}}, {{cmd>|dodoubleempty</}}, {{cmd> |dotripleempty}}, ... (from [http://source.contextgarden.net/tex/context/base/{{src|syst-genaux.tex mkiv}} or {{src|syst-gen.tex]mkii}}) to handle the arguments properly -- including the optional ones -- and then calls a "private" command that contains the internals of the macro. Note that this function call does not explicitly refer to the arguments at all.
For a command with two optional arguments, we use:
<texcode>
\def\MyCommand{\dodoubleempty\doMyCommand}
</texcode>
We then create the "private" macro (<tt>\doMacroName</tt> is the traditional ConTeXt name for these), with all the arguments defined as nonoptional. Default values for the arguments need to be handled somewhat more explicitly than with LaTeX; macros such as <{{cmd>|ifsecondargument</cmd> }} are used to determine whether the given argument was specified, as follows:
<texcode>
</context>
If you ''don't'' want any optional arguments, but still want your arguments enclosed in <tt>[]</tt> with appropriate handling for spaces (or line breaks) between the square brackets, use <{{cmd>|dodoubleargument</cmd> }} instead of <{{cmd>|dodoubleempty</cmd>}}. There are of course versions for other numbers of arguments, found by replacing <tt>double</tt> with <tt>single</tt> through <tt>seventuple</tt>; see [http://source.contextgarden.net/tex/context/base/syst-gen.mkii {{src|syst-genaux.tex] mkiv}} for the exact names.
=== Examples ===
To define <ttcode>\mycommand[.#1.][.2.]{.3.}</tt>, i.e., with curly braces around a non-optional third argument, you just define <texcode>\def\mycommand{\dodoubleempty\doMycommand}\def\doMycommand[#1][#2]#3{whatever}</texcode>    To define <code>\mycommand[with one optional]{text}</code>argument and one mandatory argument, do the following <texcodecontext source="yes"
\def\mynewcommand{\dosingleempty\doMyNewCommand}
\def\doMyNewCommand[#1]#2{%
\iffirstargument
There is an optional parameter: {\bf #1}\par%
\else
No optional parameter\par%
\fi
This is the mandatory text: {\em #2}%
}
\starttext
\mynewcommand[opt]{Hello People}
\blank
\mynewcommand{Hello People}
\stoptext
</texcodecontext>
<context>
To define <code>\def\mynewcommand{\dosingleempty\doMyNewCommand}\def\doMyNewCommandmycommand[#1][#2]{% \iffirstargument There is an optional parameter: {\bf #13}\par \else No </code> with two optional parameter\par \fi This is the arguments and one mandatory text: {\em #2}}argument, do
<texcode>\starttextdef\mynewcommand[opt]mycommand{Hello People\dodoubleempty\doMycommand}\blankdef\mynewcommanddoMycommand[#1][#2]#3{Hello Peoplewhatever}\stoptext</contexttexcode>
=== Pitfalls ===
Please keep ==== Passing preceding command's argument ==== Keep in mind that <code>\iffirstargument</code> will always return true if you put before it a command which itself has an argument. See the following example:
<context source="yes" text="produces">
\startalignment[center]
\iffirstargument
There is an optional parameter: {\bf #1}\par%
\else
No optional parameter\par%
\fi
This is the mandatory text: {\em #2}%
\stopalignment
}
Use <code>\doifsomethingelse</code> instead:
<context source="yes" text="This time this time is correct:">
\def\mynewcommand{\dosingleempty\doMyNewCommand}
\def\doMyNewCommand[#1]#2{%
\startalignment[center]%
\doifsomethingelse{#1}
{There is an optional parameter: {\bf #1}\par}
{No optional parameter\par}
This is the mandatory text: {\em #2}
\stopalignment%
}
\starttext
</context>
==== Calling the macro from within command arguments (e.g. float title) ====
 
-- I have no deeper insight yet on the why and neither on which other cases this might apply to, but I hope it may be useful to someone running into errors.
 
If you wanted to call your macro from within an "argument" such as you would have to with titles or captions in floats:
 
<texcode>
\startplacefigure[title={We look at \mynewcommand{people} in floats}]
(content)
\stopplacefigure
</texcode>
 
The above will create a `"\doMyNewCommand doesn't match its definition"` error.
This can be solved by preceding the definition that takes the optional argument with `\unexpanded`:
 
<texcode>
\unexpanded\def\doMyNewCommand[#1]#2{% ... (etc.)
</texcode>
 
=== Comparison with LaTeX ===
 
On a final note, for comparative purposes: in LaTeX, a new command with an optional argument is defined with <code>\newcommand</code>.
 
<texcode>
\newcommand{\MyCommand}[2][World]{{#2Hello #1!}}
\MyCommand{\bfseries}
\MyCommand[Hans]{\scshape}
</texcode>
Reference:
http://archive.contextgarden.net/message/20101215.225603.cc903e62.en.html
[[Category:Inside ConTeXtProgramming and Databases]][[Category:Tools]]
57

edits