Ugly formatting problem in LaTeX2e

29 views
Skip to first unread message

Paul Floriani

unread,
May 7, 1996, 3:00:00 AM5/7/96
to

Okay, here's what I want to do:

I want to have a nice neat
formatted paragraph, just like
LaTeX normally does.

Then I want to put some
arbitrary text in the middle.

Then I
want a subsequent paragraph
to begin so that the leading
line is indented just beyond
where the last line in the
previous formatted paragraph
ended, in a fairly automated
fashion.

Then there's more arbitrary
text.

And then another
paragraph with the same sort
of stunt on the leading line.

And so on. Has anyone tried to do anything remotely like this? I
suspect that this requires hacking on the raw TeX end, which I don't
think I have time to do.

Any advice and/or pointers would be greatly appreciated. I've been
flipping frantically through Knuth, Lamport, and Goossens/Mittelback/Samarin
with no success. I imagine I could figure it out if I could digest Knuth's
book in its entirety, but that's a daunting enough feat even without the
time factor.

Thank you!
--
Paul Floriani
pflo...@us.oracle.com

Donald Arseneau

unread,
May 7, 1996, 3:00:00 AM5/7/96
to

In article <4mn00u$l...@inet-nntp-gw-1.us.oracle.com>, pflo...@us.oracle.com (Paul Floriani) writes...

> I want to have a nice neat
>formatted paragraph, just like
>LaTeX normally does.
>
>Then I want to put some
>arbitrary text in the middle.
>
> Then I
>want a subsequent paragraph
>to be ... indented like this

I have done related things twice in the past. Assuming the
vertical space around your arbitrary text is indeed what you
want, then this fits very well with the mechanics of the solution,
which is to make an alignment-display. Without testing:

% Use \interject{some text} to insert text `in' a paragraph, so following
% text will start indented to where the preceding text ended.

\def\interject#1{\ifhmode
\ifinner#1\else $$ % unrestricted horizontal mode
\predisplaypenalty=-50 \postdisplaypenalty=-50
% could adjust \above/belowdisplayskip here
\halign{##\cr\noalign{#1}}
% now get the width of the last line of the paragraph that just ended,
\ifdim\absval\predisplaysize>\indentfraction\hsize
% If it is too long just use zero indentation:
\global\varindent=0pt\relax % or \parindent
\else
% otherwise, use the width of the line above (\predisplaysize-2em):
\global\varindent=\predisplaysize \global\advance\varindent -2em
\fi $$\allowbreak \hskip\varindent
% add interword space if there's any indent
\ifdim \varindent>0pt\ \fi
\fi % end \ifinner test
\else #1\par % if not h-mode: v-mode
\fi}

\newskip\varindent
\def\indentfraction{.85}% indent as much as 85% of line

% useful little macro: gives absolute value of a number or a dimension (if in
% a dimension register). Note that this makes use of TeX's confusing habit of
% expanding \if's within a number

\def\absval#1{\ifnum#1<0 -\fi#1}

Donald Arseneau as...@reg.triumf.ca

Paul Floriani

unread,
May 7, 1996, 3:00:00 AM5/7/96
to

as...@reg.triumf.ca (Donald Arseneau) writes:

>In article <4mn00u$l...@inet-nntp-gw-1.us.oracle.com>, pflo...@us.oracle.com (Paul Floriani) writes...
>> I want to have a nice neat
>>formatted paragraph, just like
>>LaTeX normally does.
>>
>>Then I want to put some
>>arbitrary text in the middle.
>>
>> Then I
>>want a subsequent paragraph
>>to be ... indented like this
>
>I have done related things twice in the past. Assuming the
>vertical space around your arbitrary text is indeed what you
>want, then this fits very well with the mechanics of the solution,
>which is to make an alignment-display. Without testing:
>

[macro clipped for brevity]
>
>Donald Arseneau as...@reg.triumf.ca

The macro works exactly as advertised!

Thanks very much to you and to the others who replied so quickly and so
well. To others who may be working on my earlier note...thanks, but I now
have the solution I needed.

Paul Floriani
--
Paul Floriani
pflo...@us.oracle.com

David Carlisle

unread,
May 7, 1996, 3:00:00 AM5/7/96
to Paul Floriani

\documentclass{article}

\setlength\textwidth{6cm} % just for show

\newcommand\findent{{%
\abovedisplayshortskip0pt \belowdisplayshortskip-\baselineskip
\abovedisplayskip0pt \belowdisplayskip-\baselineskip
$$\global\dimen1\predisplaysize\global\advance\dimen1 -2em$$}%
\noindent\hspace*{\dimen1}}

\begin{document}

some text some text some text some text some text some text some text
some text some text some text some text some text some text some text
\findent funny indentation based on length of last line.

some text some text some text some text some text some text some text
some text some text some text some text some text some text some text
some text some text some text some text some text some text some text
\findent funny indentation based on length of last line.


\end{document}

Peter Schmitt

unread,
May 8, 1996, 3:00:00 AM5/8/96
to

pflo...@us.oracle.com (Paul Floriani) writes:
>Then I want to put some
>arbitrary text in the middle.
> Then I
>want a subsequent paragraph
>to begin so that the leading
>line is indented just beyond
>where the last line in the
>previous formatted paragraph
>ended, in a fairly automated
>fashion.
>
> And so on. Has anyone tried to do anything remotely like this? I
>suspect that this requires hacking on the raw TeX end, which I don't
>think I have time to do.
>
If you are prepared to do some adjusting `by hand' there is an
easy solution:

