# How to display only certain lines of a paragraph?

From reading Knuth's TeX Book (Chapter 14 How TeX Breaks Paragraphs into Lines), I understand that entire paragraphs are read in and then "massaged" by the "line-breaking algorithm" in an optimal way (p 91):

One of typesetting system's chief duties is to take long sequences of words and to break it up into individual lines of the appropriate size. ... TeX chooses breakpoints in an interesting way that considers each paragraph in its entirety; the closing words of a paragraph can actually influence the appearance of the first line.

As a consequence, I assume that it flushes out the lines on-by-one after performing the optimization on a per-paragraph basis. Is it possible to interrupt this flushing of lines and say only output specific lines of the paragraph? I guess, almost similar to the way paragraphs are broken across pages.

For example, by means of defining an environment (say) showlines that one can use in the following way:

\begin{showlines}[lines=2]
One of typesetting system's chief duties is to take long sequences
of words and to break it up into individual lines of the appropriate size.
\TeX\ chooses breakpoints in an interesting way that considers each paragraph
in its entirety; the closing words of a paragraph can actually influence
the appearance of the first line.
\end{showlines}


And TeX would only output the first two lines of the traditional output (possibly discarding the rest):

Note: Of interest here is to preserve the typesetting after line-breaking optimization has occurred, even in the case of hyphenation, since the tie should be with the shipout of lines. Of course, if there is another method of doing this (for example, possible sub-optimal line-breaking on a line-by-line basis), that would also work.

As a bonus, not just allowing to show the first n lines as in the example above (via [lines=n]), but allowing to show any combination of lines from the paragraph using notation like: [lines={1,4-5}] or [lines={-2}] for the last two lines.

-

A Lua(La)TeX solution is missing. Not anymore:

 \documentclass{article}
\usepackage{luatexbase}
\usepackage{luacode}
\begin{luacode}
twolines = function ( head )
local linecounter = 0

linecounter = linecounter + 1
end

if linecounter > 1 then
return true
end

end
return true
end

\end{luacode}

\begin{document}
\hsize 4in
A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my
whole heart. I am alone, and feel the charm of existence in this spot, which was created for the bliss of souls like mine. I am
so happy, my dear friend, so absorbed in the exquisite sense of mere tranquil existence, that I neglect my talents. I should be
incapable of drawing a single stroke at the present moment; and yet I feel that I never was a greater artist than now.
\end{document}


This adds a callback function (twolines) to the post_linebreak_filter which counts the hlists (node id 0) found in a paragraph and just removes everything after the second hlist from the paragraph (a vlist - that is what orig_head is pointing to - not needed in this example).

The drawbacks:

• It applies to every paragraph. To circumvent this, activate the callback only when needed. See the chickenize package by Arno Trautmann.
• It has a memory leak. The nodes after the second hlist are still in a structure. On needs to call node.free(...) to remove the nodes from memory. See the reference manual (chapter 4, node library).
• It doesn't work with iTeX [tinkle a bell].

Edit: here is a full solution, including the environment:

\documentclass{article}
\usepackage{luatexbase}
\usepackage{luacode}
\begin{luacode}
twolines = function ( head )
local linecounter = 0

linecounter = linecounter + 1
end

if linecounter >= showlinescount then

end

lastline.next = nil
return true
end

end
return true
end
\end{luacode}

\newenvironment{showlines}[1]
{\directlua{showlinescount = tonumber('#1')
{\par
\directlua{luatexbase.remove_from_callback("post_linebreak_filter","twolines")}}

\begin{document}
\hsize 4in

\newcommand\sample{A wonderful serenity has taken possession of my entire soul, like these sweet mornings
of spring which I enjoy with my whole heart. I am alone, and feel the charm of existence in this spot,
which was created for the bliss of souls like mine. I am so happy, my dear friend, so absorbed in the exquisite
sense of mere tranquil existence, that I neglect my talents. I should be incapable of drawing a single
stroke at the present moment; and yet I feel that I never was a greater artist than now.}

\begin{showlines}{3}
\sample
\end{showlines}
\sample
\end{document}


This still doesn't work with iTeX [tinkle a bell] yet. But it has no memory leak anymore and it offeres a showlines environment.

-
You describe a fix for the memory leak. Why not implement it at once? –  Andrey Vihrov Sep 11 '11 at 12:45
@Andrey I like clean examples. Perhaps I add another (full) answer - but this should be left as an exercise to the reader :) –  topskip Sep 11 '11 at 14:35
@Andrey done :) –  topskip Sep 11 '11 at 15:09

