23

In answer to this question, Audrey offered an answer that works great with the authoryear option.

(Context: I'm trying to get the hyperlink in citations to include the name of the author, and not just the year. Audrey provided a solution that works with authoryear, and I'm trying to adapt it to work with authoryear-comp.)

I'm trying to adapt the answer to make it work with authoryear-comp. Here is what I tried (it doesn't work---I get an error message: Latex Error: ./biblatex.tex:96 Argument of \@secondoftwo has an extra }. Runaway argument?):

\renewbibmacro*{cite}{%
\printtext[bibhyperref]{% Enclose cite macro output in hyperlink
    \global\togglefalse{cbx:hyperref}% Prevent nested hyperlinks
  \iffieldundef{shorthand}
    {\ifthenelse{\ifnameundef{labelname}\OR\iffieldundef{labelyear}}
       {\usebibmacro{cite:label}%
    \setunit{\addspace}%
    \usebibmacro{cite:labelyear+extrayear}%
        \usebibmacro{cite:reinit}}
       {\iffieldequals{namehash}{\cbx@lasthash}
          {\ifthenelse{\iffieldequals{labelyear}{\cbx@lastyear}\AND
                       \(\value{multicitecount}=0\OR\iffieldundef{postnote}\)}
             {\setunit{\addcomma}%
              \usebibmacro{cite:extrayear}}
             {\setunit{\compcitedelim}%
              \usebibmacro{cite:labelyear+extrayear}%
              \savefield{labelyear}{\cbx@lastyear}}}
          {\printnames{labelname}%
       \setunit{\nameyeardelim}%
           \usebibmacro{cite:labelyear+extrayear}%
           \savefield{namehash}{\cbx@lasthash}%
           \savefield{labelyear}{\cbx@lastyear}}}}
    {\usebibmacro{cite:shorthand}%
     \usebibmacro{cite:reinit}}%
\global\toggletrue{cbx:hyperref}}
  \setunit{\multicitedelim}}

I don't fully understand how \cite works under authoryear-comp, so maybe someone who does can see a way to do this? (I'm assuming it's possible, since this is how hyperlinks are implemented in BibTeX.)

