Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

For example, I would to write \defpoint [option] (1,2) {A} instead of \defpoint[option](1,2){A}. What is the best way to build this kind of macro?

Only the argument [...] is optional and if spaces are allowed between between arguments, spaces are not required (obligatory ?).

And if the user made a syntax error, It might be interesting to note it, how do here?

share|improve this question
    
It might be handy to specify if you require spaces between arguments or only want to allow them. As the answers already posted show, the two things are slightly different. Also, is the (...) argument optional? –  Joseph Wright Dec 30 '11 at 8:58
    
I want only to allow spaces between arguments and only the argument [..] is optional. –  Alain Matthes Dec 30 '11 at 9:15
add comment

3 Answers

up vote 8 down vote accepted

Using the standard LaTeX2e method this works with no additional effort:

\makeatletter
\long\def\defpoint{%
  \@ifnextchar[%]
    {\defpoint@aux@i}
    {\defpoint@aux@i[]}%
}
\long\def\defpoint@aux@i[#1]{%
  \@ifnextchar(%)
    {\defpoint@aux@ii{#1}}
    {\ERROR}% As the ( ... ) part is not optional
}
\long\def\defpoint@aux@ii#1(#2)#3{\showtokens{#1:#2:#3}}
\makeatother
\defpoint [option] (1,2) {A}

This works for three different reasons for the three arguments!

For the first argument (in square brackets), TeX is skipping spaces after a control sequence and there is nothing that the programmer can do: spaces will always be allowed here (ignoring rather awkward catcode tricks).

For the optional argument in parentheses, \@ifnextchar deliberately skips any spaces it picks up, and so ignores any between ] and (. It is possible to create a version of \@ifnextchar which does not skip spaces (indeed, this would be easier that the current implementation). Note that if the [...] argument is not there then TeX is going to skip the spaces after \defpoint anyway.

Finally, grabbing the mandatory argument in the standard way again uses TeX's logic. With no additional precautions, #3 here will be grabbed as the next <balanced text>, which can be seen more simply with something like

\def\test#1#2#3{\showtokens{#1:#2:#3}}
\test {A} {B} {C}
share|improve this answer
    
What of your favorite pgfkeys solution: \pgfkeys{/alter/mundus/.code args={ (#2) #3 }{#1#2#3}}? This allows him to use keys instead of parameters. [#1] may be read as n aoptional argument. Also, he could try command keys. –  Ahmed Musa Dec 30 '11 at 10:27
add comment

xparse allows this by default. See section 1.2 Spacing and optional arguments of the xparse documentation:

TeX will find the first argument after a function name irrespective of any intervening spaces. This is true for both mandatory and optional arguments.

Barring some specific argument formatting, here is a minimal example:

enter image description here

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\NewDocumentCommand{\mycmd}{o d() m}{%
  1: #1; 2: #2; 3: #3
}
\begin{document}
\mycmd[abc](ijk){xyz} \par
\mycmd [abc](ijk){xyz} \par
\mycmd[abc] (ijk){xyz} \par
\mycmd[abc](ijk) {xyz} \par
\mycmd  [abc] (ijk){xyz} \par
\mycmd[abc](ijk)    {xyz} \par
\mycmd[abc]         (ijk){xyz}
\end{document}

Syntax errors can be performed on the arguments via boolean tests using, for example, \IfNoValueTF.

share|improve this answer
1  
We've had discussions about mandatory (...) arguments. At the moment, the way we deal with this is just to use an \IfNoValueTF test, as you suggest. It would not be too hard to add a mandatory-bracketed argument form: perhaps b? –  Joseph Wright Dec 30 '11 at 9:35
    
Why not allow the freedom for mandatory argument delimiters than currently exist with optional ones? –  Werner Dec 30 '11 at 16:39
1  
For mandatory arguments, the usual approach is to pick up TeX <balanced text>. xparse is about creating LaTeX2e-like interfaces, and so it is reasonable to stick with the convention of mandatory argument => {...}. There's also the more technical question of how you'd specify a mandatory argument with variable delimiters, as you can't pick up {} as two arguments (easily). We certainly could add something, probably most easily using the existing D-type code and adding a wrapper around the \IfNoValue test. However, it's a question of how many real use cases there are. –  Joseph Wright Dec 30 '11 at 16:56
1  
(ctd.) For example, you can imagine using M for this, with something like \NewDocumentCommand\foo{oM()m} for the case in hand. One for LaTeX-L if it seems useful. (Not sure I like using M here as the pattern for the other cases is capital letter => default given. So we'd need a good choice of letter. At one stage, we did have c for 'co-ordinate pair', but that again is not general.) –  Joseph Wright Dec 30 '11 at 16:58
    
@JosephWright: It all sounds promising! I guess the use case would vary, since most users are familiar with optional [ ] and mandatory { } delimiters. I know pstricks code, for sure, is filled with optional and mandatory ( ) code, while titlesec contains a mandatory [ ]. –  Werner Dec 30 '11 at 17:18
show 1 more comment

In addition to the other answers, I'd like to point out that using LaTeX's standard macro definition mechanism, you can prepare the option without having to pass the remaining arguments to the helper macro \defpoint@option.

The macro \defpoint doesn't consume the next tokens and leaves them on the input stream. It simply adds the default option at the start of the token stream if there is no option, and then calls \defpoint@option, which consumes all arguments.

\makeatletter
\newcommand\defpoint[1][option]{%
    \defpoint@option[#1]% partial application
}
\def\defpoint@option[#1](#2,#3) #4{% There _has_ to be a space before #4
    Look ma: #1, #2, #3, and #4.
}
\makeatother

\defpoint(1,2) {A}
\defpoint[blah](1,2) {A}
\defpoint(1,2){A} % doesn't work
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.