13

I'm trying to build my own cookbook-style, which has an ingredient makro. Sometimes the ingredients should be separated and have a headline, so I tried with an optional argument. A minimum example looks like this:

\documentclass{scrartcl}
\newcommand{\ingredient}[3][]{
    #1 #2 & #3 \\
}
\begin{document}
    \begin{tabular}{r|l}        
        \ingredient[\multicolumn{2}{l}{Head} \\]{test1}{test2}
        \ingredient[test3]{test4}{test5}
        \ingredient{test6}{test7}
    \end{tabular}
\end{document}

What's wrong with this code? I get the following error message:

! Misplaced \omit.
\multispan ->\omit 
                   \@multispan 
l.7 ...[\multicolumn{2}{l}{Head} \\]{test1}{test2}
0

3 Answers 3

16

Tabular material is really picky about what is allowed to go "before" a line. In particular, it has to be fully expandable.

Hence, even the assignment which \ingredient needs to do to check for its optional argument is enough to start the line, and then \multicolumn is no longer allowed to appear.

The easiest way to remedy this is to make the first argument of \ingredient mandatory:

\documentclass{scrartcl}
\newcommand{\ingredient}[3]{
    #1 #2 & #3 \\
}
\begin{document}
    \begin{tabular}{r|l}        
        \ingredient{\multicolumn{2}{l}{Head} \\}{test1}{test2}
        \ingredient{test3}{test4}{test5}
        \ingredient{}{test6}{test7}
    \end{tabular}
\end{document}
3
  • Thank you for a working example, but as this "headline" is really seldomly used it would be much more convenient to have it as an optional parameter. Is there no way to make it work as an optional parameter? Ideally I could also get rid of the "\multicolum{2}{1}{VARIABLE} \\"-stuff. Commented Aug 31, 2012 at 21:34
  • 1
    Nope. You could make two commands, one with two and one with three arguments. Commented Aug 31, 2012 at 21:36
  • Thank you. I found a solution by adding a new command just like you proposed. Commented Aug 31, 2012 at 21:48
10

You can retain your original syntax and have a single macro with an optional parameter if you use \DeclareExpandableDocumentCommand from the xparse package.

Code:

\documentclass{scrartcl}
\usepackage{xparse}

\DeclareExpandableDocumentCommand{\ingredient}{O{} m m}{%
    #1 #2 & #3 \\%
}%

\begin{document}
    \begin{tabular}{r|l}        
        \ingredient[\multicolumn{2}{l}{Head} \\]{test1}{test2}
        \ingredient[test3]{test4}{test5}
        \ingredient{test6}{test7}
    \end{tabular}
\end{document}
0

You can "creatively" use noalign to implement the functionality. In the following code, I define a function \NewDocumentCommandOptionalInTabular that works similar to that of \NewDocumentCommand except that you can use optional argument (or star) as you want.

\documentclass{scrartcl}

% ======== copy paste this part ========
\ExplSyntaxOn
\cs_new_protected:Npn \NewDocumentCommandOptionalInTabular #1 #2 #3 {
  \NewDocumentCommandOptionalInTabular_aux:xnnn {\exp_not:c{\cs_to_str:N #1-aux}} #1 {#2} {#3}
}

\cs_new_protected:Npn \NewDocumentCommandOptionalInTabular_aux:nnnn #1 #2 #3 #4 {
  \cs_new:Npn #2 { \noalign \bgroup #1 }
  \NewDocumentCommand #1 {#3} { \egroup #4 }
}
\cs_generate_variant:Nn \NewDocumentCommandOptionalInTabular_aux:nnnn {x}
\ExplSyntaxOff
% ======== end ========


% then you can just use \NewDocumentCommandOptionalInTabular to replace \NewDocumentCommand
\NewDocumentCommandOptionalInTabular \ingredient {O{} m m}{
    #1 #2 & #3 \\
}

\begin{document}
    \begin{tabular}{r|l}        
        \ingredient[\multicolumn{2}{l}{Head} \\]{test1}{test2}
        \ingredient[test3]{test4}{test5}
        \ingredient{test6}{test7}
    \end{tabular}
\end{document}

Inspired by egreg's answer.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .