![Como você escreve uma macro que aceita argumentos contendo parágrafos?](https://rvso.com/image/391694/Como%20voc%C3%AA%20escreve%20uma%20macro%20que%20aceita%20argumentos%20contendo%20par%C3%A1grafos%3F.png)
Estou tentando escrever uma macro que receba argumentos contendo parágrafos. Se você escrever uma macro normal e um de seus argumentos contiver um parágrafo, ela irá quebrar:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\def\mymacro#1{#1}
\mymacro{This
contains a paragraph}
\end{document}
Isso produz um erro:
Runaway argument? {This ! Paragraph ended before \mymacro was complete. <to be read again> \par l.15
Então tentei redefinir \par
para expandir os argumentos da macro, mas agora não para de compilar:
\documentclass{article}
\usepackage[utf8]{inputenc}
\title{test}
\begin{document}
\maketitle
\section{Introduction}
\gdef\oldpar{\par}
\def\mymacro{\gdef\par{}\mymacroi}
\def\mymacroi#1{#1\gdef\par{\oldpar}}
\mymacro{foo
bar}
\end{document}
Responder1
Na época em que o TeX foi escrito, uma página de um documento demorava vários minutos para ser processada, e o realce de sintaxe não era uma coisa, então era bom ter algum mecanismo para detectar se você esqueceu um arquivo }
. A \def
, por padrão, não permite um \par
token, a menos que você diga explicitamente que é um \long\def
:
\def\mymacro#1{#1}
O LaTeX, por outro lado, usa isso por padrão, então se você usar comandos LaTeX adequados ( \def
não devem ser usados em documentos LaTeX), \newcommand
cria um \long\def
por padrão. Se você quiser um “short”, \def
então você usa \newcommand*
.
xparse
retorna o argumento curto padrão, mas permite definir uma \long
macro usando o +
modificador de argumento:
\NewDocumentCommand\mymacro{ m}{#1}% \def
\NewDocumentCommand\mymacro{+m}{#1}% \long\def
Sua segunda tentativa é inteligente e poderia ter funcionado, exceto por duas coisas.
Primeiro é que você está usando \gdef\oldpar{\par}
e depois \gdef\par{\oldpar}
. Uma vez que vocêexpandir \par
você obtém \oldpar
o que, quando expandido, produz \par
o que, quando expandido, produz \oldpar
o que, quando expandido, produz \par
o que, quando expandido, produz \oldpar
... Correndo para sempre:/
Você precisa usar \let
(ou \global\let
para ter efeito global) neste caso: \let\oldpar\par
. Isso cria uma cópia exata \par
denamed \oldpar
que não depende de what is \par
.
Segundo, a verificação do argumento descontrolado é implementada em um nível inferior, independente da definição de \par
, portanto, isso falharia com o mesmo erro:
\let\par\relax
\def\mymacro#1{#1}
\mymacro{foo
bar}
porque quando o TeX vê dois \endlinechar
tokens (que é um espaço por padrão), o TeX insere um \par
token implícito, o que gera o Runaway argument
erro. Sabendo disso, então:
\newcount\oldELchar
\oldELchar=\endlinechar
\def\mymacro{\endlinechar=-1\relax\mymacroi}
\def\mymacroi#1{#1\endlinechar=\oldELchar}
\mymacro{foo
bar}
não gerará um erro, mas uma nova linha não será mais um espaço.
Responder2
O argumento de uma macro definida com \def
não permite \par
tokens. Também não permite linhas em branco, pois elas são transformadas \par
durante a fase em que o TeX processa a entrada de texto em tokens. Observe que a redefinição \par
é inútil a esse respeito, porque éprecisamenteo token \par
não permitido, independentemente do seu significado.
Solução: faça sua macro \long
.
\long\def\mymacro#1{#1}
Melhor solução:
\newcommand{\mymacro}[1]{#1}
porque \newcommand
usa \long\def
internamente. A variante \newcommand*
usa \def
sem o prefixo.