\def\SkipIndent #1{\bgroup\parfillskip #1
\parindent\hsize \advance\parindent-\parfillskip
\par \indent \egroup \ignorespaces}

(perhaps \hsize should be \textwidth in LaTeX?)

Then you can say, e.g.,
\SkipIndent {4cm}
and - if there is enough freedom (of spaceskip glue) in the two paragraphs
(in particular, if the first one is long enough) then you will get
the desired effect.
However, you will have to adjust the skip given in the command, if there
are underfull or overfull boxes because of lack of freedom.

A more complicated approach would be to use `invisible fonts'
(from LaTeX's slide option), typeset the two paragraphs twice
(as one paragraph) - once with the first and once with the second part
invisible and put them on the same place of the page - just shifted
vertically by one line (\baselineskip).
This would be rather simple to implement if the combined paragraphs
fit on the same page.
Otherwise it would require hacking of the \output routine,
a less trivial, but still possible task.

Peter

Mark Wooding

unread,
May 9, 1996, 3:00:00 AM5/9/96
to

Paul Floriani <pflo...@us.oracle.com> wrote:
> Okay, here's what I want to do:
>
> I want to have a nice neat
> formatted paragraph, just like
> LaTeX normally does.
>
> Then I want to put some
> arbitrary text in the middle.
>
> Then I
> want a subsequent paragraph
> to begin so that the leading
> line is indented just beyond
> where the last line in the
> previous formatted paragraph
> ended, in a fairly automated
> fashion.
>
> And so on. Has anyone tried to do anything remotely like this? I
> suspect that this requires hacking on the raw TeX end, which I don't
> think I have time to do.

Oddly enough, I've just been doing something vaguely like this (although
not quite as complicated). Since this article contains a solution and
lots of commentry, please don't bother reading it unless you're really
interested.

I think that the best way to do this is to horridly abuse TeX's display
handling. When you start a maths display, TeX works out the `visible'
width of the previous line and puts it in a special length called
`\predisplaysize' (i.e., not counting the extra space at the end of the
paragraph -- just the width of the actual text). It's used when
calculating the vertical space between the display and the end of the
previous paragraph.

Saying something like

\newlength\lastlinewidth
$$\global\lastlinewidth=\predisplaysize$$%

would put the width of the last line of the paragraph into the length
\lastlinewidth. (Well, almost. Actually, it adds 2em of space to it.
That has to be removed.) All well and good so far, but the display has
put all sorts of funny things in which will mess up the formatting.
What's worse is that you can't get rid of them, because TeX doesn't let
you remove such things from the main page once they've been put there.

Well, that was a dismal failure. Not quite -- we can put all the stuff
in a `vertical box' (which is a primitive sort of a parbox) while we're
working on it and then let it out when we're finished. It's called a
vertical box, because things are stacked up in it vertically (the same
way pages are built up).

The following definitions ought to be OK. I'm going to use mainly LaTeX
commands (which is unusual for me) so as to aid understanding.

All paragraphs with this odd formatting will be put into an
`oddparagraphs' environment. This is the thing to define first. The
beginning bit will just start putting everything into a vertical box.
The end will just empty the vertical box onto the page.

\newenvironment{oddparagraphs}{%
\dimen 0=\prevdepth% % Remember outer \prevdepth
\setbox 0=\vbox\bgroup% % Start building a vertical box
\kern 0pt% % This inserts correct \parskip space
\prevdepth=\dimen 0% % Set up \prevdepth inside the box
}{%
\par% % End the final paragraph
\global\dimen 1=\prevdepth% % Remember final \prevdepth
\egroup% % End the vertical box
\unvbox 0% % Spew out the box
\prevdepth=\dimen 1% % Set the \prevdepth correctly
\relax% % Stop parsing numbers
}

That's easy enough, apart from the messing with \prevdepth -- this makes
sure that the interline spacing comes out at least approximately right.
Now to actually handle the strange formatting. The command \suspendpar
will `suspend' a paragraph while we work on it. It'll use the maths
display trick from above to find how wide the last line was. It then
removes the display in a disinctly unsavoury way.

