我想了解如何排版命令以用于 LaTeX 文档。澄清一下,不是使用 LaTeX 创建文档,而不是用 LaTeX 编写有关使用 LaTeX 的文档(如手册中所述)。据我所知,没有这个术语来区分 LaTeX 文档和使用 LaTeX 创建文档(不幸的是)。
pgfmanual-en-macros.tex 的第 1099-1121 行
https://www.ctan.org/pkg/pgf?lang=en
这段代码“看起来”像是删除了 at 符号,但我不知道。为什么这是必要的?它是如何工作的?
{
\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
inNewEnviron
不起作用)
\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}
是否\expandafter\mygobble\string\abc@def
首先将其转换\abc@def
为第 12 类字符的字符串(但@
如果在上下文中调用该宏,则后面出现的字母的类别代码为 11 \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”情况下会发生什么。
假设测试返回 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
,从而避免其类别代码出现问题(读取 LaTeX 辅助文件时设置为 11)。
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