2

I want to define a command \shorttextcite that does only print the first author and "et.al.".

The standard behavoir of \textcite in authoryear should not be altered.

Example and MWE:

% !TeX program=lualatex
\documentclass{scrartcl}

\usepackage{fontspec}

\usepackage[style=authoryear-comp,backend=biber]{biblatex}

\usepackage[main=ngerman,english]{babel}

\usepackage{filecontents}

\begin{filecontents}{\jobname.bib}
    @Article{john1980,
        author  = {M. John},
        title   = {A new view on the wheel},
        journal = {Proceedings in Transportation},
        year    = {1980},
    }
    @Article{john1981,
        author  = {M. John and J. Mary},
        title   = {A new view on the wheel II},
        journal = {Proceedings in Transportation},
        year    = {1981},
    }
\end{filecontents}

\addbibresource{\jobname.bib}

\begin{document}
    \textcite{john1980,john1981}
    \printbibliography

\end{document}

This yields:

enter image description here The \shorttextcite should output "John et. al. (1980,1981)" but \textcite should still do the same as it does now.

5
  • Mhhh, interesting question. The obvious problem from biblatex's point of view is that john1980 was not written by John et al. - it was only John, so lumping the two papers together even though the authors are different is a bit of a stretch.
    – moewe
    Apr 20 '18 at 16:33
  • Thank you for pointing that oversight out! In the case I actually need to do this, all papers have more than one author. Apr 20 '18 at 16:36
  • Of course this would generally be "unsafe", as you noticed. Apr 20 '18 at 16:37
  • But I assume they have a different list of co-authors, right?
    – moewe
    Apr 20 '18 at 16:37
  • Yes, the co-authors differ. Apr 20 '18 at 16:38
2

This is basically a copy of \textcite with a little trickery to only compare the first name instead of the entire name list to check if we compress citations.

Normally we can just use the field namehash to compare the name lists (indeed this is what \textcite normally does), but namehash obeys the truncation settings and considers all names that are displayed in a citation. We only focus on the very first author, so we need a way to access their hash. This hash is only available if the name is processed, so we use the trick from biblatex: filter out publications from a specific author in the references dynamically and employ indexing commands. Indexing commands allow us to process a name list without printing anything.

For each first author of a work we extract his hash as well as the information whether he worked alone or "et al.". This information is saved and compared to the last citation. If the last citation has the same status they are compressed.

\documentclass{scrartcl}
\usepackage[style=authoryear-comp,backend=biber]{biblatex}

\usepackage{filecontents}

\begin{filecontents}{\jobname.bib}
    @Article{john1980,
        author  = {M. John and B. Fairy},
        title   = {A new view on the wheel},
        journal = {Proceedings in Transportation},
        year    = {1980},
    }
    @Article{john1981,
        author  = {M. John and J. Mary},
        title   = {A new view on the wheel II},
        journal = {Proceedings in Transportation},
        year    = {1981},
    }
    @Article{john1982,
        author  = {M. John},
        title   = {A new view on the wheel III},
        journal = {Proceedings in Transportation},
        year    = {1983},
    }
\end{filecontents}

\addbibresource{\jobname.bib}
\addbibresource{biblatex-examples.bib}

\makeatletter
\DeclareIndexNameFormat{cbx@chr@getfirstauthorhash}{%
  \ifnumequal{\value{listcount}}{1}
    {\savefield{hash}{\cbx@thishash}%
     \ifmorenames
       {\gappto{\cbx@thishash}{@alone}}
       {\gappto{\cbx@thishash}{@etal}}}
    {}}

