8

I want to typeset a booklet of poetry, in Plain. Thus far I've been able to make TeX obey spaces and lines with the following code:

\def\startline{\par\noindent}
\obeylines\obeyspaces
\let^^M=\startline
\raggedright
\everypar{\hangindent=2em}

However, the macros swallow the double ^^M that should mark the space between stanzas.

  On the white sand
Of the beach of a small island
In the Eastern Sea

  I, my face streaked with tears,
Am playing with a crab

   – Ishikawa Takuboku

How can I teach TeX to catch the double line feeds to produce the vertical space needed?

tanka

Addendum

@egreg and @Steven's answers almost do the job, but in the simple case the vertical space is determined by the \baselineskip of \par; to make the problem more interesting, let's say I borrow the definition of \@ifnextchar from LaTeX and I define

\parindent=0em
\def\stanza{\leavevmode\vskip 1ex plus 1ex minus 1ex}
\long\def\normalpar{\expandafter\par}
\long\def\checkpar{\@ifnextchar^^M\stanza\normalpar}
\obeylines\obeyspaces
\let^^M=\checkpar%
\raggedright%
\everypar{\hangindent=2em}%

As you see, at every ^^M I'm trying to check \@ifnextchar is another ^^M; if so, add stanza vertical space defined in \stanza; otherwise, add a regular \par. My problem is that I don't know how to tell the processor that the next token to check for is precisely the line feed character. The idea is to avoid the default vertical space assumed by the \baselineskip on regular lines.

5
  • If I get it right, both @Steven and @egreg's first answers are based on the idea of entering horizontal mode immediately at the end of the current paragraph or at the beginning of the next one, either by simply saying \leavevmode or by inserting a \hbox; however, in either case the vertical space is assumed to be determined by \baselineskip. Is there a way to get some control on it? Am I asking a different question?
    – jarnosc
    Oct 28, 2015 at 18:59
  • For the addendum: move the definition of \checkpar after \obeylines. And remember % at the end of the line.
    – egreg
    Oct 29, 2015 at 7:50
  • I did as you suggested, and the stanza vertical spaces are added right, but the \obeyspaces is now ignored. Didn't figure out why.
    – jarnosc
    Oct 29, 2015 at 22:44
  • You are using the wrong approach: if you remove markup, you give no clue for how to decide what a blank line should be. Note that you can't test a blank line by checking whether ^^M immediately follows ^^M, because spaces could be on that line. But if you remove spaces, you can't have indentation on the first verse of a stanza. Well, it can be done, but is it worth the effort?
    – egreg
    Oct 29, 2015 at 22:56
  • But then you have no indentation where specified.
    – egreg
    Oct 29, 2015 at 23:27

3 Answers 3

4

If you want to have an empty line where indicated by the blank line, add \leavevmode to \startline. Rather than issuing \noindent each time, it's better to set \parindent to zero.

Also some % are missing after \obeylines starts having effect; you couldn't see the issue with your code, just because a \par in vertical mode gave nothing.

\parindent=0pt
\def\startline{\par\leavevmode}
\obeylines\obeyspaces
\let^^M=\startline%
\raggedright%
\everypar{\hangindent=2em}%

  On the white sand
Of the beach of a small island
In the Eastern Sea

  I, my face streaked with tears,
Am playing with a crab

   --- Ishikawa Takuboku

\bye

enter image description here

The next version requires that a blank line is really empty, so you can control also the space between stanzas (and the final attribution).

Maybe one can also cope with taking care of spaces, but it's difficult and not worthy the effort. Your approach is wrong to begin with: no mark up means no flexibility.

\obeylines\obeyspaces
\parindent=0pt%
\def\endline{%
  \par%
  \let\savedspaces\empty%
  \futurelet\next\perhapseol%
}%
\def\perhapseol{%
  \ifx\next^^M%
    \let\nxt\newstanza%
  \else%
    \let\nxt\leavevmode%
  \fi%
  \nxt%
}%
\def\newstanza#1{\vskip50pt#1}% exaggerated to show the effect
\let^^M=\endline%
\raggedright%
\everypar{\hangindent=2em}%

  On the white sand
Of the beach of a small island
In the Eastern Sea

  I, my face streaked with tears,
Am playing with a crab

   --- Ishikawa Takuboku

\catcode`\^^M=5

\bye

enter image description here

0
5

Here I add a null \hbox to the \everypar. What this does is force two blank lines to be interpreted as \par\hbox{}\par rather than \par\par. In the latter case, TeX collapses it down to a single \par, which is not wanted here.

\def\startline{\par\noindent}
\obeylines\obeyspaces
\let^^M=\startline
\raggedright
\everypar{\hbox to 0pt{}\hangindent=2em}

  On the white sand
Of the beach of a small island
In the Eastern Sea

  I, my face streaked with tears,
Am playing with a crab

   -– Ishikawa Takuboku
\bye

enter image description here

0
0

So, a fairly general solution might be, assuming loading \@ifnextchar from miniltx.tex,

\input miniltx
\makeatletter
\parindent=0em
\def\stanzasp#1{\edef\@stanzasp{\vskip#1\relax}}
\def\normalpar{\par\leavevmode}
\obeylines\obeyspaces
\def\checkpar{\@ifnextchar^^M\@stanzasp\normalpar}%
\let^^M=\checkpar%
\raggedright%
\everypar{\hangindent=2em}%
\makeatother%
\stanzasp{2ex plus 1ex minus 1ex}

The macro \stanzasp takes a dimension as an argument; in this example it is set to 2ex plus 1ex minus 1ex, but you may adjust it according to your taste (or lack thereof).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .