# Optional but encouraged line break + \hfill

How would I write a macro (to be placed immediately before every URL in a bibliography) whose effect is to tell TeX

1. This is a good place to insert a line break, but breaking the line here is not required.
2. If (and only if) you break the line here, insert a \hfill (or maybe a \par, I'm not sure which makes more sense) immediately before the line break.

I tried \discretionary{\hfill}{}{}\penalty-500\relax which gave me a bunch of "Improper discretionary list" errors, and I also tried \discretionary{\par}{}{}\penalty-500\relax which didn't give me any errors but also didn't seem to have any effect.

(Also I'm not sure if \penalty is how you encourage a line break.)

(What I really want is for TeX to insert a paragraph break before the URL if and only if the URL doesn't fit onto the space remaining in the current line, but -- after that break happens -- not interfere with url.sty's intra-URL line breaking. But I suspect this is not even possible, whereas what I described above, I'm pretty sure is possible, I just don't know how to do it.)

EDIT: Minimal-ish example of overfull hboxes with TH's currently suggested code:

\documentclass[twocolumn]{article}
\usepackage[hyphens]{url}
\usepackage[letterpaper,margin=1in]{geometry}
\begin{document}
\urlstyle{same}

\begin{thebibliography}{10}
\let\oldurl\url
\makeatletter
\renewcommand*\url{%
\begingroup
\let\do\@makeother
\dospecials
\catcode{1
\catcode}2
\catcode\ 10
\url@aux
}
\newcommand*\url@aux[1]{%
\setbox0\hbox{\oldurl{#1}}%
\ifdim\wd0>\linewidth
\strut
\\
\vbox{%
\parindent=0pt
\kern-\lineskip
\raggedright
\strut\oldurl{#1}%
}%
\else
\hskip0pt plus\linewidth
\penalty0
\box0
\fi
\endgroup
}
\makeatother

ThinkerMade. (2008) {How to Tell if a User is Signed in to Facebook and Other
Services}. Blog entry.
\end{thebibliography}
\end{document}


Complaint:

(./argh.tex (/usr/share/texmf-texlive/tex/latex/base/article.cls
Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
(/usr/share/texmf-texlive/tex/latex/base/size10.clo))
(/usr/share/texmf-texlive/tex/latex/ltxmisc/url.sty)
(/usr/share/texmf-texlive/tex/latex/geometry/geometry.sty
(/usr/share/texmf-texlive/tex/latex/graphics/keyval.sty)
(/usr/share/texmf-texlive/tex/generic/oberdiek/ifpdf.sty)
(/usr/share/texmf-texlive/tex/generic/oberdiek/ifvtex.sty)) (./argh.aux)
*geometry auto-detecting driver*
*geometry detected driver: pdftex*

Overfull \hbox (20.5556pt too wide) in paragraph at lines 40--43
[]
[1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./argh.aux) )


This is not just a cosmetic problem; the URL extends into the right margin.

-
A line break makes more sense to me. Why do you want a paragraph break? – TH. Mar 2 '11 at 1:43
When the URL is split onto its own line, I don't want the text on the line before the URL to be justified (because this looks terrible, with giant spaces between words). A paragraph break does that, but if there's a way to get that effect for just one line in the middle of a paragraph, that would be fine too. – zwol Mar 2 '11 at 1:59
Okay, you basically just want what \\ does. – TH. Mar 2 '11 at 2:11
Yeah, except for \\ being a mandatory linebreak. – zwol Mar 2 '11 at 2:14
Right. I meant to say that when the url is to long to fit on the line, you want it to break like \\ does. – TH. Mar 2 '11 at 2:26

This solution checks if the url is longer than the line width. If it is, then it inserts \\ (since there is no way it can fit on a line) and then typesets the url. If it isn't larger, then it will fit on a line, so we typeset it as a box with a stretchable space before it. If the box does not fit on the line, then the space will stretch to fill the rest of the line so the line won't be underfull and the url will appear on the next line.

\documentclass[twocolumn]{article}
\usepackage{lipsum}
\usepackage{url}

\let\oldurl\url
\makeatletter
\renewcommand*\url{%
\begingroup
\let\do\@makeother
\dospecials
\catcode{1
\catcode}2
\catcode\ 10
\url@aux
}
\newcommand*\url@aux[1]{%
\setbox0\hbox{\oldurl{#1}}%
\ifdim\wd0>\linewidth
\strut
\\
\vbox{%
\hsize=\linewidth
\kern-\lineskip
\raggedright
\strut\oldurl{#1}%
}%
\else
\hskip0pt plus\linewidth
\penalty0
\box0
\fi
\endgroup
}
\makeatother
\begin{document}
\lipsum[1]

Here is some text
\url{http://www.example.com/~example/foo/bar/baz/index%20here.html}

Here is some text \url{http://example.org/index.html}

Short \url{http://example.org}
\end{document}


Edit:
I modified it to try to prevent the underfull hbox as well as deal with specials in the argument better than just using \detokenize.

-
Works great, thanks! Only problem is now I get an "Underfull \hbox (badness 10000)" complaint for every URL that needs more than one line. Harmless, but kinda irritating ... any idea why? – zwol Mar 2 '11 at 3:56
@Zack: I provided a better solution that should solve that problem as well as deal with hyperref and % in the url. I think I got the spacing right, but I'm not completely sure. – TH. Mar 2 '11 at 4:46
Wow, this is bizarre. With your revision, instead of underfulls I get over fulls. Overfull by precisely 18.32794pt each time. It is as if \linewidth is too large, but I checked my class file's definition of thebibliography and it seems to be doing that correctly. (Also I had to put the catcode of % back to 14 to cope with BibTeX's habit of breaking very long lines with %-newline; I don't need URL %-encoding, fortunately.) – zwol Mar 2 '11 at 5:31
... now I'm even more confused. I set \@tempdima to \linewidth minus 18.32794pt (at the beginning of \url@aux), replaced every instance of \linewidth in your code with \@tempdima, and wrapped the \vbox in a \hbox to\@tempdima ... and the overfull hboxes are now exactly twice as overfull as they used to be. – zwol Mar 2 '11 at 5:37
The width of the \vbox isn't constrained by anything that happens outside of it. I was going to say it sounded like you omitted the \parindent=0pt, but that is actually done in \raggedright so I didn't need to use it. Can you add a minimal example to your question so that I can see the misbehavior? – TH. Mar 2 '11 at 6:07