Push/Pop or save a length/dimension?

Just say, in your preamble,

\newlength{\savedparindent}

and, when you want to change the \parindent, say

\setlength{\savedparindent}{\parindent}
\setlength{\parindent}{<dimen>}

Then you can restore the previous \parindent by

\setlength{\parindent}{\savedparindent}

This is even unnecessary if you use the environment structure:

\newenvironment{otherparindent}[1]
  {\par\setlength{\parindent}{#1}}
  {\par}

so that the change to \parindent is confined to the environment. Of course it's not necessary to use such an environment: you can put the \setlength{\parindent}{<dimen>} code in the definition of any environment.

A stack based solution is easily obtained with 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}

This will show in succession 15.0pt, 100.0pt, 50.0pt, 100.0pt, 15.0pt; the command \pushparindent stores the current value and sets \parindent to the value specified in the argument. With \popparindent you get the last stored value.

Here's a version with "standard 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}

You can implement a stack without using LaTeX3 as well, by using a token list and some macros. That would work as follows:

\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}

It will print 200pt 400pt 300pt 200pt Can't pop from an empty stack.. You can of course replace the error message with some error handling code, or some default value to be returned. This is all based on an example in chapter 14 of TeX by Topic. If you want to set \parindent directly instead of just printing the value, simply change #1 in the \else of \splitList to \parindent=#1.


You can create a new macro length and add \parindent to it which creates a copy of \parindent

\newlength{\mylen}
\setlength\mylen{\parindent}
\setlength\parindent{0pt}

When you are ready to restore \parindent you can use

\setlength\parindent{\mylen}

Note this method does not allow nesting.

There is also a stack based solution but maybe less efficient.

With lualatex you can simply use a stack in lua with a tex macro wrapper. Should be pretty self-explanatory.

Tags:

Macros

Lengths