3

For some reasons, \NewDocumentCommand from xparse package other than \newcommand from Latex has to be used to construct my macro. Yet I find in some situations blank lines in arguments of my macro will lead to failure of compile. The following link gives explanation: blank lines break xparse or ifthen macro

However, my example code below still fail to compile. Why?

\documentclass{article}
\usepackage{xparse}
\usepackage[most]{tcolorbox}

    \begin{document}

    \NewDocumentCommand{\mycmd}{+O{}m}{% notice "+O{}"
      \begin{tcbitemize}[#1]
        #2
      \end{tcbitemize}
    }
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    \mycmd[
    colback=yellow,

    coltext=red
    ]
    {\tcbitem some text}

    \end{document}
  • Welcome to TeX.SX! The problem hass nothing to do with xparse: you get the same problem if you have a blank line in the optional argument to tcbitemize because such optional arguments do not accept blank lines. – Andrew Nov 1 '18 at 1:28
  • "Long" macros allow multiple paragraphs (blank lines), and are produced using \newcommand or \long\def. "Normal" macros do NOT allow multiple paragraphs in their arguments, and are produced using \newcommand* or \def. – John Kormylo Nov 1 '18 at 2:19
  • For my example, is there a solution? – lyl Nov 1 '18 at 2:36
  • 1
    @lyl Not using blank lines in key-value specifications is the solution. – egreg Nov 1 '18 at 11:34
5

The problem, as Andrew said in the comment, is not your \mycmd, but it's deeper down in PGF's key parser. The problem is reported in the \pgfkeys@addpath macro.

The first, and trivial alternative, is to remove the blank line. A paragraph break doesn't make much sense in that context. And if you want a visual separation between keys you can always comment the line end:

\mycmd[
colback=yellow,
% <- here
coltext=red
]

The second alternative could be to redefine \pgfkeys@addpath to make it long. Spoiler alert: another macro will probably complain shortly after because the \par token will be passed on through the key-value parser. But suppose you manage to make all (!) these macros \long. Then the parser would, eventually, see a key-value pair like this: \par coltext=red. The parser is coded such that it trims spaces around the keys, but \par is not a space, so at the very least you would have to rewrite some of the parser to make it remove \par tokens as well.

If we're removing \par tokens, then we can go straight to the third alternative, which is to remove them much earlier:

\documentclass{article}
\usepackage{xparse}
\usepackage[most]{tcolorbox}

\begin{document}

\ExplSyntaxOn
\tl_new:N \LylTmpaTl
\cs_new:Npn \StripPar #1 #2
  {
    \tl_set:Nn #1 { #2 }
    \tl_remove_all:Nn #1 { \par }
  }
\ExplSyntaxOff

\NewDocumentCommand{\mycmd}{+O{}m}{% notice "+O{}"
  \StripPar\LylTmpaTl{#1}% Removing ALL \par tokens
  % Trick to expand \LylTmpaTl once
  \begingroup\edef\x{\endgroup\noexpand
  \begin{tcbitemize}[\unexpanded\expandafter{\LylTmpaTl}]}\x
    #2
  \end{tcbitemize}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\mycmd[
colback=yellow,

coltext=red
]
{\tcbitem some text}

\end{document}

This method will remove all par tokens from the option list. Even the ones you don't want to be removed, but it's the price you have to pay. If you happen to want a \par token somewhere in the value to a key you'd have to use \endgraf instead.

2

The internal macros of TikZ/PGF that control key-value assignments don't allow for \par tokens and it's a good thing™ they don't.

Your input

colback=yellow,

coltext=red

is completely equivalent to

colback=yellow,\par coltext=red

and obviously there is no \par coltext key. In order to avoid the issue, the macros are explicitly defined as not long, so not allowing \par in their argument.

Recall that TeX automatically transforms a blank line into a \par token at the time input is read in.

The fact you marked the optional argument as long (with +) doesn't “remove” the wrong \par token, it just allows to accept it at argument absorbing time. But then the argument is passed to other macros that should be able to accept it: well, they can't accept it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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