10

I am trying to use TikZ together with a macro that I defined via \NewDocumentCommand (for multiple optional arguments), but it doesn't behave as expected. TikZ is giving up on the path instead of working with the macro expansion.

Minimal example:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{positioning}

\NewDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}

\begin{document}
% This works
\begin{tikzpicture}
  \node (test1) {test1};
  \node (test2) [right=of test1] {test2} edge [] node [auto] {test3} (test1);
\end{tikzpicture}

% This does not
\begin{tikzpicture}
  \node (test1) {test1};
  \node (test2) [right=of test1] {test2} \myEdge{test3} (test1);
\end{tikzpicture}
\end{document}

Output:

! Package tikz Error: Giving up on this path. Did you forget a semicolon?.

See the tikz package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.19 ...e (test2) [right=of test1] {test2} \myEdge
                                                  {test3} (test1);

Edit: The answer given by @Werner works beautifully when only using the macro with the required argument, or not using it more than once per path. But the following example still fails:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{positioning}

\DeclareExpandableDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}
\begin{document}
% This works
\begin{tikzpicture}
  \node (node1) {node1};
  \node (node2) [right=of node1] {node2};
  \node (node3) [right=of node2] {node3} edge [bend left] node [right] {edge1} (node2) edge [] node [auto] {edge2} (node1);
\end{tikzpicture}

% This does not
\begin{tikzpicture}
  \node (node1) {node1};
  \node (node2) [right=of node1] {node2};
  \node (node3) [right=of node2] {node3} \myEdge[bend left][right]{edge1} (node2) \myEdge{edge2} (node1);
\end{tikzpicture}
\end{document}

The error:

! Package tikz Error: Giving up on this path. Did you forget a semicolon?.

See the tikz package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.19 ...left][right]{edge1} (node2) \myEdge{edge2}
                                                   (node1);

I feel like I am missing some fundamental understanding of how either xparse generates those macros, or how TikZ parses the path.

1
  • If you place your last nonworking line replacing the dots \edef\temp{\noexpand....}\temp it works and shows that it is still an expansion issue.
    – percusse
    Commented Oct 30, 2012 at 7:53

1 Answer 1

7

The desired output is achieved using \DeclareExpandableDocumentCommand:

\DeclareExpandableDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}

As mentioned, this is only a partial solution since it only works sometimes, maybe. The requirement that the command be expandable stems from the fact that tikz is building a path on-the-go, and therefore scans your input, assembling it into pieces. If it finds a piece in the path generation it doesn't understand, it assumes you should have actually closed the path (with a trailing ;). So, since \myEdge isn't part of the tikz path lingo, it has a problem interpreting it. This is a typical expansion issue.

1
  • 1
    Not part of the initial question, but: Is there a different, less fragile way to do this then? And thanks for the answer :-)
    – dominikh
    Commented Oct 30, 2012 at 12:38

You must log in to answer this question.

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