Linhas 1099-1121 do pgfmanual-en-macros.tex

Linhas 1099-1121 do pgfmanual-en-macros.tex

Estou tentando entender como os comandos são compostos para uso na documentação do LaTeX. Esclarecer,nãousar LaTeX para criar documentação, em vez de escrever documentação em LaTeX sobre o uso do LaTeX (como nos manuais). Até onde eu sei, não existe nenhum termo para distinguir a documentação do LaTeX da criação de documentação com o LaTeX (infelizmente).

Linhas 1099-1121 do pgfmanual-en-macros.tex

https://www.ctan.org/pkg/pgf?lang=en

Este código "parece" que remove sinais de arroba para mim, mas não sei. Por que isso é necessário? Como funciona?

{
  \makeatletter
  \global\let\myempty=\@empty
  \global\let\mygobble=\@gobble
  \catcode`\@=12
  \gdef\getridofats#1@#2\relax{%
    \def\getridtest{#2}%
    \ifx\getridtest\myempty%
      \expandafter\def\expandafter\strippedat\expandafter{\strippedat#1}
    \else%
      \expandafter\def\expandafter\strippedat\expandafter{\strippedat#1\protect\printanat}
      \getridofats#2\relax%
    \fi%
  }

  \gdef\removeats#1{%
    \let\strippedat\myempty%
    \edef\strippedtext{\stripcommand#1}%
    \expandafter\getridofats\strippedtext @\relax%
  }

  \gdef\stripcommand#1{\expandafter\mygobble\string#1}
}

Raciocínio

A razão pela qual eu gostaria de entender isso é porque parece que consigo digitar comandos com o código a seguir. Suspeito que há casos em que a minha ideia não funcionará.

Também existem limitações:

  • incluir comandos com argumentos de modo que eu possa digitá-los (em NewEnvironwith #1) como exemplo na explicação (por exemplo, \hello{input1} e depois usar #1no NewEnvironnão funcionaria)

\documentclass{article}
\usepackage{fontspec}
\usepackage{environ}
\NewEnviron{command}[1]{% 
\begin{minipage}[t]{.3\textwidth}
\texttt{\string#1}
\end{minipage}
\hfill
\begin{minipage}[t]{.7\textwidth}
\BODY
\end{minipage}
\xdef\putcommandexample{\BODY}% Set BODY to variable http://tex.stackexchange.com/a/14392/13552
}%
\begin{document}
\section{Friendly Commands}
\begin{command}{\hello}
This command greets the reader in a friendly manner.
\end{command}
\begin{command}{\goodbye}
This command greets the reader in a friendly manner.
\end{command}
\end{document}

Nota lateral para quem estiver interessado: Em vez de minipages também coloquei os comandos na margem usando o marginnotepacote. Parece tudo bem.

\NewEnviron{command}[1]{% 
\reversemarginpar\marginnote{\texttt{\string#1}}
\BODY
\par
}%

Saída

insira a descrição da imagem aqui

Responder1

A questão“por que é necessário?”exigiria a leitura de toda a fonte de documentação. Como funciona é fácil de ver.

A macro \getridofatsdecide se o que vem a seguir no fluxo de entrada \relaxcontém um código de categoria 12 @.

No entanto, é melhor ver como \removeatsfunciona para começar. Deve receber um nome de comando como seupreparadoargumento; primeiro de tudo, ele inicializa \strippedatcom uma lista de tokens vazia. Então acontece

\edef\strippedtext{\stripcommand#1}

que define \strippedtextuma string contendo o nome do comando com a barra invertida removida, porque isso faz

\expandafter\mygobble\string#1

Por exemplo, \removeats{\abc@def}isso \expandafter\mygobble\string\abc@defprimeiro se transforma \abc@defem uma sequência de caracteres da categoria 12 (mas o código de categoria 11 para letras que aparecem depois de @, se a macro for chamada em um \makeatothercontexto) e depois \mygobbleconsome a barra invertida.

Após esta preparação, \expandafter\getridofats\strippedtext @\relaxé chamado, que produz os seguintes tokens no fluxo de entrada:

\getridofats abc@def@\relax

Olhando para a definição de \getridofats, vemos que #1é abc, enquanto #2é def@. Se a chamada \removeats{\abcdef}tivesse sido vista, o fluxo de entrada conteria

\getridofats abcdef@\relax

e #1seria abcdef, enquanto #2estaria vazio.

A macro \getridtestestá definida para expandir para #2; no primeiro caso não está vazio, no segundo caso está.

Depois disso, \ifx\getridtest\myemptyretorna verdadeiro no segundo caso, falso no primeiro caso.

Suponha que o teste retorne verdadeiro (segundo caso). Então

\expandafter\def\expandafter\strippedat\expandafter{\strippedat abcdef}

é executado, que anexa #1(neste caso abcdef) ao valor anterior de \strippedat. Pode parecer inútil, porque \strippedatfoi inicializado vazio. Mas veremos mais tarde o que acontece no caso “falso”.

Suponha que o teste retorne falso (primeiro caso). Então

  \expandafter\def\expandafter\strippedat\expandafter{\strippedat abc\protect\printanat}%
  \getridofats def@\relax

está pronto: a primeira parte é anexada \strippedate \protect\printanata macro \getridofatsé chamada de volta para processar a parte final.

Não é uma macro particularmente bem escrita, na minha opinião. No entanto, as chamadas

\removeats\abcdef
\removeats\abc@def
\removeats\ab@cd@ef

resultar em \strippedatconter, respectivamente,

abcdef
abc\protect\printanat def
ab\protect\printanat cd\protect\printanat ef

onde \printanaté definido por

\def\printanat{\char`\@}

É claro \protectque definitivamente não é necessário, desde que a macro seja definida com \def\printanat{\char64 }, mas isso é uma escolha pessoal. Como a documentação é processada com LaTeX, provavelmente eu teria optado por

\DeclareRobustCommand{\printanat}{\char`\@ }

(observe o espaço à direita, é errado não tê-lo).

Aparentemente o mecanismo é utilizado para evitar a escrita @de caracteres no .auxarquivo evitando problemas com seu código de categoria (que é definido como 11 na leitura de arquivos auxiliares LaTeX).


expl3versão, a ser emitida em contexto onde @possua código de categoria 12.

\ExplSyntaxOn
\cs_new_protected:Npn \removeats #1
 {
  \tl_set:Nx \strippedat { \cs_to_str:N #1 }
  \tl_replace_all:Nnn \strippedat { @ } { \protect\printanat }
 }
\ExplSyntaxOff

informação relacionada