1

I'm using code from The TeXBook to align some text to the right of the last line of the paragraph or to the of the next line if there isn't room on the last line of the paragraph. (See chapter 14, page 106 and implementation below.)

It works well, except there are situations when I have a section of text in an environment using \obeylines. This messes things up, since \obeylines inserts a paragraph break at the end of each line including the last line and the text to be aligned to the right always appears on a line by itself even if there is space for it on the previous line.

I can work around this by suppressing the paragraph break on the last line of the \obeylines section with a % on the end of the line.

But I'm after an automatic way that doesn't require me to do this.

Here's a MWE to play with.

The zzsection and olsection environments simulate environments I use in my document structure. I'd like to just modify code in these two environments, not the text within the environments. The olsection may occur with ordinary text above or below it. I.e., the only case that needs to be worked around is when a zzsection finishes with an olsection environment. Filler text is of arbitrary length and content. Hopefully that makes sense…

In this example, the third paragraph is the one that needs correcting.

\documentclass{article}

\usepackage{lipsum}

\newcommand{\zz}{%
  {\unskip\nobreak\hfil\penalty50
   \hskip2em\hbox{}\nobreak\hfil\textbf{Filler text}%
   \parfillskip=0pt \finalhyphendemerits=0 \par}}

\newenvironment{zzsection}{}{\zz}
\newenvironment{olsection}{\obeylines}{}

\begin{document}

\begin{zzsection}
  \lipsum[1]
\end{zzsection}

\begin{zzsection}
  \lipsum[5]
\end{zzsection}

\begin{zzsection}
  \begin{olsection}
    \lipsum[1]
  \end{olsection}
\end{zzsection}

\begin{zzsection}
  \begin{olsection}
    \lipsum[5]
  \end{olsection}
\end{zzsection}

\end{document}

Update

Henri Menke's code is almost perfect for me.

My actual document has a \leftskip 1cm inside the olsection environment. This isn't taken into account for the last line with his answer. i.e., this fails:

\begin{zzsection}
  \begin{olsection}
    \leftskip 1cm
    Some text.
    Some text.
    Some text.
  \end{olsection}
\end{zzsection}
3
+100

Just make obeylines look ahead for \end.

If there may be multiple blank lines before the \end you might need to skip these recursively. This is quite slow because it absorbs tokens one by one.

\documentclass{article}

\usepackage{lipsum}

\newcommand{\zz}{%
  {\unskip\nobreak\hfil\penalty50
   \hskip2em\hbox{}\nobreak\hfil\textbf{Filler text}%
   \parfillskip=0pt \finalhyphendemerits=0 \par}}

% Loosely adapted from ConTeXt
%
% Two stage indirection via \obeylineshandler is such that we can change
% \obeyedline at some later stage.
\newcommand*\obeyedline{\par}
\newcommand*\obeylineshandler{\obeyedline}
{\catcode`\^^M=\active % these lines must end with %
  \protected\gdef\obeylines{\catcode`\^^M\active \let^^M\obeylineshandler}%
  \global\let^^M\obeylineshandler} % this is in case ^^M appears in a \write

% Look ahead for \end and skip any ^^M on the way there
\makeatletter
{\catcode`\^^M=\active % these lines must end with %
\gdef\obeylineend{%
    \@ifnextchar\end{}{%
        \@ifnextchar^^M{%
            \expandafter\obeylineend\@gobble}{\par}}}}
\makeatother

\newenvironment{zzsection}{}{\zz}
\newenvironment{olsection}{\let\obeyedline\obeylineend\obeylines}{}

\begin{document}

\begin{zzsection}
  \lipsum[1]
\end{zzsection}

\begin{zzsection}
  \lipsum[5]
\end{zzsection}

\begin{zzsection}
  \begin{olsection}
    \lipsum[1]

  \end{olsection}
\end{zzsection}

\begin{zzsection}
  \begin{olsection}
    \lipsum[5]
  \end{olsection}
\end{zzsection}

\end{document}
| improve this answer | |
  • Ooh! This looks very promising. It doesn't quite work in my actual document, but I may be able to fix that. – David Purton Jul 10 at 2:48
  • @DavidPurton I can guess your problem is with multiple blank lines before the \end. See my updated answer for that. – Henri Menke Jul 10 at 2:59
  • I have a \leftskip 1cm in my olsection environment. This seems to be ignored on the last line. – David Purton Jul 10 at 3:00
  • Speed isn't a concern. These documents are short and this structure only appears rarely. – David Purton Jul 10 at 3:03
  • Your initial \obeylineend macro gives better results in my actual code. i may need to ask a new question with a little more detail of what actually is in the olsection environment. (It's quite similar to the psalm environment at tex.stackexchange.com/a/360322/87678) – David Purton Jul 10 at 3:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.