[Tex/LaTex] How to change indentation in the middle of a paragraph

indentationparagraphstex-core

I'll start with a little background info. Maybe it will help find an alternative solution.

I have made a few macros for simple indented lists, text-editor-efficient (just add or remove an x to change indentation). All this by changing \leftskip, which just worked. But then I decided to save some space by attaching the description text \descr to the item before it – without ending a paragraph but still I want the continuation of this description to have a larger indentation. The code below does this wrong. \desc in fact increases indentation of the paragraph it is appended to.

Here's my current code. I'm using LaTeX, although it may not look like it:

\newdimen\ListSkip\ListSkip=1cm
\def\nox{\par\bigskip\leftskip=0pt\normalsize\rm\relax}
\def\x{\par\leftskip=0pt\Large\rm\bfseries\relax}
\def\xx{\par\leftskip=1\ListSkip\normalsize\rm\bfseries\relax}
\def\xxx{\par\leftskip=2\ListSkip\normalsize\rm\relax}
\def\desc{\quad\leftskip=3\ListSkip\footnotesize\sf\relax}

\x First Chapter.
\xx A few words from our sponsor.
\xx Theory of ABC explained in detail.
\xxx The scientifical world just a few years back.
\xxx First important discovery.
\desc Here I will describe how professor Humblegoat made the miraculous discovery of the relation behind this theory while he was electroshocked in his bathtub.
\xxx Ground-breaking changes in physical concepts.
\nox Normal text again here.

This renders as:

rendered example

The problem is, that First important discovery is now more indented than The scientifical world… \leftskip obviously isn't the right tool to use in \desc. If instead of it I use \hangindent=1\ListSkip\hangafter=1 the result is correct but how do I know the current line in a paragraph that I can use in \hangafter?

Best Answer

If instead of it I use \hangindent=1\ListSkip\hangafter=1 the result is correct but how do I know the current line in a paragraph that I can use in \hangafter?

The simple answer is: you can't. TeX doesn't know which element of a paragraph falls onto which line before it is actually breaking the paragraph into line and that happens on when it counters the \par command or an empty line that finishes the paragraph. However, by that time all macro processing within the paragraphs has taken place and thus this information is not available to the macro processing.

Thus, if the the material before the description is more than one line, e.g.

\xxx First important discovery. And it takes more than a line in the document. Or perhaps more.
\desc Here I will describe how professor Humblegoat ...

then there is no way to detect this if it all happens in a single paragraph. And there is another problem with this setup: you change the \baselineskip midway as you are changing the font size for the description. But again TeX only looks once at the \baselineskipfor a paragraph (when it hits \par). Thus your first two lines would already be in the smaller baselineskip but with a larger font.

So having said all this, there is a sneaky way to make it work: split the material in two paragraphs and ensure that the second one has the right kind of indentation on its first line. The trick is to use a math display feature which allows us to obtain the length lof the last line preceding the display. So at begin of \desc we interrupt the current paragraph with a math display, record the size of the precious line. Then back up by whatever space the empty display has added to the page. Then set up producing the new paragraph and continue.

The fairly horrible code for this looks as follows:

\newdimen\lastlinewidth

\def\desc{%
\begingroup
  \predisplaypenalty=10000
  \postdisplaypenalty=10000
  \abovedisplayskip=0pt
  \abovedisplayshortskip=0pt
  \belowdisplayskip=-\baselineskip
  \belowdisplayshortskip=-\baselineskip
  $$\global\lastlinewidth\predisplaysize
      \global\advance\lastlinewidth by -2em
  $$%  
\endgroup
\footnotesize\sf\relax
\vskip-\baselineskip             % backup by the baselineskip about to come for the new text (depends on new font size!)
\vskip-\parskip                  % and the parskip being added
\noindent\kern\lastlinewidth     % start new paragraph for "description"
\leftskip=0pt                    % cancel any \leftskip
\hangindent=3\ListSkip           % but instead use \hangindent from the start
\quad
  }

If we apply this definition to the example (with the extra line after \xxx First ...) we get the following result:

enter image description here

which should be the expected result.

What happens behind the scence can be seen if one looks at the generated material on the final page (via \showoutput). The relevant portion here is:

....\OT1/cmr/m/n/10 m
....\OT1/cmr/m/n/10 o
....\OT1/cmr/m/n/10 r
....\OT1/cmr/m/n/10 e
....\OT1/cmr/m/n/10 .
....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil
....\glue(\rightskip) 0.0
...\penalty 10000
...\glue(\abovedisplayskip) 0.0
...\glue(\baselineskip) 10.05556
...\hbox(0.0+0.0)x0.0, shifted 172.5, display
...\penalty 10000
...\glue(\belowdisplayskip) -12.0
...\glue -9.5
...\glue 0.0 plus -1.0
...\glue(\parskip) 0.0 plus 1.0
...\glue(\baselineskip) 3.94444
...\hbox(5.55556+1.55556)x345.0, glue set 0.09123
....\glue(\leftskip) 85.35823
....\kern 183.98907
....\kern -85.35823
....\glue 8.50012
....\OT1/cmss/m/n/8 H
....\OT1/cmss/m/n/8 e
....\OT1/cmss/m/n/8 r
....\OT1/cmss/m/n/8 e

You can see the various penalties and skips that are added by the display (and the empty box representing the display) and the kerns and skips that got added to counter balance this. You also see the different baselineskips due to the different font sizes.

One final comment:

Splitting a paragraph this way can have side effects, especially if such code is imbedded into the LaTeX machinery, which has its own set of peculiarities around paragraph handling (like internally redefining \everpar in places, etc.). Thus one need to be careful and one has to be prepared to dig into the LaTeX2e kernel code in case of trouble.

One general side effect worth mentioning is the following: the last line of a paragraph when broken by TeX is always set without any stretch while lines in the middle of a paragraph may be set somewhat loose or tight depending on the circumstances. This means that artificially splitting the paragraph in this manner reduces the options TeX has to find optimal line breaks and may alter the paragraph even if otherwise everything would be kept the same (i.e., no margin changes and so on). In particular the last line of the first paragraph and the first line of the last paragraph will not necessarily have the same "looseness", the latter might be set very loose or tight while the former always has spaces at their natural width.