[Tex/LaTex] Optional but encouraged line break + \hfill

discretionaryline-breaking

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

\bibitem{thinkermade08focus}
ThinkerMade. (2008) {How to Tell if a User is Signed in to Facebook and Other
  Services}. Blog entry.
  \url{http://replay.waybackmachine.org/20081020072934/http://www.thinkermade.com/blog/2008/07/how-to-tell-if-a-user-is-signed-in-to-facebook-and-other-services/}
\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.

Best Answer

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.

Related Question