\newbibmacro*{shorttextcite}{%
  \indexnames[cbx@chr@getfirstauthorhash][1-1]{labelname}%
  \ifdefequal{\cbx@thishash}{\cbx@lasthash}
    {\iffieldundef{shorthand}
       {\ifthenelse{\iffieldequals{labelyear}{\cbx@lastyear}\AND
                    \(\value{multicitecount}=0\OR\iffieldundef{postnote}\)}
          {\setunit{\addcomma}%
           \usebibmacro{cite:extradate}}
          {\setunit{\compcitedelim}%
           \usebibmacro{cite:labeldate+extradate}%
           \savefield{labelyear}{\cbx@lastyear}}}
       {\setunit{\compcitedelim}%
        \usebibmacro{cite:shorthand}%
        \global\undef\cbx@lastyear}}
    {\ifnameundef{labelname}
       {\iffieldundef{shorthand}
          {\usebibmacro{cite:label}%
           \setunit{%
             \global\booltrue{cbx:parens}%
             \printdelim{nonameyeardelim}\bibopenparen}%
           \ifnumequal{\value{citecount}}{1}
             {\usebibmacro{prenote}}
             {}%
           \usebibmacro{cite:labeldate+extradate}}
          {\usebibmacro{cite:shorthand}}}
       {\printnames[labelname][1-1]{labelname}%
        \setunit{%
          \global\booltrue{cbx:parens}%
          \printdelim{nameyeardelim}\bibopenparen}%
        \ifnumequal{\value{citecount}}{1}
          {\usebibmacro{prenote}}
          {}%
        \iffieldundef{shorthand}
          {\iffieldundef{labelyear}
             {\usebibmacro{cite:label}}
             {\usebibmacro{cite:labeldate+extradate}}%
           \savefield{labelyear}{\cbx@lastyear}}
          {\usebibmacro{cite:shorthand}%
           \global\undef\cbx@lastyear}}%
     \stepcounter{textcitecount}%
     \global\let\cbx@lasthash\cbx@thishash}%
  \setunit{%
    \ifbool{cbx:parens}
      {\bibcloseparen\global\boolfalse{cbx:parens}}
      {}%
    \textcitedelim}}


\DeclareCiteCommand{\cbx@shorttextcite}
  {\usebibmacro{cite:init}%
   \global\undef\cbx@thishash}
  {\usebibmacro{citeindex}%
   \usebibmacro{shorttextcite}}
  {}
  {\usebibmacro{textcite:postnote}}

\DeclareCiteCommand{\shorttextcite}[\cbx@textcite@init\cbx@shorttextcite]
  {\gdef\cbx@savedkeys{}%
   \citetrackerfalse%
   \pagetrackerfalse%
   \DeferNextCitekeyHook%
   \usebibmacro{cite:init}%
   \global\undef\cbx@thishash}
  {\ifthenelse{\iffirstcitekey\AND\value{multicitetotal}>0}
     {\protected@xappto\cbx@savedcites{()(\thefield{multipostnote})}%
      \global\clearfield{multipostnote}}
     {}%
   \xappto\cbx@savedkeys{\thefield{entrykey},}%
   \indexnames[cbx@chr@getfirstauthorhash][1-1]{labelname}%
   \ifdefequal{\cbx@thishash}{\cbx@lasthash}
     {}
     {\stepcounter{textcitetotal}%
      \global\let\cbx@lasthash\cbx@thishash}}
  {}
  {\protected@xappto\cbx@savedcites{%
     [\thefield{prenote}][\thefield{postnote}]{\cbx@savedkeys}}}
\makeatother


\begin{document}
  \shorttextcite{john1980,john1981}

  \shorttextcite{knuth:ct:a,knuth:ct:b}

  \shorttextcite{john1982,john1981}

  \shorttextcite{john1982,john1981,john1980}

  \printbibliography
\end{document}

enter image description here

5
  • mind-boggling... Apr 20 '18 at 17:10
  • 1
    @Christoph90 I have slightly edited the solution. It should now also be able to deal with "John" and "John et al."
    – moewe
    Apr 21 '18 at 5:49
  • @moewe, why would a local set of maxnames=1 or blx@maxcitenames with a hook \AtNextCite not work? (I suppose it is to keep pre and postnote, but given the complexity of the changes needed for textcite, wouldn't it be worth it to literally use the hook when a short citation is needed, or define a hook like \nextshort and use \nextshort\textcite?)
    – gusbrs
    Apr 21 '18 at 11:19
  • 1
    @gusbrs You can try with \newrobustcmd*{\citeshortsecond}{% \AtNextCite{\AtEachCitekey{\defcounter{maxnames}{1}}}% \textcite} in the example above. It does not quite work because \textcite uses namehash to compare the name lists (and to decide whether or not to 'compactify' the citations), but namehash is computed by Biber based on the global max(cite)names settings and does not respond dynamically to setting maxnames=1. This is basically what PLK explains in tex.stackexchange.com/q/27359/35864
    – moewe
    Apr 21 '18 at 11:24
  • @moewe Ah, it's the -comp variant! Indeed that complicates things. Thanks for clearing it up!
    – gusbrs
    Apr 21 '18 at 11:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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