这是我的例子,与删除多余的花括号。除了我的应用程序之外,尝试在边距中对标签进行换行,即使它们中没有空格,我也试图了解发生了什么。
\documentclass{article}
\usepackage{showlabels}
\usepackage{seqsplit}
\usepackage{xpatch}
\makeatletter
% line-break annotations, http://tex.stackexchange.com/a/148613/30810
\patchcmd{\showlabelsetlabel}{#1}{\parbox[t]{\marginparwidth}{\myseqsplit{#1}}}{}{err}
% remove extra curly braces, http://tex.stackexchange.com/a/300871/30810
\newcommand{\myseqsplit}[1]{\expandafter\seqsplit\expandafter{\@firstofone#1}}
% remove curly braces from text
\patchcmd{\SL@margintext}{\{\SL@prlabelname{#1}\}}{#1}{}{err}
% testing patch: overwrite *definition* of \SL@prlabelname (twice because two code paths) - no effect
% \patchcmd{\SL@margtext}{\xdef\SL@labelname{\SL@prlabelname{#1}}}{\xdef\SL@labelname{kooooooooooooooooooooooooooooooong}}{}{err}
% \patchcmd{\SL@margtext}{\xdef\SL@labelname{\SL@prlabelname{#1}}}{\xdef\SL@labelname{kooooooooooooooooooooooooooooooong}}{}{err}
% testing patch: overwrite *use* of \SL@prlabelname - has an effect
% \patchcmd{\@eqnnum}{\SL@eqntext{\SL@labelname}}{\SL@eqntext{pooooooooooooooooooooooooooooooong}}{}{err}
% down the road, show the argument being passed. no change with either patch!
\pretocmd{\SL@eqnlrtext}{\edef\test{#1}\meaning\test}{}{err}
\begin{document}
\begin{equation}
\label{looooooooooooooooooooooooooooooong}
\end{equation}
\end{document}
第一行应该相当明显,定义了parbox
要放入标签的。第二行与我前面提到的问题有关,因为我假设额外的花括号可能是罪魁祸首(我不认为它们现在也是罪魁祸首)。第三行简化了中的文本,parbox
使其成为一个单组参数,见上文。
现在,虽然整个过程在equation
环境之外(不同的代码路径)确实有效,但在环境内部却不起作用,我试图调查原因。(这就是为什么这个 MWE 几乎归结为这个单一案例的原因。)
我的两个可选补丁覆盖了 的定义和使用\SL@labelname
。有趣的是,虽然覆盖定义不起作用(它可以工作,但对换行符没有影响),但覆盖使用却有效。更有趣的是,后面的最后一个补丁显示了参数的值,而这个值在不同的补丁之间似乎没有变化(至少我看不出有什么区别)。
答案1
而且,它真的有效。太神奇了。
\seqsplit
遍历除最后一步之外的每个步骤中插入的标记列表。
因此,如果给定looooong
,则在构建循环时忽略扩展顺序和赋值的有效行为是
l\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert n\seqinsert g
如果提供的序列是单个标记\kong
,\seqsplit
则不执行任何有用的操作,因为该序列的长度为 1。
解决这个问题的标准方法是\kong
在调用之前\seqsplit
进行扩展
\expandafter\seqsplit\expandafter{\kong}
如果\kong
定义为,则looooong
只需一步即可扩展为
\seqsplit{looooong}
从而产生与原始相同的结果。
建议使用
\seqsplit{\expandafter\kong}
其工作或多或少是偶然的,并且严重依赖于循环的具体实现。
稍微简化\seqsplit
一下,通过查看第一个标记,检查它不是标记输入结束的保护标记,如果不是,则输出第一个标记,然后输出\SQSPL@insert
递归开始查看下一个标记的命令。
因此
\seqsplit{\expandafter\kong}
第一个 token 是,\expandafter
所以第一步是
\expandafter\SQSPL@insert\kong
但是现在这个第一个标记不仅仅是一个像l
扩展一样的字符,所以\kong
在循环递归之前扩展标记,所以下一步是
\SQSPL@insert looooong
从这一点开始,迭代继续进行,就好像字符串在输入参数中已经明确一样。
因此,该{\expandafter\kong}
形式之所以有效,是因为\seqsplit
迭代只会在标记之间放置一个标记,以便扩展\expandafter
的\kong
,也因为它会导致\seqinsert
在第一个标记之后插入,\expandafter
这意味着最终结果不等同于显式输入,而是等同于
\seqinsert l\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert o\seqinsert n\seqinsert g
\seqinsert
在开头有一个附加项。(您可以通过将其定义\seqinsert
为可见的内容来看到这一点,例如
\def\seqinsert{!}
默认定义只是一个\hspace
自然大小为 0 的,所以这个虚假空间不是那么明显,但如果你这样做
\def\seqinsert{\ifmmode\allowbreak\else\hspace{20pt plus 0.02em}\fi}
您会看到该{\expandafter\kong}
版本有 10pt 的虚假缩进。
因此,要在宏调用之前扩展参数,
\expandafter\seqsplit\expandafter{\kong}
形式为佳。
答案2
将我的 MWE 降低到这个之后
\documentclass{article}
\usepackage{seqsplit}
\makeatletter
\newcommand{\myseqsplit}[1]{\expandafter\seqsplit\expandafter{\@firstofone#1}}
\begin{document}
\seqsplit{loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong}
\def\kong{loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong}
\seqsplit{\kong}
\end{document}
我试过\seqsplit{\expandafter\kong}
。
而且,它真的有效。太神奇了。
因此,在我最初的 MWE 中,情况是这样的:
\patchcmd{\@eqnnum}{\SL@eqntext{\SL@labelname}}{\SL@eqntext{\expandafter\SL@labelname}}{}{err}
如果你使用amsmath
,这可能会更完整:
\ifSL@AMS
\patchcmd{\maketag@@@}{{\df@label}}{{\expandafter\df@label}}{}{err}
\patchcmd{\maketag@@@}{{\SL@labelname}}{{\expandafter\SL@labelname}}{}{err}
\else
\patchcmd{\@eqnnum}{{\SL@labelname}}{{\expandafter\SL@labelname}}{}{err}
\fi