Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I need a macro that aligns an object against the right margin, on the current line if this leaves a space between the text and the object, and on the next line otherwise. No other material should appear on the same line as the object in the latter case.

Right alignment illustration

My first attempt (\tmarksi) seems to work, but it causes underfull hbox warnings if it occurs at the end of a paragraph (I don't understand why). The second attempt (\tmarksii) seems to insert an unwanted paragraph break. Therefore I tried locally setting \parskip to zero in the third attempt, but this doesn't work either.

Surely this should not be difficult; what am I missing?

\documentclass{article}
\setlength\parindent{0pt}
\setlength\parskip{2cm} %For illustration purposes
%
\newcommand\tmarksi[1]{\hspace*{\fill}~\mbox{[#1]}\newline}
\newcommand\tmarksii[1]{\hspace*{\fill}~\mbox{[#1]}\vskip0pt}
\newcommand\tmarksiii[1]{\hspace*{\fill}~\mbox{[#1]}\bgroup\parskip=0pt\parindent=0pt\par\egroup}
%
\begin{document}
The quick brown fox jumps over the lazy dog. \tmarksi{1}
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over \tmarksi{1}
the lazy dog.
\end{document}
share|improve this question
    
@Werner --- Done. –  Ian Thompson Jan 13 '12 at 17:11
    
I'm not getting any Overfull \hbox warnings with \tmarksi and that approach seems to be working fine. –  Werner Jan 13 '12 at 17:19
    
@Werner --- You need to insert a blank line after a \tmarksi. I'll edit the question later; I don't have time now. –  Ian Thompson Jan 13 '12 at 17:32
    
@Werner --- edited. –  Ian Thompson Jan 14 '12 at 13:20
    
@Frank --- edited. –  Ian Thompson Jan 14 '12 at 13:20
add comment

2 Answers

up vote 5 down vote accepted

You can use a variant of the "Bourbaki problem" in the TeXbook

\documentclass[convert,border=2]{standalone}

\newcommand{\tmark}[1]{%
  {{\unskip\nobreak\hfil\penalty50
  \hskip2em\vadjust{}\nobreak\hfil[#1]%
  \parfillskip=0pt \finalhyphendemerits=0 \par
  \penalty 10000 \parskip=0pt\noindent}}\ignorespaces}

\begin{document}
\begin{minipage}{150pt}\parindent=20pt\parskip=20pt
The quick brown fox jumps over the lazy dog.\tmark{1}
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over\tmark{1}
the lazy dog.

The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy \tmark{1}
the lazy dog.

The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy brown dog \tmark{1}

Another
\end{minipage}

\end{document}

This introduces a paragraph break, but also issues \noindent and \penalty 10000 that inhibits a page break. I've added also \parskip=0pt to cover our tracks. The minimum space between the end of text and the mark is 2em, play with it.

Note: the \parskip is set in the minipage just to show the effect. Also \parindent needs to be set, otherwise it's zero.

enter image description here

To get the text flush right in case the mark is moved to the next line, change the first \hfil into \hskip0pt. For a normal interword space as the minimum, change \hskip2em into \space.

The following version implements this and also avoids page breaks in case the mark is moved to the next line:

\newcommand{\tmark}[1]{%
  {{\unskip\nobreak\vadjust{\nobreak}\hskip0pt\penalty50 \space
  \vadjust{}\nobreak\hfil[#1]%
  \clubpenalty=0 \widowpenalty=0 \brokenpenalty=0
  \parfillskip=0pt \finalhyphendemerits=0 \par
  \penalty 10000 \parskip=0pt\noindent}}\ignorespaces}

There is a price to pay: we have less control of widow and club lines, but as Frank Mittelbach remarks in the comments it seems quite hard to comply with both necessities.

share|improve this answer
    
So if I want a normal interword space it should be \hskip\fontdimen2\font minus \fontdimen4\font, right? –  Ian Thompson Jan 14 '12 at 15:31
    
@IanThompson And plus \fontdimen3\font. –  egreg Jan 14 '12 at 15:40
    
Would that make any difference when there is a \hfil to the left? –  Ian Thompson Jan 14 '12 at 15:43
    
@IanThompson With \hfil instead of a non zero \hskip the space before the mark could well be zero. –  egreg Jan 14 '12 at 15:48
    
I mean the plus \fontdimem3\font. –  Ian Thompson Jan 14 '12 at 15:55
show 7 more comments

I assume you meant that \tmarksi generates an underfull hbox not an overfull one if it comes at the end of the paragraph. The reason for this behavior is that the \newline in that definition always starts another line in that paragraph and then the final line is fully empty. This is why in LaTeX \\ or \newline are introduced as line separators not as line endings (though many people try to use \\ \\ to get empty lines or extra space).

So, this means either you write two different commands for the two cases or you try something like this:

\newcommand\tmarksi[1]{\hspace*{\fill}~\mbox{[#1]}\penalty -9999 }

What is different here is that I used a penalty which is not quite an "always break here" so that the final breakpoint at the end of the paragraph will overwrite it. However, within the paragraph it should normally be sufficient, that is as long as you do not use explicit \linebreak commands. So take your pick.

share|improve this answer
    
Any hints on doing this with \discretionary? It seems like you should be able to get TeX to pick the breakpoint for you, but I didnt have any luck. –  Justin Bailey Jan 14 '12 at 0:59
2  
@Justin I think you are mistaken. \discretionary doesn't help you here. it can only consist of boxes characters and kerns (not flexible glue). What is needed is glue that pushes the mark to the right plus a breakpoint that ensures the line ends at this point. But the issue then is that a forced breakpoint just before \par` will result result in an empty extra line. One could of course try to look ahead to see if par is coming but that again is not failsafe either if it is hidden deeply inside a following command or environment. –  Frank Mittelbach Jan 14 '12 at 9:27
    
I'd add \unskip\space at the beginning of \tmarksi. Otherwise it's necessary to have a space before \tmarksi. –  egreg Jan 14 '12 at 18:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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