EDIT (in re: to Marco's comment): Here's a minimal example:

\documentclass{article} 
\usepackage[utf8]{inputenc} 
\usepackage[style=authoryear-comp]{biblatex} 
\usepackage[colorlinks]{hyperref} 
\bibliography{biblatex-examples} 


\newtoggle{cbx:hyperref}
\toggletrue{cbx:hyperref}

\DeclareFieldFormat{bibhyperref}{% Adapted from bibhyperref format in biblatex.def
\iftoggle{cbx:hyperref}
{\bibhyperref{#1}}
{#1}}


\renewbibmacro*{cite}{%
\printtext[bibhyperref]{% Enclose cite macro output in hyperlink
    \global\togglefalse{cbx:hyperref}% Prevent nested hyperlinks
  \iffieldundef{shorthand}
    {\ifthenelse{\ifnameundef{labelname}\OR\iffieldundef{labelyear}}
       {\usebibmacro{cite:label}%
    \setunit{\addspace}%
    \usebibmacro{cite:labelyear+extrayear}%
        \usebibmacro{cite:reinit}}
       {\iffieldequals{namehash}{\cbx@lasthash}
          {\ifthenelse{\iffieldequals{labelyear}{\cbx@lastyear}\AND
                       \(\value{multicitecount}=0\OR\iffieldundef{postnote}\)}
             {\setunit{\addcomma}%
              \usebibmacro{cite:extrayear}}
             {\setunit{\compcitedelim}%
              \usebibmacro{cite:labelyear+extrayear}%
              \savefield{labelyear}{\cbx@lastyear}}}
          {\printnames{labelname}%
       \setunit{\nameyeardelim}%
           \usebibmacro{cite:labelyear+extrayear}%
           \savefield{namehash}{\cbx@lasthash}%
           \savefield{labelyear}{\cbx@lastyear}}}}
    {\usebibmacro{cite:shorthand}%
     \usebibmacro{cite:reinit}}%
\global\toggletrue{cbx:hyperref}}
  \setunit{\multicitedelim}}

\DeclareCiteCommand{\textcite}% Adapted from \textcite command in authoryear.cbx
  {\boolfalse{cbx:parens}}
  {\usebibmacro{citeindex}%
  \printtext[bibhyperref]{% Enclose textcite macro output in hyperlink
    \global\togglefalse{cbx:hyperref}% Prevent nested hyperlinks
    \usebibmacro{textcite}%
    \iffieldundef{postnote}% Include closing parenthesis if no postnote
      {\ifbool{cbx:parens}
         {\bibcloseparen\global\boolfalse{cbx:parens}}
      {}}
   {}}%
 \global\toggletrue{cbx:hyperref}}
 {\ifbool{cbx:parens}
 {\bibcloseparen\global\boolfalse{cbx:parens}}
 {}%
  \multicitedelim}
 {\iffieldundef{postnote}
  {}
 {\usebibmacro{textcite:postnote}}}

\begin{document} 
A reference to \parencite{kastenholz,sigfridsson} and~\cite{sigfridsson}. 
\printbibliography 
\end{document}

I'm using references from the biblatex-example database. The error I get is this: Paragraph ended before \@secondoftwo was complete.

apc
  • 848
  • 7
  • 15
  • Please provide a full minimal example. If I change the style of Audreys answer I get 0 Erros – Marco Daniel Sep 05 '11 at 22:25
  • @Marco For context, refer to the comments here. I think the error is just omission of \makeatletter/makeatother. But on your end, you'll see a number of problems with the output. Also: apc is attempting to adapt the cite bib macro from authoryear-comp, which is different from the one in authoryear. – Audrey Sep 05 '11 at 22:54
  • @Audrey: In my opinion it is very bad to ask such unclear questions or question with: see link_1...link_n. The possibility with makeatletter is more a guess ;-) (no MWE). – Marco Daniel Sep 05 '11 at 23:09

2 Answers2

21

Both \cite and \textcite use \setunit inside the <loopcode> argument of \DeclareCiteCommand. Links will include punctuation if you simply wrap <loopcode> (or the cite and textcite bibliography macros) in \bibhyperref. Moreover printing of \setunit is deferred to the next \print* or \bibstring command. So it is difficult to ensure that this approach will create links that point to the correct item in the bibliography.

The following patches to cite will make a single link for labelname/label and labelyear+extrayear where appropriate. The patches to textcite will include the parentheses around labelyear+extrayear in the absence of prenote, postnote and citation lists. Otherwise separate links are applied, similar to the citation links obtained with natbib.

\documentclass{report}
\usepackage[style=authoryear-comp]{biblatex}
\usepackage{hyperref}
\usepackage{xpatch}

% Just for demo \ExecuteBibliographyOptions{maxcitenames=1}

% Combine label and labelyear links \xpatchbibmacro{cite} {\usebibmacro{cite:label}% \setunit{\printdelim{nonameyeardelim}}% \usebibmacro{cite:labeldate+extradate}} {\printtext[bibhyperref]{% \DeclareFieldAlias{bibhyperref}{default}% \usebibmacro{cite:label}% \setunit{\printdelim{nonameyeardelim}}% \usebibmacro{cite:labeldate+extradate}}} {} {\PackageWarning{biblatex-patch} {Failed to patch cite bibmacro}}

% Include labelname in labelyear link \xpatchbibmacro{cite} {\printnames{labelname}% \setunit{\printdelim{nameyeardelim}}% \usebibmacro{cite:labeldate+extradate}} {\printtext[bibhyperref]{% \DeclareFieldAlias{bibhyperref}{default}% \printnames{labelname}% \setunit{\printdelim{nameyeardelim}}% \usebibmacro{cite:labeldate+extradate}}} {} {\PackageWarning{biblatex-patch} {Failed to patch cite bibmacro}}

% Access hyperref's citation link start/end commands \makeatletter \protected\def\blx@imc@biblinkstart{% @ifnextchar[%] {\blx@biblinkstart} {\blx@biblinkstart[\abx@field@entrykey]}} \def\blx@biblinkstart[#1]{% \blx@sfsave\hyper@natlinkstart{\the\c@refsection @#1}\blx@sfrest} \protected\def\blx@imc@biblinkend{% \blx@sfsave\hyper@natlinkend\blx@sfrest} \blx@regimcs{\biblinkstart \biblinkend} \makeatother

\newbool{cbx:link}

% Include parentheses around labelyear in \textcite only in % single citations without pre- and postnotes \def\iflinkparens{% \ifboolexpr{ test {\ifnumequal{\value{multicitetotal}}{0}} and test {\ifnumequal{\value{citetotal}}{1}} and test {\iffieldundef{prenote}} and test {\iffieldundef{postnote}} }}

\xpatchbibmacro{textcite} {\printnames{labelname}} {\iflinkparens {\DeclareFieldAlias{bibhyperref}{default}% \global\booltrue{cbx:link}\biblinkstart% \printnames{labelname}} {\printtext[bibhyperref]{\printnames{labelname}}}} {} {\PackageWarning{biblatex-patch} {Failed to patch textcite bibmacro}}

\xpatchbibmacro{textcite} {\usebibmacro{cite:label}} {\iflinkparens {\DeclareFieldAlias{bibhyperref}{default}% \global\booltrue{cbx:link}\biblinkstart% \usebibmacro{cite:label}} {\usebibmacro{cite:label}}} {} {\PackageWarning{biblatex-patch} {Failed to patch textcite bibmacro}}

\xpretobibmacro{textcite:postnote} {\ifbool{cbx:link} {\ifbool{cbx:parens} {\bibcloseparen\global\boolfalse{cbx:parens}} {}% \biblinkend\global\boolfalse{cbx:link}} {}} {} {\PackageWarning{biblatex-patch} {Failed to patch textcite:postnote bibmacro}}

\renewcommand{\baselinestretch}{1.2} \setlength{\parskip}{\smallskipamount} \setlength{\parindent}{0pt} \addbibresource{biblatex-examples.bib} \begin{document} \null\vfill \textbf{Single citations}

Filler text \parencite{aristotle:poetics}. Filler text \parencite{kant:ku}. Filler text \parencite{cms}. \ Filler text \parencite[See][23]{aristotle:poetics}. Filler text \parencite[1--10]{kant:ku}. \ \textcite{knuth:ct} and \textcite{knuth:ct:a}. \textcite{knuth:ct:b} and \textcite{knuth:ct:c}. \ \textcite{aristotle:poetics} and \textcite{kant:ku} and \textcite{cms}. \ \textcite[e.g.][]{aristotle:poetics} and \textcite[10]{kant:ku}. \ Filler text.\footcite[23]{aristotle:poetics} Filler text.\footcite[1--10]{aristotle:rhetoric} Filler text.\footnote{\smartcite[10--15]{companion}}

\textbf{Unqualified citation lists}

\textcite{knuth:ct,knuth:ct:a,knuth:ct:b,knuth:ct:c} showed that... \ \textcite[e.g.][10--15]{aristotle:poetics,aristotle:rhetoric,cms} showed that...\ Filler text \parencite[See][for example]{aristotle:poetics,aristotle:rhetoric,cms}. \ Filler text \parencite[etc.]{knuth:ct,knuth:ct:a,knuth:ct:b,knuth:ct:c}.

\textbf{Qualified citation lists}

\textcites{aristotle:poetics}{aristotle:rhetoric} showed that... \textcites(See)(){aristotle:poetics}[cf.][]{aristotle:rhetoric}. \ \textcites(See)()[e.g.][15]{aristotle:poetics}[cf.][10]{aristotle:rhetoric} \ \parencites(See)()[10--15]{aristotle:poetics}[cf.][10]{aristotle:rhetoric} \ \parencites{knuth:ct,knuth:ct:a}[10--11]{knuth:ct:b,knuth:ct:c}

\textbf{Mix of qualified and unqualified citation lists}

\textcites(See)()[e.g.][]{aristotle:poetics}[10]{bertram,companion} \ \textcites[e.g.][]{aristotle:poetics,aristotle:rhetoric}[10]{companion} \ \textcites[10]{aristotle:poetics}{aristotle:rhetoric}[cf.][]{bertram} \ \textcites[15]{aristotle:poetics}[cf.][10]{bertram,companion}

\printbibliography \chapter*{Appendix} \end{document}

Here is the output you should get with biblatex 2.6 or earlier. The patches also work with later releases, where \textcite and friends incorporate the and string into the final citation delimiter.

enter image description here

moewe
  • 175,683
Audrey
  • 28,881
  • Oh, I see. That makes sense. Thanks for clearing this up. – apc Sep 06 '11 at 00:01
  • 2
    Why is this not an option in biblatex yet? – Oleg Dec 20 '15 at 20:11
  • 1
    @Oleg Because the default behaviour is the best way to apply the links. – Audrey Jun 06 '16 at 00:42
  • Thanks for your efforts Audrey! Unfortunately your solution seems to partially fail on current systems if the \parencite command is used, e.g. also on Overleaf: the name of the author does not get linked. I would really appreciate if you could update your solution, since I would like to use colored text for the hyperlinks to make citations distinguishable. MWE: Overleaf/wxthgndftfmk – Pontis Apr 22 '21 at 19:43
  • 2
    @theBridge Updated the code to work with a current version of biblatex. Some patches were using outdated code. – moewe Apr 24 '21 at 12:34
  • @moewe Many thanks, I really appreciate your help! Just to let you know (pardon my bluntness): I'm aware of the difficulties pointed out in the issue on Github but I would also like such an option in biblatex, since it's nice to make citations distinguishable if using colored links. And maybe most of us would not mind if postnotes would not be supported if using such an option. – Pontis Apr 25 '21 at 07:11
  • 1
    Update 2021: Reason why this is not part of BiBLaTeX: github.com/plk/biblatex/issues/1024 (2020) and github.com/plk/biblatex/issues/428 (2016). – Dr. Manuel Kuehner Nov 25 '21 at 21:38
  • @moewe Can you update this code again? I was able to repatch, but I am seeing ! Undefined control sequence. l.15896 \blx @secinit ? which seems to be called in refsection but I can't seem to figure out the fix myself. – k4rtik Feb 24 '22 at 21:10
  • 1
    @k4rtik The code as posted appears to be working just fine with biblatex v3.17 (I just checked). If you get an error then, I'm suspecting you are using it in a different context or with a different biblatex version. If you need help with getting it going, please ask a new question. – moewe Feb 24 '22 at 21:32
  • Nah, even removing refsection results in that error, so I am unsure what's calling it. I am on the latest version of everything involved (tlmgr update --all). – k4rtik Feb 24 '22 at 21:32
12

I would prefer another solution:

\makeatletter
%Works without the last bracket ;-)
\let\abx@macro@citeOrig\abx@macro@cite
\renewbibmacro{cite}{%
   \bibhyperref{%
   \let\bibhyperref\relax\relax%
   \abx@macro@citeOrig%
   }%
}
\let\abx@macro@textciteOrig\abx@macro@textcite
\renewbibmacro{textcite}{%
   \bibhyperref{%
   \let\bibhyperref\relax\relax%
   \abx@macro@textciteOrig%
   }%
}%
\makeatother

You can use it for every cite-command.

\documentclass{article} 
\usepackage[utf8]{inputenc} 
\usepackage[style=authoryear-comp,backend=biber,hyperref]{biblatex} 
\usepackage[colorlinks]{hyperref} 
\bibliography{biblatex-examples} 

\makeatletter
%Works without the last bracket ;-)
\let\abx@macro@citeOrig\abx@macro@cite
\renewbibmacro{cite}{%
   \bibhyperref{%
   \let\bibhyperref\relax\relax%
   \abx@macro@citeOrig%
   }%
}
\let\abx@macro@textciteOrig\abx@macro@textcite
\renewbibmacro{textcite}{%
   \bibhyperref{%
   \let\bibhyperref\relax\relax%
   \abx@macro@textciteOrig%
   }%
}%
\makeatother


\begin{document} 
A reference to \parencite{kastenholz,sigfridsson} and~\cite{sigfridsson}. 
\printbibliography 
\end{document}

EDIT:

I change the code of the example above.

\makeatletter
   \patchcmd{\blx@citeprint}%
           {\blx@loopcode}%
           {\blx@imc@bibhyperlink{#1}‌​‌​{\blx@loopcode}}%
           {}{}
\makeatother

The problem: The last bracket isn't part of the link.

Marco Daniel
  • 95,681
  • +1 Clever! It doesn't seem to handle delimiters between compact labels and parentheses in \textcite correctly. (Try generating the sample document in my answer.) Can you fix this? – Audrey Sep 05 '11 at 23:44
  • @Audray: Maybe tomorrow. I must sleep now ;-) (2:00am in Germany) – Marco Daniel Sep 05 '11 at 23:52
  • @Marco I'm guessing the problem is \setunit. Your approach wraps the whole result in \printtext[bibhyperref], which prevents what would otherwise be adjacent \setunits (generated at the end of one cite/textcite and at the beginning of the next) from working their magic. – Audrey Sep 06 '11 at 08:44
  • @Audrey: I compared the solution. I must think about it ;-) – Marco Daniel Sep 06 '11 at 13:39
  • @Audrey: But I am interested in a "careless" solution ;-) – Marco Daniel Sep 06 '11 at 15:18
  • @Audrey: I suppose I don't use \textcite at all, so the problem didn't really arise. (In cases where you'd use \textcite I'd prefer the year alone being the hyperlink, so I trained myself to use natbib's \citeyear in those cases.) I'd be curious to see if @Marco comes up with a solution, though. Thanks to both of you! – apc Sep 06 '11 at 16:08
  • @apc The problem arises in other citation commands, particularly in delimiting a compact citation/multi-citation. Extending that example we discussed elsewhere, in \parencite we might expect to see (Smith 1990; Doe 1990a,b) but this answer gives (Smith 1990; Doe 1990a; b). That said Marco's TeX skills far surpass mine, so I would wait till he has some time to take a look at it. – Audrey Sep 06 '11 at 16:35
  • @Audrey: In Germany I would say "Thanks for the flowers" but this isn't correct. So far I was able to patch the commands that the links and the brackets are correct. The problem: In this way you get two colored link boxes. – Marco Daniel Sep 06 '11 at 16:51
  • @Audrey: now I see how the problem pops up elsewhere. Too bad. But I see that your solution does not have this problem, so the problem has been solved. (Unless I'm missing something) Marco: please keep us posted! – apc Sep 06 '11 at 18:20
  • @Audrey: Now I have solution but the link ignore the last bracket ;-) – Marco Daniel Sep 06 '11 at 20:14
  • @Audrey: I changed my code ;-) – Marco Daniel Sep 07 '11 at 01:27
  • @apc: Try the new one. – Marco Daniel Sep 07 '11 at 01:27
  • @Marco Or in other words: \makeatletter\patchcmd{\blx@citeprint}{\blx@loopcode}{\blx@imc@bibhyperlink{#1}‌​{\blx@loopcode}}{}{}\makeatother. The links generated appear to be nested and include some delimiters, which can be confusing with colorlinks=true. Most of them take you to the correct entry, but there is something funny going on with the link applied to labelname in a compact citation. Still an interesting approach, though! – Audrey Sep 07 '11 at 02:53
  • @Audrey: OK this way is more elegant ;-) – Marco Daniel Sep 07 '11 at 09:05
  • @MarcoDaniel: I am trying to use your solution, but I am a bit confused by the edits. What is the code below the edit for (\patchcmd etc.)? When using \textcite the right bracket is still not hyperlinked. – Jörg Mar 15 '12 at 17:19
  • @Jörg: I have to look at this question/answer. That can take some time. – Marco Daniel Mar 15 '12 at 17:34
  • Did you ever figure this one out @MarcoDaniel? I'd love for this to work on the final bracket too :) – cflewis Oct 12 '12 at 21:36
  • @cflewis you need to make the name reference at the beginning of a comment, otherwise the person will not get notified. I took the liberty of notifying Marco. – Jörg Nov 22 '12 at 14:18
  • @MarcoDaniel Did you ever figure out the solution to include the final bracket? cflewis and I are really eager to use it :) – Jörg Nov 22 '12 at 14:19
  • @Jörg: I didn't test it anymore ;-) – Marco Daniel Nov 22 '12 at 18:19
  • The code in the edit does not work for me with your minimal example: http://pastebin.com/Jq7aXQvX And with the non edited version I have one minor issue: When using \autocite[vgl.][17]{sigfridsson} without the colorlinks hyperref option the space between the prenote and actual quoted material is also included in the link, see http://i.imgur.com/hi8yjBL.png Any idea how to fix this? – GEO Sep 24 '14 at 15:53
  • @MarcoDaniel Thanks for this answer. At present, has this option been added to biblatex or not yet? – Diaa Feb 05 '17 at 03:30
  • @DiaaAbidou I don't know this. You can ask Audrey. He is the maintainer of the package – Marco Daniel Feb 05 '17 at 09:30
  • Update 2021: Reason why this is not part of BiBLaTeX: github.com/plk/biblatex/issues/1024 (2020) and github.com/plk/biblatex/issues/428 (2016). – Dr. Manuel Kuehner Nov 25 '21 at 21:38