
Я пытаюсь понять, как команды набираются для использования в документации 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}
}
Рассуждение
Причина, по которой я хотел бы это понять, заключается в том, что я, кажется, могу набирать команды с помощью следующего кода. Я подозреваю, что есть случаи, когда моя идея не будет работать.
Существуют также ограничения:
- включить команды с аргументами, чтобы я мог набрать их (в
NewEnviron
with#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}
Примечание для тех, кому интересно: Вместо minipage
s я также поместил команды на поля, используя 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