\newlength\suspendparwidth
\newcommand\suspendpar{%
$$% % Start display
\global\suspendparwidth=\predisplaysize% % Read line width
\global\advance\suspendparwidth by -2em% % Adjust slightly
$$% % End the display
\par% % Come out into vertical mode
\unskip% % Remove \belowdisplayskip
\unpenalty% % Remove \postdisplaypenalty
\setbox 0=\lastbox% % Remove the display box
\skip 0=\lastskip% % Get size of baselineskip glue
\advance\skip 0 by -\baselineskip% % Deduce value of \prevdepth
\unskip% % Remove \baselineskip glue
\unskip% % Remove \abovedisplayskip glue
\unpenalty% % Remove \predisplaypenalty
\vskip\skip 0% % Move back to previous baseline
\relax% % Stop parsing a number
}

That wasn't too bad, now, was it?

All we need to do now is to resume a suspended paragraph.

\newcommand\resumepar{%
\par% % End the previous paragraph
\noindent% % Don't indent this paragraph
\hskip-\leftskip% % Counteract \leftskip glue
\kern\suspendparwidth% % Indent by correct amount
\hspace{1em plus 10pt}% % Insert some stretchy space
}

The \hspace there is to provide a little separation between the width of
the suspended paragraph and the start of the resumed one (which I think
is the right thing to do), and to allow a line break just there (which
is definitely right -- otherwise things will look really ugly). The
stretchiness avoids problems with very short first lines looking really
horrible.

Now an example of how to use all of this:

This is some text
which goes on for quite a while
just to wrap around onto the next
line nicely, so I can see what's
going on. I think that should be
enough. Text, text, glorious text.

\begin{oddparagraphs}

I want to have a nice neat
formatted paragraph, just like

LaTeX normally does. \suspendpar

Then I want to put some
arbitrary text in the middle.

\resumepar Then I


want a subsequent paragraph
to begin so that the leading
line is indented just beyond
where the last line in the
previous formatted paragraph
ended, in a fairly automated
fashion.

\end{oddparagraphs}

This is some text
which goes on for quite a while
just to wrap around onto the next
line nicely, so I can see what's
going on. I think that should be
enough. Text, text, glorious text.

And some tips:

* Since the environment stores all the text in a box, it uses up lots
of memory. Try to split large chunks of text into smaller
environments.

* Good luck.

I've tested the code a bit (no matter what the .sig says ;-) ) with
various settings of things like \leftskip and \parskip, and it looks
like it's working OK. If it doesn't work, play with it. I'm not going
to support this code or be at all nice like that.
--
(` t r a y l i g h t / `Beware of bugs in the above code; I
,_) cs...@csv.warwick.ac.uk / have only proved it correct, not actually
/ tried it.'
Mark Wooding / Donald Knuth


Peter Schmitt

unread,
May 9, 1996, 3:00:00 AM5/9/96
to

>If you are prepared to do some adjusting `by hand' there is an
>easy solution:
[]

>Then you can say, e.g.,
> \SkipIndent {4cm}
>However, you will have to adjust the skip given in the command, if there
>are underfull or overfull boxes because of lack of freedom.
>A more complicated approach would be to use `invisible fonts'
[]

After having posted this yesterday I realized that my approach was
unnecessarily complicated.
There is an easy solution which does just what was wanted:

The problem is just to leave exactly one line of white space
where the linebreak may occur everywhere.
If you build up the line by sufficiently small empty boxes
TeX will automatically do this for you:

\def\SkipIndent {\unskip \bgroup
\vadjust{\vskip\parskip}\dimen0 .015625\hsize
\def~{\hskip0pt\hbox{\hskip\dimen0}}%
\edef~{~~~~}\edef~{~~~~}~~~~%
\hskip0pt \vadjust{\nobreak}%
\egroup \ignorespaces }

Remarks:
- it is assumed that - as usual - the tilde ~ already is an active character.
- \hsize is divided into 64 equal parts
- the first \vadjust inserts \parskip to imitate a \par
- the second \vadjust prevents a line break after the first line of the
second paragraph
( linebreaks before the last line of the first paragraph are possible )
- if the first paragraph ends flush right then this will produce an empty
line - if this is not intended then suitable adjustments have to be made

Peter

Reply all
Reply to author
Forward
0 new messages