When TeX breaks a paragraph into lines, it constructs a hbox for each line. This stack of hboxes can be placed in a vbox (so that there is actually a first hbox) and analyzed one hbox at a time using the \lastbox operation.

The following code was heavily influenced by TeX by Topic, subsection 5.9.6.

\documentclass{article}

\usepackage{lipsum}

\newbox\linebox

\newcount\mycount
\def\processline{% Underline every second line
\ifodd\mycount
\underline{\box\linebox}%
\else
\box\linebox
\fi}

\def\splitlines{%
\setbox\linebox\lastbox
\ifvoid\linebox
\noindent\ignorespaces
\else
\unskip\unpenalty
\begingroup\splitlines\space\endgroup
\processline
\fi}

\long\def\doit#1{\vbox{#1\par\splitlines}}

\begin{document}

\doit{\lipsum[1]}

\end{document}


You can redefine \processline to suit your needs. For example, it might discard lines conditionally or \unhbox them for further changes. Selecting lines by number is now a matter of going through the hboxes and comparing numbers. It might be necessary to dissect the vbox twice.

-

The following code outputs the number of lines stated in the argument, provided all the lines have the same height (more precisely, the baselines are uniformly spaced):

\documentclass[a4paper]{article}

\makeatletter
\newbox\wernerboxa
\newbox\wernerboxb

\newenvironment{showlines}[1]
\setbox\wernerboxa=\vbox\bgroup}
{\egroup\setbox\wernerboxb=\vsplit\wernerboxa to\how@many\baselineskip
\vbox{\unvbox\wernerboxb}}
\makeatother

\usepackage{lipsum}

\begin{document}
\begin{showlines}{5}
\lipsum
\end{showlines}
\end{document}


Repeating the \vsplit operation recursively can solve the problem of showing a specified list of lines.

Let's look at another approach that can cope with the case when there are higher objects in a line.

If the paragraph has no fancy things, but only plain text, a modification of an answer of mine will underline each line of the paragraph; actually the rule is added by the macro \add@rule, so it's possible to modify it in such a way that it draws the rule only if certain conditions are satisfied; the final number of lines is available in the macro \how@many. This works bottom up; it shouldn't be so complicated to add a check whether a line must be underlined.

\documentclass[a4paper]{article}
\usepackage{lipsum}

\makeatletter

\newif\ifboxended
\newbox\wernerbox
\newenvironment{werner}
{\par\setbox\wernerbox=\vbox\bgroup}
{\par\xdef\how@many{\the\prevgraf}\egroup
\message{The box has \how@many\space lines}%
\underlinevbox}

\def\underlinevbox{\begingroup\global\setbox\@ne=\box\voidb@x
\global\boxendedfalse
\setbox\z@=\copy\wernerbox\relax\dounderlinevbox}
\def\dounderlinevbox{%
\setbox\z@=\vbox{\unvbox\z@
\ifcase\lastnodetype
% char node (can't remove)
\or
% hlist node
\setbox\tw@=\lastbox
\or
% vlist node
\setbox\tw@=\lastbox
\or
% rule node (can't remove)
\or
% ins node (can't remove)
\or
% mark node (can't remove)
\or
\or
% ligature node (can't happen)
\or
% disc node (can't happen)
\or
% whatsit node (can't remove)
\or
% math node (can't remove)
\or
% glue node
\skip@=\lastskip\unskip
\def\next{\global\setbox\@ne=\vbox{\vskip\skip@\unvbox\@ne}}%
\or
% kern node
\dimen@=\lastkern\unkern
\def\next{\global\setbox\@ne=\vbox{\kern\dimen@\unvbox\@ne}}%
\or
% penalty node
\count@=\lastpenalty\unpenalty
\def\next{\global\setbox\@ne=\vbox{\penalty\count@\unvbox\@ne}}%
\or
% unset node (can't happen)
\or
% math mode node (can't remove)
\else
% empty list
\def\next{\global\boxendedtrue}
\fi
\next}
\ifboxended
\def\next{\unvbox\@ne\endgroup}
\else
\let\next\dounderlinevbox
\fi
\next}
\makeatother

\begin{document}
\begin{werner}
\lipsum[2]
\end{werner}
\end{document}


The code can be modified in order to output only specified lines. It should be noted that the dismantling happens from the bottom line up.

-
I'm not-so-much interested in underlining a specific line in a paragraph. I'm interested in only displaying the lines above the horizontal line in my example. Hence the question: " Is it possible to interrupt this flushing of lines and say only output specific lines of the paragraph? ... For example, by means of defining an environment (say) showlines, ... And TeX would only output the first two lines of the traditional output (possibly discarding the rest)" –  Werner Sep 10 '11 at 21:32