Строки 1099-1121 pgfmanual-en-macros.tex

Строки 1099-1121 pgfmanual-en-macros.tex

Я пытаюсь понять, как команды набираются для использования в документации LaTeX. Чтобы прояснить,нетиспользование LaTeX для создания документации, а не написание документации в LaTeX об использовании LaTeX (как в руководствах). Насколько мне известно, нет такого термина, чтобы отличить документацию LaTeX от создания документации с помощью LaTeX (к сожалению).

Строки 1099-1121 pgfmanual-en-macros.tex

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

Этот код "выглядит" как будто он удаляет знаки, но я не знаю. Зачем это нужно? Как это работает?

{
  \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}
}

Рассуждение

Причина, по которой я хотел бы это понять, заключается в том, что я, кажется, могу набирать команды с помощью следующего кода. Я подозреваю, что есть случаи, когда моя идея не будет работать.

Существуют также ограничения:

  • включить команды с аргументами, чтобы я мог набрать их (в NewEnvironwith #1) в качестве примера под объяснением (например, \hello{input1} и затем использовать #1в NewEnvironне будет работать)

\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}

Примечание для тех, кому интересно: Вместо minipages я также поместил команды на поля, используя marginnoteпакет. Выглядит нормально.

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

Выход

введите описание изображения здесь

решение1

Вопрос«зачем это нужно?»потребовалось бы прочитать всю документацию источника. Как это работает, легко увидеть.

Макрос \getridofatsрешает, содержит ли то, что следует за ним во входном потоке, \relaxкод категории 12 @.

Однако лучше \removeatsсначала посмотреть, как это работает. Он должен получить имя команды в качестве своегоукрепленныйаргумент; сначала он инициализируется \strippedatпустым списком токенов. Затем он делает

\edef\strippedtext{\stripcommand#1}

который устанавливает \strippedtextстроку, содержащую имя команды с удаленным обратным слешем, потому что это не так

\expandafter\mygobble\string#1

Например, сначала преобразуется \removeats{\abc@def}в строку символов категории 12 (но код категории 11 для букв, появляющихся после , если макрос вызывается в контексте), а затем поглощает обратную косую черту.\expandafter\mygobble\string\abc@def\abc@def@\makeatother\mygobble

После этой подготовки \expandafter\getridofats\strippedtext @\relaxвызывается , который создает следующие токены во входном потоке:

\getridofats abc@def@\relax

Глядя на определение \getridofats, мы видим, что #1есть abc, в то время как #2есть def@. Если бы вызов \removeats{\abcdef}был виден, входной поток содержал бы

\getridofats abcdef@\relax

и #1будет abcdef, в то время как #2будет пустым.

Макрос \getridtestопределен так, чтобы расширяться до #2; в первом случае он не пустой, во втором — пустой.

После этого \ifx\getridtest\myemptyвозвращает true во втором случае, false в первом случае.

Предположим, что тест возвращает true (второй случай). Тогда

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

выполняется, что добавляет #1(в данном случае abcdef) к предыдущему значению \strippedat. Это может показаться бесполезным, поскольку \strippedatбыло инициализировано пустым. Но позже мы увидим, что происходит в случае «ложь».

Предположим, что тест возвращает false (первый случай). Тогда

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

выполняется: первая часть добавляется к \strippedat, затем \protect\printanatмакрос \getridofatsвызывается обратно для обработки последней части.

Не очень хорошо написанный макрос, на мой взгляд. Однако вызовы

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

результат в том, \strippedatчтобы содержать, соответственно,

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

где \printanatопределяется как

\def\printanat{\char`\@}

Конечно, \protectэто определенно не нужно, если макрос определен с помощью \def\printanat{\char64 }, но это личный выбор. Поскольку документация обрабатывается с помощью LaTeX, я бы, вероятно, выбрал

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

(обратите внимание на пробел в конце, его отсутствие неправильно).

По-видимому, этот механизм используется для того, чтобы избежать записи @символов в .auxфайл, тем самым избегая проблем с его кодом категории (который устанавливается равным 11 при чтении вспомогательных файлов LaTeX).


expl3версия, которая будет выпущена в контексте, где @имеет код категории 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

Связанный контент