4

Given this MWE:

\documentclass[12pt]{report}
\usepackage{fontspec}

\setlength{\parindent}{0pt}
\NewDocumentCommand{\testone}{m m m }{%
    \if\relax\detokenize{#2}\relax
        \textbf{#1}\dotfill#3\\%
    \else
        \textbf{#1}\dotfill(#2)#3\\%
    \fi
}
\NewDocumentCommand{\testtwo}{m O{} m }{%
    \if\relax\detokenize{#2}\relax
        \textbf{#1}\dotfill#3\\%
    \else
        \textbf{#1}\dotfill(#2)#3\\%
    \fi
}

\begin{document}
\testone{ach}{ch as in loch}{,but}
\testone{aig}{}{(ek), at}
\testtwo{ach}{ch as in loch}{,but}
\testtwo{aig}{(ek), at}
\end{document}

Which results in:

ach . . . . . . . . . . . . . . . . . . . . . . . . . . . . (ch as in loch),but

aig . . . . . . . . . . . . . . . . . . . .  . . . . . . . . . . . . . (ek), at

ach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ch as in loch

,but aig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . (ek), at

I am confused as to why the optional parameter version seems to fail with a newline inserted which messes up the next line. My test for an empty parameter seems to work in the first version but not in the second, where the default of {} doesn't seem to be empty.

1
  • Please, revert the green tick to Teepeemm
    – egreg
    Commented Jun 17 at 21:13

2 Answers 2

4

In LaTeX, optional arguments are denoted with []. This means that your code is being parsed as

\testtwo{ach}[]{ch as in loch}{,but}
\testtwo{aig}[]{(ek), at}

and the first line becomes

-> \testtwo{ach}[]{ch as in loch},but
-> \textbf{ach}\dotfill ch as in loch\\,but

Instead, you want \testtwo{ach}[ch as in loch]{,but}

From a programming perspective, things are a bit simpler if you can move common code out of a conditional. So you can move the \textbf{#1}\dotfill before the \if, and the #3\\ after the conditional ends. You can also use \IfBlankTF{#2}{}{(#2)} instead of the \detokenize magic. And since the T branch is now doing nothing, we can trim this down to \IfBlankF{#2}{(#2)}, so that \testtwo is \textbf{#1}\dotfill\IfBlankF{#2}{(#2)}#3\\%

8
  • Nicely stated! I love code that shrinks down to almost nothing. In my defense, this started out as a one-liner that didn't work. There's no way that I can just use two braces if I've nothing for the second parameter I take it?
    – hsmyers
    Commented Jun 17 at 20:33
  • There is also the o argument specifier that will probably be better in this application.
    – egreg
    Commented Jun 17 at 20:34
  • @hsmyers If by braces you mean {}, then no. {} are for mandatory arguments (otherwise, how would TeX know whether the {} are present or not, since it can't tell if you add extra {} at the end?). {} and an optional argument are not interchangeable. And to elaborate on egreg's point, O{default} uses default if nothing is given. Since your default is blank, you can change O{} to o, which uses a blank default.
    – Teepeemm
    Commented Jun 17 at 20:43
  • The \textbf{#1}\dotfill\IfBlankF{#2}{(#2)}#3\\% unfortunately doesn't work (under xelatex). @egreg, what is the syntax for small 'o'?
    – hsmyers
    Commented Jun 17 at 20:43
  • @Teepeemm o is not equivalent to O{}. o uses a specially constructed marker that prints as -NoValue-, but can nicely be tested for with \IfNoValueTF or \IfValueTF.
    – Skillmon
    Commented Jun 17 at 20:47
4

Teepeemm's answer is up to the point and deserves all credits.

I'd like to extend it by showing better xparse methods for this application.

Regarding \testtwo, you seem to want to add #2 in parentheses if given. The code should not use the legacy \if\relax\detokenize{#2}\relax test, but the better ones provided by xparse (now included in the kernel).

\NewDocumentCommand{\testtwo}{mom}{%
  \par\noindent
  \textbf{#1}\dotfill
  \IfValueT{#2}{(#2)}%
  #3\par
}

Full test.

\documentclass[twocolumn]{article}

\NewDocumentCommand{\testtwo}{mom}{%
  \par\noindent
  \textbf{#1}\dotfill
  \IfValueT{#2}{(#2)}%
  #3\par
}

\begin{document}

\testtwo{ach}[ch as in loch]{, but}
\testtwo{aig}[ek]{, at}
\testtwo{AAA}{BBB}

\end{document}

Don't use \\ to break lines. The twocolumn option is used just to make a smaller picture.

See texdoc usrguide for full information about features for \NewDocumentCommand.

enter image description here

0

You must log in to answer this question.

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