我正在更新subsubsection
命令,以便我可以将以下文本放在同一行(默认),或者留下一些空格,并!
传递一个标记。看来,对于subsubsection
与[]
或!
的组合*
,!
它可以编译但不会产生所需的结果。
我已经成功创建了接受多个令牌的命令(在同一个 MWE 中测试)xparse
,但不确定这是否是问题所在。
这已在 Overleaf 上的 TeX Live 2020 上进行了测试。我尝试了luaexec
、directlua
和luadirect
。
问题:有人能发现我的尝试/方法中的缺陷吗?我的解决方案使用 LuaLaTeX。重建命令并从 Lua 打印它感觉有点不合时宜——有没有一种规范的方法可以以类似的方式“增强”命令(即添加标记参数!或者说其他可选参数)。subsubsection 命令是否需要可扩展?
\documentclass{scrartcl}
\usepackage{xparse}
\usepackage{luacode}
\RedeclareSectionCommand[afterskip=-4ex]{subsubsection}
\begin{luacode*}
_xTrue = '\\BooleanTrue '
_xFalse = '\\BooleanFalse '
_xNoValue = '-NoValue-'
function makesubsubsection(s, o, m)
texio.write_nl('>>>>> Arguments are: '..s..', '..o..', '..m)
local cmd = '\\oldsubsubsection'
if s == _xTrue then
cmd = cmd .. '*'
end
if o ~= _xNoValue then
cmd = cmd..'['..o..']'
end
tex.print(cmd..'{'..m..'}')
end
\end{luacode*}
\let\oldsubsubsection\subsubsection
\RenewExpandableDocumentCommand{\subsubsection}{ s t! o m }{% does this need to be expandable?
\IfBooleanT{#2}{\RedeclareSectionCommand[afterskip=12pt]{subsubsection}}{}
\directlua{makesubsubsection(\luastringN{#1},\luastringN{#3},\luastringN{#4})}
\IfBooleanT{#2}{\RedeclareSectionCommand[afterskip=-4ex]{subsubsection}}{}%
}
% \NewDocumentCommand{\TestTokArg}{ s t! }{%
% Test:\IfBooleanT{#1}{Star}\IfBooleanT{#2}{Excl}% testing token arg
% }
\begin{document}
% \TestTokArg \TestTokArg* \TestTokArg! \TestTokArg*! % testing token arg
\tableofcontents
\subsubsection{in ToC, in Line} text %% works
\subsubsection[short1]{in ToC, in Line} text %% works
\subsubsection!{in ToC, not in Line} text %% works
\subsubsection![short2]{in ToC, not in Line} text %% does not work
\subsubsection*{no ToC, in Line} text %% works
\subsubsection*!{no Toc, not in line} text %% does not work
\end{document}
为了排除故障,我打印出我的 lua 函数接收的参数,但在日志中,它只显示前三个调用subsubsection
:
>>>>> Arguments are: \BooleanFalse , -NoValue-, in ToC, in Line
>>>>> Arguments are: \BooleanFalse , short1, in ToC, in Line
>>>>> Arguments are: \BooleanFalse , -NoValue-, in ToC, not in Line
答案1
首先让我们不使用 Lua 来重写这个,以避免两种语言的交互分散对实际问题的注意力:
\documentclass{scrartcl}
\usepackage{xparse}
\RedeclareSectionCommand[afterskip=-4ex]{subsubsection}
\let\oldsubsubsection\subsubsection
\RenewDocumentCommand{\subsubsection}{ s t! o m }{%
\IfBooleanT{#2}{\RedeclareSectionCommand[afterskip=12pt]{subsubsection}}%
\expanded{% \expanded ensures that we get one pass of expansion first which we use to build the right command. We can put \noexpand and/or \unexpanded around everything that should be preserved.
\noexpand \oldsubsubsection
\IfBooleanT {#1}{*}%
\IfValueT {#3} {\unexpanded{[#3]}}%
\unexpanded{{#4}}%
}%
\IfBooleanT{#2}{\RedeclareSectionCommand[afterskip=-4ex]{subsubsection}}%
}
\begin{document}
\tableofcontents
\subsubsection{in ToC, in Line} text %% works
\subsubsection[short1]{in ToC, in Line} text %% works
\subsubsection!{in ToC, not in Line} text %% works
\subsubsection![short2]{in ToC, not in Line} text %% does not work
\subsubsection*{no ToC, in Line} text %% works
\subsubsection*!{no Toc, not in line} text %% does not work
\end{document}
这仍然会失败,所以 Lua 不可能是导致该问题的原因。
每次调用\subsubsection
后 !
已使用过一次。每当!
使用时,您的代码都会调用\RedeclareSectionCommand
,这将覆盖您指定的部分命令的当前定义(在您的例子中\subsubsection
)。因此,它会覆盖您对此命令的重新定义,从而导致问题,因为之后\subsubsection
不再知道您的附加参数。
为了解决这个问题,您可以避免\RedeclareSectionCommand
并直接更改参数控制afterskip
:afterskip
forsubsubsection
存储在中\scr@subsubsection@afterskip
。
所以你得到
\documentclass{scrartcl}
\usepackage{xparse}
\let\oldsubsubsection\subsubsection
\makeatletter
\RenewDocumentCommand \subsubsection { s t! o m }{%
\edef \scr@subsubsection@afterskip {%
\IfBooleanTF {#2} {12pt} {-4pt}%
}%
\expanded{%
\noexpand \oldsubsubsection
\IfBooleanT {#1} {*}%
\IfValueT {#3} {\unexpanded{[#3]}}% edit forgot {#3}
\unexpanded{{#4}}%
}%
}
\makeatother
\begin{document}
\tableofcontents
\subsubsection{in ToC, in Line} text %% works
\subsubsection[short1]{in ToC, in Line} text %% works
\subsubsection!{in ToC, not in Line} text %% works
\subsubsection![short2]{in ToC, not in Line} text %% works
\subsubsection*{no ToC, in Line} text %% works
\subsubsection*!{no Toc, not in line} text %% works
\end{document}