是否可以像 parindent 那样推送或弹出长度?我想暂时更改它,但很快就会重置它。
我有一个解决方案,但正在寻找更好的解决方案。我会将其作为答案发布。
答案1
您也可以不使用 LaTeX3,而是使用标记列表和一些宏来实现堆栈。其工作原理如下:
\documentclass{article}
\newtoks\paridstack
\paridstack={\empty}
\def\push#1#2{%
\begingroup\toks0={{#1}}%
\edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
}% push #1 onto #2
\def\pop#1{%
\begingroup
\edef\act{\endgroup\noexpand\splitList\the#1(tail)#1}\act
}% pop from #1
\def\splitList#1#2(tail)#3{%
\ifx#1\empty Can't pop an empty stack.\else#1\global#3={#2}\fi
}
\begin{document}
\noindent
\push{200pt}{\paridstack}%
\pop{\paridstack}\\
\push{200pt}{\paridstack}%
\push{300pt}{\paridstack}%
\push{400pt}{\paridstack}%
\pop{\paridstack}\\
\pop{\paridstack}\\
\pop{\paridstack}\\
\pop{\paridstack}
\end{document}
它将打印200pt
400pt
300pt
200pt
Can't pop from an empty stack.
。当然,你可以用一些错误处理代码或要返回的某些默认值替换错误消息。这一切都基于第 14 章中的示例TeX 按主题分类。如果您想\parindent
直接设置而不是只打印值,只需将的更改#1
为。\else
\splitList
\parindent=#1
答案2
在你的序言中说,
\newlength{\savedparindent}
并且,当你想改变时\parindent
,说
\setlength{\savedparindent}{\parindent}
\setlength{\parindent}{<dimen>}
然后你可以\parindent
通过以下方式恢复之前的状态
\setlength{\parindent}{\savedparindent}
如果您使用环境结构,这甚至是不必要的:
\newenvironment{otherparindent}[1]
{\par\setlength{\parindent}{#1}}
{\par}
这样对 的更改\parindent
就仅限于该环境。当然,没有必要使用这样的环境:你可以将代码放在\setlength{\parindent}{<dimen>}
任何环境的定义中。
使用 LaTeX3 可以轻松获得基于堆栈的解决方案:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \g_uiy_parindent_seq
\NewDocumentCommand{\pushparindent}{m}
{
\seq_gpush:Nx \g_uiy_parindent_seq {\the\parindent}
\dim_gset:Nn \parindent {#1}
}
\NewDocumentCommand{\popparindent}{}
{
\seq_gpop:NN \g_uiy_parindent_seq \l_tmpa_tl
\dim_gset:Nn \parindent {\l_tmpa_tl}
}
\ExplSyntaxOff
\begin{document}
\showthe\parindent
\pushparindent{100pt}
\showthe\parindent
\pushparindent{50pt}
\showthe\parindent
\popparindent
\showthe\parindent
\popparindent
\showthe\parindent
\end{document}
这将依次显示 15.0pt、100.0pt、50.0pt、100.0pt、15.0pt;该命令\pushparindent
存储当前值并设置\parindent
为参数中指定的值。\popparindent
您将获得最后存储的值。
以下是“标准 LaTeX”的版本:
\newtoks\parindentstack
\newcommand{\pushparindent}[1]{%
\edef\temp{\noexpand\listelement{\the\parindent}\the\parindentstack}%
\global\parindentstack=\expandafter{\temp}%
\global\parindent=#1\relax
}
\newcommand{\popparindent}{%
\if\relax\detokenize\expandafter{\the\parindentstack}\relax
\errmessage{Empty stack}%
\else
\expandafter\getlistelement\the\parindentstack\getlistelement
\fi
}
\def\getlistelement\listelement#1#2\getlistelement{%
\global\parindentstack{#2}\global\parindent=#1\relax}
答案3
您可以创建一个新的宏长度并添加\parindent
到它,从而创建\parindent
\newlength{\mylen}
\setlength\mylen{\parindent}
\setlength\parindent{0pt}
当您准备恢复时,\parindent
您可以使用
\setlength\parindent{\mylen}
注意此方法不允许嵌套。
还有基于堆栈的解决方案,但效率可能较低。
使用 lualatex,您可以简单地使用 lua 中的堆栈和 tex 宏包装器。应该很容易理解。
答案4
此解决方案只是对 Roelof 的回应。我希望它在这里是合适的。我在他的解决方案\empty
中用替换了\roelofstackbegin
。这比使用 更安全\empty
。Roelof 的堆栈看起来像一个万能堆栈。因此应避免任何可能的故障源。
\documentclass{article}
\makeatletter
\newtoks\roelofstack
\roelofstack={\roelofstackbegin}
\def\roelofstackbegin{\empty}
% push #1 onto #2:
\def\push#1#2{%
\begingroup
\toks0={{#1}}%
\edef\act{\endgroup\global#2={\the\toks0 \the#2}}%
\act
}
% pop from #1:
\def\pop#1{%
\begingroup
\edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}%
\act
}
\def\SplitOff#1#2(tail)#3{%
\ifx#1\roelofstackbegin
\errhelp{Attempting to pop empty stack #3.}%
\errmessage{You can't pop an empty stack.}%
\else
#1\global#3={#2}%
\fi
}
\makeatother
% Tests:
\begin{document}
\noindent
\push{\empty}{\roelofstack}
\pop{\roelofstack}
\push{200pt}{\roelofstack}
\pop{\roelofstack}\par
\push{200pt}{\roelofstack}
\push{300pt}{\roelofstack}
\push{400pt}{\roelofstack}
\pop{\roelofstack}\par
\pop{\roelofstack}\par
\pop{\roelofstack}\par
% \pop{\roelofstack} % Popping empty stack.
\end{document}