Líneas 1099-1121 del pgfmanual-en-macros.tex

Líneas 1099-1121 del pgfmanual-en-macros.tex

Estoy tratando de entender cómo se componen los comandos para su uso en la documentación de LaTeX. Para aclarar,nousar LaTeX para crear documentación, en lugar de escribir documentación en LaTeX sobre el uso de LaTeX (como en los manuales). Hasta donde yo sé, no existe ningún término para distinguir la documentación de LaTeX de la creación de documentación con LaTeX (desafortunadamente).

Líneas 1099-1121 del pgfmanual-en-macros.tex

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

Este código "parece" que me elimina las señales, pero no lo sé. ¿Por qué es esto necesario? ¿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}
}

Razonamiento

La razón por la que me gustaría entender esto es porque parece que puedo escribir comandos con el siguiente código. Sospecho que hay casos en los que mi idea no funcionará.

También existen limitaciones:

  • incluir comandos con argumentos de modo que pueda escribirlos (con NewEnviron) #1como ejemplo bajo la explicación (por ejemplo, \hello{input1} y luego usarlos #1en NewEnvironno funcionaría)

\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 al margen para cualquiera interesado: en lugar de minipages, también pongo los comandos en el margen usando el marginnotepaquete. Se ve bien.

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

Producción

ingrese la descripción de la imagen aquí

Respuesta1

La pregunta"¿Por qué es necesario?"Requeriría leer toda la fuente de documentación. Cómo funciona es fácil de ver.

La macro \getridofatsdecide si lo que le sigue en el flujo de entrada hasta \relaxcontiene un código de categoría 12 @.

Sin embargo, es mejor ver cómo \removeatsfunciona para empezar. Debería recibir un nombre de comando como suapuntaladoargumento; En primer lugar, se inicializa \strippedaten una lista de tokens vacía. entonces lo hace

\edef\strippedtext{\stripcommand#1}

que se establece \strippedtexten una cadena que contiene el nombre del comando sin la barra invertida, porque no

\expandafter\mygobble\string#1

Por ejemplo, \removeats{\abc@def}eso \expandafter\mygobble\string\abc@defprimero se transforma \abc@defen una cadena de categoría 12 caracteres (pero código de categoría 11 para las letras que aparecen después de @, si la macro se llama en un \makeatothercontexto) y luego \mygobblese come la barra invertida.

Después de esta preparación, \expandafter\getridofats\strippedtext @\relaxse llama, lo que produce los siguientes tokens en el flujo de entrada:

\getridofats abc@def@\relax

Mirando la definición de \getridofats, vemos que #1es abc, mientras que #2es def@. Si \removeats{\abcdef}se hubiera visto la llamada, el flujo de entrada contendría

\getridofats abcdef@\relax

y #1sería abcdef, mientras #2estaría vacío.

La macro \getridtestestá definida para expandirse a #2; en el primer caso no está vacío, en el segundo caso sí.

Después de esto, \ifx\getridtest\myemptydevuelve verdadero en el segundo caso y falso en el primero.

Supongamos que la prueba es verdadera (segundo caso). Entonces

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

se realiza, que se suma #1(en este caso abcdef) al valor anterior de \strippedat. Podría parecer inútil porque \strippedatse había inicializado para que estuviera vacío. Pero veremos más adelante qué sucede en el caso “falso”.

Supongamos que la prueba arroja falso (primer caso). Entonces

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

Está hecho: se agrega la primera parte y \strippedatluego se vuelve a llamar \protect\printanata la macro \getridofatspara procesar el fragmento final.

En mi opinión, no es una macro particularmente bien escrita. Sin embargo, las llamadas

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

resultan en \strippedatcontener, respectivamente,

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

donde \printanatestá definido por

\def\printanat{\char`\@}

Por supuesto, \protectdefinitivamente no es necesario siempre que la macro esté definida con \def\printanat{\char64 }, pero es una elección personal. Como la documentación se procesa con LaTeX, probablemente habría optado por

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

(tenga en cuenta el espacio final, está mal no tenerlo).

Aparentemente el mecanismo se utiliza para evitar escribir @caracteres en el .auxarchivo y así evitar problemas con su código de categoría (que se establece en 11 al leer archivos auxiliares de LaTeX).


expl3versión, que se emitirá en un contexto donde @tenga el código de categoría 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

información relacionada