15

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.

6
  • 1
    A line break makes more sense to me. Why do you want a paragraph break? Commented Mar 2, 2011 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. Commented Mar 2, 2011 at 1:59
  • Okay, you basically just want what \\ does. Commented Mar 2, 2011 at 2:11
  • 1
    Yeah, except for \\ being a mandatory linebreak. Commented Mar 2, 2011 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. Commented Mar 2, 2011 at 2:26

3 Answers 3

9

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.

8
  • 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? Commented Mar 2, 2011 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. Commented Mar 2, 2011 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.) Commented Mar 2, 2011 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. Commented Mar 2, 2011 at 5:37
  • 1
    I've used the \hskip solution to get DOIs and arXiv IDs onto a separate line, but in some situations two skips end up on the same line and the glue is divided equally among them. I found that \hfil\penalty0\hfilneg inserts the glue only where it is needed and is a tad more elegant IMHO. Commented Jan 9, 2018 at 18:45
7

Classical solution of given task is \nobreak\hfil\penalty0 \hfilneg. If the line is not broken in the \peanlty0 then \hfil+\hfilneg results to nothing. If the line is broken in \peanlty0 then \hfil is used at the end of the first line but \hfilneg is discarded because it is "discarable item" (from TeX point of view).

3
  • 1
    I did not know about \hfilneg. Nice answer! Is there a reason you use \penalty0 instead of \allowbreak? Commented Feb 23, 2021 at 21:37
  • 1
    No, there is no reason. I prefer to use primitives (I don't need to remember many other control sequences), but there are usable shortcuts: \nobreak instead of \penalty10000, for instance). Commented Feb 24, 2021 at 6:41
  • In one place I did this, the line doesn't stretch out all the way. Is this because the line is "underfull" or because of some artifact of this workaround? Commented Feb 8, 2023 at 19:53
0

I propose surrounding your \url with glue and use \allowbreak (mentioned in the comments). Specifically,

\hspace{\stretch{.001}}\allowbreak\url{___}\hspace{\stretch{1000}}\mbox{}

should suffice. Warning: this answer assumes the url is placed at the end of the \bibitem.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.