下面是一个简短的程序,可以使用\meaning
和 \string
让 LaTeX 和 TeX 命令组合打印出宏列表。不出所料(TeX 再也不会让我感到惊讶了),该命令还可以列出自己的列表。
\makeatletter
\parindent0pt
\def\reflect{\@star@or@long\accommand}
\fboxrule=0.0pt
\def\accommand#1{\framebox[4cm][l]{\color{red}
{\tt\string#1:}} %
\parbox[t]{7cm}{\tt\expandafter\strip@prefix\meaning#1}}
\reflect{\reflect}\\
\reflect{\listoffigures}\\
\reflect{\section}\\
\reflect*{\thispagestyle}\\
\makeatother
我正在考虑把它变成一个包,这样就可以说
\reflect{command1, command2, command3}
并获得控制序列的列表。我是否重复了您知道的任何包?除了上述方法之外还有其他方法吗?例如,代码在数学模式下失败\reflect{\gamma}
。
答案1
编辑:几周前,我写了这个“答案”,希望能有比 Yiannis 更强大的东西,即能够逐步执行 LaTeX 文件。我有一个原型。请参阅本文底部的完整代码。
编辑 2、3、4:改进了代码。
我不确定这是否应该是一个答案,但对于评论来说它肯定太长了。
如果我可以输入并看到宏的解开,我会觉得很简洁\unravel{\section*{title}}
:首先,展开一次,然后展开第一个宏一次并向我显示结果标记列表,然后按照 TeX 执行的顺序继续展开,直到需要在作为参数给出的标记列表之后读取一些内容\unravel
。
例如,\unravel{\section*}
应该给予
\@startsection {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus
-.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }*
注意末尾的星号。然后它应该给出
\if@noskipsec \leavevmode \fi \par \@tempskipa -3.5ex \@plus -1ex
\@minus -.2ex\relax \@afterindenttrue \ifdim \@tempskipa <\z@
\@tempskipa -\@tempskipa \@afterindentfalse \fi \if@nobreak
\everypar {}\else \addpenalty \@secpenalty \addvspace \@tempskipa
\fi \@ifstar {
\@ssect {\z@ }{-3.5ex \@plus -1ex \@minus -.2ex}{2.3ex \@plus
.2ex}{\normalfont \Large \bfseries }
}{
\@dblarg {\@sect {section}{1}{\z@ }{-3.5ex \@plus -1ex \@minus
-.2ex}{2.3ex \@plus .2ex}{\normalfont \Large \bfseries }}
}*
等等。如果能够跳过某些命令的扩展就好了:如果我已经非常清楚该做什么\@sect
,我应该能够愉快地执行扩展的几个步骤。
编辑(续):抱歉,代码太大了(而且有 bug)。我尝试添加一些注释。最后,你只需要写代码
\debug@unravel{\textrm{Hello}}
就能看到 TeX 是如何工作的。
\documentclass{article}
\usepackage{trace}
\makeatletter
% Storing a few primitives that we use, to avoid crashes if they are
% redefined by the user. [...]
% =========== Setup.
% "todo": tokens that are going to be read, expanded, etc.
% "modifiers": a place to save modifiers (so far, only "\global")
% "done": the output, which in the best possible world would contain
% tokens that produce the same output as the original ones.
\newtoks\debug@toks@todo
\long\xdef\debug@modifiers@tl{}
\newtoks\debug@toks@done
\long\gdef\debug@afterassignment@token{}
\long\gdef\debug@toks@done@append#1{%
\global\debug@toks@done\expandafter{\the\debug@toks@done#1}%
}
% Various scratch objects.
\newcount\debug@tmp@count
\newskip\debug@tmp@skip
\newbox\debug@tmp@box
% A few parameters to control display:
\newcounter{debug@output@stream} \setcounter{debug@output@stream}{16}
\newcounter{debug@prompt@stream} \setcounter{debug@prompt@stream}{-1}
\newcounter{debug@noise} \setcounter{debug@noise}{1}
\newcounter{debug@steps} \setcounter{debug@steps}{0}
\newcounter{debug@nonstop} \setcounter{debug@nonstop}{1}
% Spaces make \debug@unravel{...} choke!
%
% Explicit braces which start a group (rather than the argument
% of a macro) are not yet implemented.
%
% \noexpand, \afterassignments, \aftergroup,
% \unhbox, \unvbox, \unhcopy, \unvcopy,
% \write,
% ...
% need to be implemented
% The main command, \debug@unravel, simply sets the toks \debug@toks@todo,
% and repeatedly does one step of the expansion until we reach the
% end of the list.
\long\gdef\debug@unravel#1{%
\debug@print@welcome%
%
\global\debug@toks@todo{#1}%
\global\debug@toks@done{}%
\global\let\debug@head\relax%
%
\loop%
\debug@set@to@head\debug@head\debug@toks@todo%
\unless\ifx\debug@head\debug@qstop%
\debug@step%
\repeat%
%
\debug@print@outcome%
}
\long\gdef\debug@insurance#1{%
\begingroup\escapechar=`\\\relax%`
#1%
\endgroup%
}
\long\gdef\debug@step{%
%
% Then, in a safe environment (\escapechar=92),
% - analyse the token,
% - print the token list
% - print/show the first token
% - figure out whether we should be using \debug@type or @iv
% - prepare the message on what we will be doing
\debug@insurance{%
\debug@type@from@meaning\debug@head%
\debug@print@done%
\debug@print@todo%
\debug@print@first%
\debug@prompt%
\debug@type@find@correct%
\debug@setup@print@wedid%
}%
%
% Finally, do what we should do.
\csname debug@do@\debug@type@correct\endcsname%
\debug@print@wedid% auto-insured
}
\long\gdef\debug@type@find@correct{%
\@ifundefined{debug@do@\debug@type}{%
\@ifundefined{debug@do@\debug@type@iv}{%
\debug@read@unsafe{1}%
\debug@typeout{Warning: Unknown token \debug@solid@name.}%
\debug@typeout{\@spaces Input code to insert here. Or press return to proceed:}%
\debug@typeout{\@spaces this dumps \debug@solid@name into the output,}%
\debug@typeout{\@spaces by inserting \noexpand\debug@primitive{\debug@type}{unsupp}}%
\debug@prompt@{\debug@type@find@correct@ifempty}%
\debug@type@find@correct%
}{%
\global\let\debug@type@correct\debug@type@iv%
}%
}{%
\global\let\debug@type@correct\debug@type%
}%
}
\long\gdef\debug@type@find@correct@ifempty#1{%
\ifx\debug@empty@short#1%
\debug@primitive{\debug@type}{unsupp}%
\fi
#1}
% short, not long!
\gdef\debug@empty@short{}
\long\gdef\debug@empty@long{}
% ========== Macros to read the beginning of \debug@toks@todo.
\long\gdef\debug@qstop{\debug@qstop}
\global\let\debug@varqstop\debug@qstop
\long\gdef\debug@to@stop#1\debug@qstop{}
\long\gdef\debug@to@stop@keep#1\debug@qstop{#1}
\long\gdef\debug@set@to@head#1#2{%
\expandafter\futurelet\expandafter#1%
\expandafter\debug@to@stop\the#2\debug@qstop}
% ==== below, "unsafe" means we do not check for explicit braces or #.
% \debug@read@unsafe{3} reads the 3 first (at least 1) tokens of
% \debug@toks@todo and stores them in \debug@read@x.
\newcount\debug@read@count%
%
\long\gdef\debug@read@unsafe#1{%
\debug@read@count #1\relax%
\long\gdef\debug@read@x{}%
\expandafter\debug@read@unsafe@aux\the\debug@toks@todo%
\debug@varqstop\debug@qstop%
}
\long\gdef\debug@read@unsafe@aux#1{%
\expandafter\long\expandafter\gdef%
\expandafter\debug@read@x\expandafter{\debug@read@x#1}%
\advance \debug@read@count by \m@ne%
\ifnum\debug@read@count>0\relax%
\expandafter\debug@read@unsafe@aux%
\else%
\expandafter\debug@to@stop%
\fi%
}
% ========== Macros to understand the meaning of the head.
\long\gdef\debug@type@from@meaning#1{%
\expandafter\debug@meaning@aux\meaning#1 \debug@qstop%
\expandafter\debug@tfm@macro\meaning#1->\debug@qstop%
\long\xdef\debug@type@iv{%
\expandafter\debug@type@nondigits\debug@type\debug@qstop}%
}
\long\gdef\debug@tfm@macro#1->#2\debug@qstop{%
\ifx\debug@qstop#2\debug@qstop%
\else%
\long\gdef\debug@type{macro}%
\fi}
\begingroup
\lccode`\*`\\
\lowercase{%
\endgroup%
\let\debug@char@bs*}
% \long\gdef\debug@iv#1#2#3#4#5\debug@qstop{#1#2#3#4}
\long\gdef\debug@type@nondigits#1{%
\ifx\debug@qstop#1%
\expandafter\debug@use@TF%
\else%
\expandafter\debug@use@FT%
\fi%
{}{%
\ifnum9<1#1 % Critical space
\expandafter\debug@use@TF%
\else%
\expandafter\debug@use@FT%
\fi%
{\debug@to@stop}%
{#1\debug@type@nondigits}%
}%
}
\long\gdef\debug@use@TF#1#2{#1}
\long\gdef\debug@use@FT#1#2{#2}
\long\gdef\debug@use@FF#1#2{}
\long\gdef\debug@use@F#1{}
\long\gdef\debug@gobble#1{}
\long\gdef\debug@meaning@aux#1#2 #3\debug@qstop{%
\ifx\debug@char@bs#1%
\long\gdef\debug@type{#2}%
\else%
\long\gdef\debug@type{character}%
\fi%
}
% ============= Let us now act! =======================
% For "macros", we expand once, whether it is protected or not.
\long\gdef\debug@do@expand{%
\debug@toks@expandfirst\debug@toks@todo}
\long\gdef\debug@toks@expandfirst#1{%
\expandafter\expandafter\expandafter\expandafter%
\expandafter\expandafter\expandafter\global%
\expandafter\expandafter\expandafter\expandafter%
\expandafter\expandafter\expandafter#1%
\expandafter\expandafter\expandafter\expandafter%
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\empty%
\the#1%
}%
}
% Special type of expansion: conditionals, for which we wish to also
% output the outcome of the test.
\long\gdef\debug@do@expand@if#1{%
\debug@insurance{%
\debug@read@unsafe{#1}%
\long\xdef\debug@print@wedid@tl{\space%
Test: \detokenize\expandafter{\debug@read@x}= %
\debug@read@x true \else false \fi%
}%
}%
\debug@do@expand%
}
% For a few other cases, we remove the head of \debug@toks@todo
% and append it to \debug@toks@done
\long\gdef\debug@do@keep{%
\debug@save@first\debug@use@first\debug@remove@first}
\long\gdef\debug@do@character{%
\debug@save@first\debug@use@first\debug@remove@first}
\long\gdef\debug@do@unsupp{%
\debug@save@first\debug@remove@first}
\long\gdef\debug@do@throw{\debug@remove@first}
\long\gdef\debug@do@justdo{%
\expandafter\expandafter\expandafter\global%
\expandafter\expandafter\expandafter\debug@toks@todo%
\expandafter\expandafter\expandafter{%
\expandafter\debug@use@F\the\debug@toks@todo}%
\debug@head%
}
\long\gdef\debug@do@relax{%
\expandafter\expandafter\expandafter\global%
\expandafter\expandafter\expandafter\debug@toks@todo%
\expandafter\expandafter\expandafter{%
\expandafter\debug@use@F\the\debug@toks@todo}%
}
% For assignments, we use \afterassignment\debug@do@assign@aux
% to regain control after letting TeX do the assignment.
\long\gdef\debug@do@assign@after{%
\long\xdef\debug@modifiers@tl{}%
\let\debug@tmpa\debug@afterassignment@token%
\let\debug@afterassignment@token\debug@empty@long%
\global\debug@toks@todo\expandafter\expandafter\expandafter{%
\expandafter\debug@tmpa\iffalse}\fi%
}
\long\gdef\debug@do@assign{%
\afterassignment\debug@do@assign@after%
\iffalse{\fi%
\expandafter\debug@modifiers@tl%
\the\debug@toks@todo}%
}
% Todo: reset modifiers after any step
\long\gdef\debug@do@modifier{%
\debug@read@unsafe{1}%
\long\xdef\debug@modifiers@tl{%
\debug@modifiers@tl\debug@read@x}%
\debug@remove@first%
}
% Experimental \afterassignment.
\long\gdef\debug@do@afterassignment{%
\debug@remove@first%
\debug@read@unsafe{1}%
\debug@remove@first%
\let\debug@afterassignment@token\debug@read@x%
}
% When we want to keep things like skips, penalties, etc., and
% particularly cleanup after them, we assign their "argument" to
% an internal skip or count, and regain control \afterassignment.
% We use \debug@do@keep@skip and \debug@do@keep@count.
\long\gdef\debug@remember#1{\long\gdef\debug@remembered{#1}}
\long\gdef\debug@do@keep@after{%
\long\xdef\debug@modifiers@tl{}%
\global\debug@toks@todo\expandafter{\iffalse}\fi%
}
\long\gdef\debug@do@keep@#1{%
\long\gdef\debug@tmpa{\afterassignment\debug@do@keep@after%
\csname debug@tmp@#1\endcsname}%
\afterassignment\debug@tmpa%
\iffalse{\fi\expandafter\debug@remember\the\debug@toks@todo}%
%
\expandafter\debug@remembered\the\csname debug@tmp@#1\endcsname%
%
\expandafter\expandafter\expandafter\debug@toks@done@append%
\expandafter\expandafter\expandafter{%
\expandafter\debug@remembered%
\the\csname debug@tmp@#1\endcsname%
\relax}%
}
\long\gdef\debug@do@keep@count{\debug@do@keep@{count}}
\long\gdef\debug@do@keep@skip{\debug@do@keep@{skip}}
\long\gdef\debug@do@keep@count@edef{%
\long\gdef\debug@tmpa{% captures the rest of the toks
\global\debug@toks@todo\expandafter{\iffalse}\fi%
}%
\long\gdef\debug@tmpb{% captures the text to write, then proceed
\afterassignment\debug@tmpa%
\edef\debug@tmpw% will get the text to write
}%
\long\gdef\debug@tmpc{% captures the stream number, then proceed
\afterassignment\debug@tmpb%
\global\debug@tmp@count% will get the stream.
}%
\afterassignment\debug@tmpc%
\iffalse{\fi\expandafter\debug@remember\the\debug@toks@todo}%
%
\long\xdef\debug@tmpa{%
\debug@modifiers@tl%
\expandafter\noexpand\debug@remembered%
\the\debug@tmp@count%
{\unexpanded\expandafter{\debug@tmpw}}%
}%
\debug@tmpa%
\expandafter\debug@toks@done@append\expandafter{\debug@tmpa}%
\long\xdef\debug@modifiers@tl{}%
}
% For \setbox, the situation is more complicated: \afterassignment only
% brings us inside the box. So we \afterassignment a macro which expands
% to \aftergroup \<regain_control>.
\long\gdef\debug@do@assign@after@afgr{\aftergroup\debug@do@assign@after}
\long\gdef\debug@do@assign@box{%
\afterassignment\debug@do@assign@after@afgr%
\iffalse{\fi%
\the\debug@toks@todo}%
}
% For \hbox, \vbox, \vtop, we cheat by storing them inside the dummy
% box \debug@tmp@box (using \savebox that we have just obtained).
\long\gdef\debug@do@any@box{%
\global\debug@toks@todo\expandafter{%
\expandafter\setbox\expandafter\debug@tmp@box\expandafter=%
\the\debug@toks@todo}%
}
% ===== Moving the first from \debug@toks@todo to \debug@toks@done.
\long\gdef\debug@remove@first{%
\expandafter\expandafter\expandafter\global%
\expandafter\expandafter\expandafter\debug@toks@todo%
\expandafter\expandafter\expandafter{%
\expandafter\debug@use@F\the\debug@toks@todo}%
}
\long\gdef\debug@save@first{%
\expandafter\debug@save@first@\the\debug@toks@todo\debug@qstop}
\long\gdef\debug@save@first@#1{%
\debug@toks@done@append{#1}%
\debug@to@stop}
\long\gdef\debug@use@first{%
\expandafter\debug@use@first@\the\debug@toks@todo\debug@qstop}
\long\gdef\debug@use@first@#1{%
\expandafter#1\debug@to@stop}
% ============ Setup one macro per primitive
\long\gdef\debug@primitive#1{%
\long\xdef\debug@tmpa@tl{#1}%
\debug@primitive@aux%
}
\long\gdef\debug@primitive@iv#1{%
\long\xdef\debug@tmpa@tl{\debug@type@nondigits #1\debug@qstop}%
\debug@primitive@aux%
}
\long\gdef\debug@primitive@aux#1{%
\long\xdef\debug@tmpb@tl{%
\unexpanded\expandafter\expandafter\expandafter{%
\csname debug@text@do@#1\endcsname}}%
\expandafter\global\expandafter\let%
\csname debug@do@\debug@tmpa@tl\expandafter\endcsname%
\csname debug@do@#1\endcsname%
\expandafter\long\expandafter\gdef\csname debug@text@do@\debug@tmpa@tl%
\expandafter\endcsname\expandafter{\debug@tmpb@tl}%
}
\long\gdef\debug@solid@name{\detokenize\expandafter{\debug@read@x}}
\long\gdef\debug@text@do@character{Output the character \debug@solid@name. }
\long\gdef\debug@text@do@expand{Expanded \debug@solid@name once. }
\long\gdef\debug@text@do@keep{Sent \debug@solid@name to the output. }
\long\gdef\debug@text@do@justdo{Just did \debug@solid@name! }
\long\gdef\debug@text@do@throw{Ignored \debug@solid@name! }
\long\gdef\debug@text@do@relax{Relaxed a bit with \debug@solid@name. }
\long\gdef\debug@text@do@keep@skip{Output \debug@solid@name and its skip. }
\long\gdef\debug@text@do@keep@count{Output \debug@solid@name and its count. }
\long\gdef\debug@text@do@keep@count@edef{Maybe it was a write? \debug@solid@name. }
\long\gdef\debug@text@do@unsupp{Unsupported \debug@solid@name dumped into the output. }
\long\gdef\debug@text@do@assign{Assigned using %
\detokenize\expandafter{\debug@modifiers@tl}\debug@solid@name... }
\long\gdef\debug@text@do@assign@box{Assigned a box using \debug@solid@name... }
\long\gdef\debug@text@do@any@box{Preparing to store the \debug@solid@name in our box. }
\long\gdef\debug@text@do@modifier{Remembering the modifier \debug@solid@name. }
\long\gdef\debug@text@do@afterassignment{Attempting to take care of afterassignment.}
% In the current implementation, macros are mis-recognized as
% their modifiers, so we need to cheat and pretend that those
% modifiers should just be expanded. This will fail if there
% is a genuine \long or \protected or \outer out there.
\debug@primitive{immediate}{modifier}
\debug@primitive{global}{modifier}
%\debug@primitive{outer}{modifier}%disabled because it will break me.
\debug@primitive{long}{modifier}
\debug@primitive{protected}{modifier}
\debug@primitive{macro}{expand}
\debug@primitive{expandafter}{expand}
\debug@primitive{noexpand}{expand}
\debug@primitive{detokenize}{expand}
\debug@primitive{string}{expand}
\debug@primitive{csname}{expand}
\debug@primitive{lowercase}{expand}
\debug@primitive{uppercase}{expand}
\debug@primitive{relax}{relax}
\debug@primitive{par}{keep}
\debug@primitive{indent}{keep}
\debug@primitive{unskip}{keep}
\debug@primitive{unhbox}{keep@count}
\debug@primitive{unhcopy}{keep@count}
\debug@primitive{penalty}{keep@count}
\debug@primitive{vskip}{keep@skip}
\debug@primitive{hskip}{keep@skip}
\let\debug@do@muskipAA\debug@do@keep@muskip% not yet supported!
\debug@primitive{begingroup}{keep}
\debug@primitive{endgroup}{keep}
\debug@primitive{write}{keep@count@edef}
\debug@primitive{ignorespaces}{unsupp}
\debug@primitive{unpenalty}{unsupp}
\debug@primitive{/}{unsupp}
\debug@primitive{hbox}{unsupp}
\debug@primitive{vbox}{unsupp}
\debug@primitive{afterassignment}{afterassignment}
\debug@primitive{aftergroup}{throw}
\debug@primitive{futurelet}{assign}
\debug@primitive{let}{assign}
\debug@primitive{def}{assign}
\debug@primitive{edef}{assign}
\debug@primitive{gdef}{assign}
\debug@primitive{xdef}{assign}
\debug@primitive{advance}{assign}
\debug@primitive@iv{toks}{assign}
\debug@primitive@iv{skip}{assign}
\debug@primitive@iv{font}{assign}
\debug@primitive@iv{muskip}{assign}
\debug@primitive@iv{dimen}{assign}
\debug@primitive@iv{count}{assign}
\debug@primitive{everypar}{assign}
\debug@primitive{baselineskip}{assign}
\debug@primitive{parfillskip}{assign}
\debug@primitive{parskip}{assign}
\debug@primitive{leftskip}{assign}
\debug@primitive{rightskip}{assign}
\debug@primitive{parindent}{assign}
\debug@primitive{parshape}{assign}
\debug@primitive{escapechar}{assign}
\debug@primitive{hyphenchar}{assign}
\debug@primitive{catcode}{assign}
\debug@primitive{lccode}{assign}
\debug@primitive{uccode}{assign}
\debug@primitive{accent}{assign}%??
\debug@primitive{tracingassigns}{assign}
\debug@primitive{tracingcommands}{assign}
\debug@primitive{tracinggroups}{assign}
\debug@primitive{tracinglostchars}{assign}
\debug@primitive{tracingmacros}{assign}
\debug@primitive{tracingonline}{assign}
\debug@primitive{tracingoutput}{assign}
\debug@primitive{tracingpages}{assign}
\debug@primitive{tracingparagraphs}{assign}
\debug@primitive{tracingrestores}{assign}
\debug@primitive{tracingstats}{assign}
\debug@primitive{showboxbreadth}{assign}
\debug@primitive{showboxdepth}{assign}
\debug@primitive{setbox}{assign@box}
\debug@primitive{hbox}{any@box}
\debug@primitive{vbox}{any@box}
\debug@primitive{vtop}{any@box}
\debug@primitive{if}{expand}
\debug@primitive{ifdim}{expand}
\debug@primitive{ifnum}{expand}
\debug@primitive{else}{expand}
\debug@primitive{fi}{expand}
\long\gdef\debug@do@ifx{\debug@do@expand@if{3}}
\long\gdef\debug@do@ifvmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@ifhmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@ifmmode{\debug@do@expand@if{1}}
\long\gdef\debug@do@iffalse{\debug@do@expand@if{1}}
\long\gdef\debug@do@iftrue{\debug@do@expand@if{1}}
% ========== Messages.
\usepackage{hardwrap}
\long\gdef\debug@typeout#1{\immediate\write\c@debug@output@stream{#1}}
\long\gdef\debug@print@welcome{%
\debug@typeout{}%
\debug@typeout{======== Welcome to the debug package ========}%
\debug@typeout{\@spaces "|>" denotes tokens that we will act on.}%
\debug@typeout{\@spaces "<|" denotes the output to TeX's stomach.}%
\debug@typeout{\@spaces Type "\string\step{2}" to do two steps [...]}%
\debug@typeout{}%
}
\long\gdef\debug@print@outcome{%
\debug@typeout{Step \the\c@debug@steps\space===== The end!}%
\debug@print@done%
}
\long\gdef\debug@message@aux#1#2#3{%
\begingroup%
\lccode`\*=\newlinechar\relax%
\lowercase{\def\debug@newline{*}}%
\def\MessageBreak{%
\debug@newline #1\space\space}%
\set@display@protect%
\debug@typeout{#2\MessageBreak #3}%
\debug@typeout{}%
\endgroup}%
\long\gdef\debug@message#1#2#3{%
\HardWrap{\debug@message@aux{#1}{#2}}{72}{\HardWrapSetup}%
{\MessageBreak}{#3}}
\long\gdef\debug@print@todo{%
\ifnum\the\c@debug@noise>-1\relax%
\debug@message{|>}{\expandafter\debug@use@F}{%
\detokenize\expandafter{\the\debug@toks@todo}}%
\fi}
\long\gdef\debug@print@done{%
\debug@insurance{%
\debug@message{<|}{\expandafter\debug@use@F}{%
\detokenize\expandafter{\the\debug@toks@done}}}}
\long\gdef\debug@setup@print@wedid{%
\debug@read@unsafe{1}%
\long\xdef\debug@print@wedid@tl{\space%
\csname debug@text@do@\debug@type@correct\endcsname}}
\long\gdef\debug@print@wedid{%
\debug@insurance{%
\global\advance \c@debug@steps by 1\relax%
\lccode`\*=\newlinechar%
\lowercase{\long\gdef\MessageBreak{*\@spaces\@spaces\@spaces}}%
\debug@typeout{Step \the\c@debug@steps\space%
=====\debug@print@wedid@tl}%
\ifnum\c@debug@noise>-1\relax%
\debug@typeout{}%
\fi%
}%
}
% ============= To show the first token.
\long\gdef\debug@print@first{%
\ifnum\the\c@debug@noise>0\relax
\debug@read@unsafe{1}%
\long\xdef\debug@first@meaning{\expandafter\meaning\debug@read@x}%
\long\xdef\debug@first@string{\expandafter\string\debug@read@x}%
\debug@message{\debug@use@FF}{\debug@use@F}{%
\debug@first@string=\debug@first@meaning}%
\fi%
}
% ============= The prompt
\long\def\debug@hop@else#1\else#2\fi{\fi#1}
\long\def\debug@hop@fi#1\fi{\fi#1}
\long\gdef\debug@prompt{%
\ifnum\the\c@debug@nonstop=1\relax%
\debug@hop@else\debug@prompt@{\debug@prompt@treat}%
\else%
\global\advance\c@debug@nonstop by -1\relax%
\fi%
}
\long\gdef\debug@prompt@treat#1{%
\expandafter\debug@prompt@treat@aux#1\debug@qstop}
\long\gdef\debug@prompt@treat@aux#1{%
\ifcat A\noexpand#1\relax%
\expandafter\debug@use@TF%
\else%
\expandafter\debug@use@FT%
\fi%
{\csname debug@prompt@treat@#1\endcsname%
\debug@prompt@treat@aux}%
{\debug@to@stop@keep#1}%
}
\long\gdef\debug@prompt@treat@q{\noise{-1}\step{0}}
\long\gdef\debug@prompt@treat@x{\endgroup\endgroup\fi\iffalse}
\long\gdef\debug@prompt@treat@s#1#2{\silentstep{#2}#1}
\long\gdef\debug@prompt@treat@o#1#2{%
\ifnum#2<0\relax%
\else\ifnum#2=0\relax%
\global\c@debug@output@stream-1\relax%
\else%
\global\c@debug@output@stream16\relax%
\fi\fi%
#1}
\long\xdef\debug@prompt@tl#1{%
\noexpand\read\noexpand\c@debug@prompt@stream to%
\expandafter\noexpand\csname Your input \endcsname%
#1\expandafter\noexpand\csname Your input \endcsname}
\long\gdef\debug@prompt@before@tl{}
\long\gdef\debug@prompt@#1{%
\begingroup\escapechar=-1\relax%
\def\step##1{\global\c@debug@nonstop##1\relax}%
\def\noise##1{\global\c@debug@noise##1\relax}%
\def\silentstep##1{%
\noise{-1}%
\step{##1}%
\long\gdef\debug@prompt@before@tl{\noise{1}}%
}%
\endlinechar=-1%
\debug@prompt@before@tl%
\long\gdef\debug@prompt@before@tl{}%
\debug@prompt@tl{#1}%
\endgroup}
\usepackage{amsmath}
\begin{document}
\section{Normal-section}
Title above for comparison purposes.
\debug@unravel{\section{Unravelled-section}}%
The section title above was typeset as we unravelled.
\the\debug@toks@done%
That third section is made using what is stored at
the end of the unravelling.
Only trivial maths works: $\debug@unravel{xy = z}$,
and it is stored in our ouput token list, $\the\debug@toks@done$.
Some more complex maths symbols fail, complain, cheat:
\[
\debug@unravel{\int\mathrm{d}x\sin(\pi)=0}
\]
\[
\the\debug@toks@done.
\]
And sub- and super-scripts are totally unsupported so far.
\end{document}
答案2
查尔斯要求我发布上述评论的摘要;这里有一个简短的概要。
将要:
我可能不是目标受众,但我认为这对我来说没什么用。(不过,尝试一下肯定很有趣。)我通常发现,当我需要检查宏定义时,输出中缺少缩进和换行符,这
\show
在\meaning
很多情况下限制了它们的实用性。
芭芭拉:
很可爱。2 条评论:
- 我认为“反射”就像镜子中发生的事情,并使用该名称通过图形包(其中已经有一个 \reflectbox 命令)水平镜像符号或字符串。我会称之为不同的东西,也许是 \unwrap 或 \unravel。
- 也许我假设太多,但是我尝试直接运行它,而不使用文档类和 \begin/\end{document} 来包装它,...并且失败了。我想我被宠坏了,但是我喜欢开箱即用的例子。
曼努埃尔:
为了快速调试,我更喜欢以交互方式运行 TeX 并
\show
直接在终端上查看输出。