9

I want to write source like

Lorem ipsum dolor sit amet. \smallnote{Smaller.}

and have it render so that

  • if there is enough room for a \parindent plus the start of the \smallnote (the first word, or perhaps up to the first hyphenation point, in smaller type), then there will be a \parindent-sized whitespace and then the note will appear in the same paragraph;
  • or, if there isn’t room, the note appears in a new paragraph entirely (or after a line-break with a \parindent space at the start of the new line).

The following illustrations (which I faked) show what I mean:

with run-on line

with new paragraph

How is it possible to do this with TeX spacing?

2
  • 2
    do you mean \parskip here (that is the vertical space between paragraphs, but you seem to mean a horizontal space (\parindent perhaps?) May 31, 2015 at 17:54
  • Whoops, yes, I do. I always make that mistake. Fixed, thanks! May 31, 2015 at 17:56

4 Answers 4

10

enter image description here

you can use a hidden display math to measure the last line:

\documentclass{article}

\def\a{One two three four five six. }
\def\b{\a zzzzzz \a gg \a gg }

\def\smallnote#1{\xsmallnote#1 \zsmallnote}
\def\xsmallnote#1 #2\zsmallnote{%
{\abovedisplayshortskip0pt\abovedisplayskip0pt
 \belowdisplayshortskip0pt\belowdisplayskip0pt
$$\global\dimen1\predisplaysize$$\par}%
\sbox0{\small#1}%
\ifdim\dimexpr\dimen1-2em+\parindent+\wd0>\linewidth
\typeout{^^J!!! not enough room on \the\inputlineno^^J}%
\vskip-\baselineskip
{\small #1 #2\par}%
\else
\nobreak
\vskip-\glueexpr\baselineskip+\parskip\relax
\typeout{^^J!!! is enough room on \the\inputlineno^^J}%
{\small\vskip-\baselineskip\hspace*{\dimen1}#1 #2\par}
\fi}



\begin{document}


\b\b\smallnote{verylongword two three four five six seven eight
AAA BBB CCC DDD EE FF GG}

\bigskip

\b\b\a zz zz\smallnote{verylongword two three four five six seven eight}

\bigskip

\b\b\smallnote{verylongword two three four five six seven eight
AAA BBB CCC DDD EE FF GG with a long multiline not \b\b}

\end{document}
4
  • This is close, but the baseline of the note is not lined up with the baseline of the preceding paragraph in the ‘is enough room’ case. This is causing the ascenders of the following smallnote line to clash with the ascenders of the last line of the main paragraph. May 31, 2015 at 23:28
  • @DavidP.Kendal oh because it was getting late and I forgot to account for the different size baselineskip after the font change, will fix it later today, no time now:-) Jun 1, 2015 at 7:25
  • @DavidP.Kendal fixed the code to subtract one large and one small baseline, rather than two large, and updated example with some descenders and multi-line note. Jun 1, 2015 at 17:47
  • Oops, I did not see this before accepting the other answer. Both seem pretty good to me, but I guess this one wins because it sets with the correct line spacing for the selected note font size. Jun 1, 2015 at 18:02
8

This question reminds me of the “Mathematical Reviews example” that you can find on page 106 of The TeXbook (second double dangerous bend paragraph): indeed, rather than the unnecessarily complicated and, above all, inherently unsafe test on \predisplaysize, I would use that approach, which is much more straightforward and reliable.

The reason for which the test for the value of \predisplaysize cannot be trusted, in general, is explained on page 188, second (double dangerous bend) paragraph. In particular, with e-TeX, simply activating the \lastlinefit feature can cause this test to fail.

In the following code, a command named \cleverparindentspace is defined: you use this command to insert into the current paragraph a space of width \parindent which is “clever” in the sense that it starts a new line if the text following it does not comfortably fit into the remainder of the same line -- just what you asked, if I understood well. Anyway, once you have got the general idea, you can fine tune this command to your needs; in particular, you can calibrate TeX’s propensity to choose the “new line” alternative by changing the value of the \penalty. The code also demonstrates the unreliability of the \predisplaysize test.

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}

\newcommand*{\cleverparindentspace}{%
  \unskip
  \nobreak \hfil \penalty1000 \hfilneg \indent
}

\lastlinefit = 750

\begin{document}

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  One two three four five six seven eight.\cleverparindentspace
{\footnotesize\bfseries Here it is!}

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  One two three four five six seven eight.  With a few words
added.\cleverparindentspace {\footnotesize\bfseries Here it is!}

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  One two three four five six seven eight.  With some more words
added.\cleverparindentspace {\footnotesize\bfseries Here it is!}

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  One two three four five six seven eight.  This one is just a tiny
bit longer:~a.\cleverparindentspace {\footnotesize\bfseries Here it is!}

% But consider the following:

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  One two three four five six seven eight.  This one is just a tiny
bit longer: a.\cleverparindentspace {\footnotesize\bfseries Here it is!}

% You shouldn't trust \predisplaysize:

One two three four five six seven eight.  Some words.  Some more words.  How
long is this going to last?  One two three four five six seven eight.  This is
incredibly boring, isn't it?  (That was actually a quotation from \textsl{The
\TeX book}.)  The pre-display line.
$$\verb"\predisplaysize"=\mbox{\the\predisplaysize}$$

\end{document}

Output:

Output of the above code

2
  • the predisplaysize test isn't "unreliable" it works or not in predictable cases (notably \parfillskip needs to be infinite) The main disadvantage of balancing penalties/glue as here is that as you are using a single paragraph you are restricted to a single baselineskip so the small text note is set on the full baseline. Jun 1, 2015 at 16:54
  • Thanks! This works well. I’m not too bothered about it setting on the full baseline. Jun 1, 2015 at 17:57
5

It's not really possible to reliable measuring the last line of a paragraph without doing it inside a \vbox.

Here's a solution with an environment.

\documentclass{article}

\newenvironment{addsmallnote}
 {\par\edef\tpd{\the\prevdepth}\setbox0=\vbox\bgroup\prevdepth=\tpd}
 {}
\makeatletter
\newcommand{\smallnote}[1]{\unskip\do@smallnote#1 \@nil}
\def\do@smallnote#1 #2\@nil{%
  \par
  \setbox2=\lastbox
  \setbox2=\hbox{\unhbox2\unskip}% remove the \parfillskip glue
  \setbox4=\hbox{\itshape#1\/}%
  \ifdim\dimexpr\wd2+\wd4+\parindent>\hsize
    \nointerlineskip\box2
    \nobreak
    {\interlinepenalty=\@M \footnotesize\itshape #1 #2\par}
  \else
    \parindent=\dimexpr\parindent+\wd2
    \nointerlineskip\box2
    \nobreak
    {\interlinepenalty=\@M \footnotesize\itshape #1\vadjust pre{\vskip-\baselineskip} #2\par}
  \fi
  \egroup
  \unvbox0
}
\makeatother

\begin{document}

This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.

\begin{addsmallnote}
This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.
\smallnote{Here is a small note}
\end{addsmallnote}

\begin{addsmallnote}
This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  A test.
\smallnote{Here is a small note}
\end{addsmallnote}

\begin{addsmallnote}
This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.
\smallnote{Here is a small note that runs over and over in order to
fill much more than just the rest of a line and part of the next
line, I hope this is sufficient.}
\end{addsmallnote}

This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.

\end{document}

The last line is split off, reboxed and measured. Then a decision is made based on its length and the length of the first word in the note. If the first word (plus the parindent) doesn't fit, a new paragraph is set normally at \footnotesize, otherwise the note is set with a parindent equal to the normal parindent plus the width of the last line; a negative skip equal to \baselineskip is inserted to cover our tracks.

No page break can be taken between the paragraph and the note, until the note itself has finished.

enter image description here

3
  • Be careful, egreg: your claim that no page break can occur between the paragraph and the note is false: indeed, given the preceding \widowpenalty, the \parskip glue between the paragraph and the note is a pretty inviting breakpoint. And a page break here would ruin your clever trick with the paragraph indentation. I haven’t got time to check, now, but I think you should emit \nobreak \vskip -\baselineskip before leaving vertical mode to typeset the note (the \vskip is to avoid depending on pdfTeX’s \vadjust pre :-) .
    – GuM
    Jun 1, 2015 at 17:09
  • There was a missing \nobreak after the second \box2, I guess.
    – egreg
    Jun 1, 2015 at 17:11
  • That is exactly what I was suggesting.
    – GuM
    Jun 1, 2015 at 17:13
3

Here, I put a \kern of size \parindent and the first word of the small note into a box (to keep them together), and follow with the rest of the note. I also allow a break before the \kern, if needed.

I made the small note \bfseries just to help set it off.

EDITED, based on Gustavo's comment, to insert an \hfil prior to the \allowbreak, so that a linebreak would result in a ragged end prior to the small note.

\documentclass{article}
\newcommand\smallnote[1]{\smallnotehelp\expandafter\kern\the\parindent#1\relax}
\def\smallnotehelp#1#2\relax{\hfil\allowbreak%
  {\bfseries\small\mbox{#1}#2}}
\begin{document}
This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a big test.%
\smallnote{here is the small note}

This is a test.  This is a test.  This is a test.  This is a test. 
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  This is a test.
This is a test.  This is a test.  This is a test.  A test.%
\smallnote{here is the small note}
\end{document}

enter image description here


2
  • It’s not clear from the question whether, in case of a line break, the line before the note should end flush against the right margin or not. In my answer I assumed that a \hfil was desired in that case.
    – GuM
    Jun 1, 2015 at 13:57
  • @GustavoMezzetti Thanks for pointing out that interpretation. I'll revise accordingly. Jun 1, 2015 at 14:20

You must log in to answer this question.

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