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.

Christoph90
  • 1,020

1 Answers1

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

moewe
  • 175,683
  • mind-boggling... – Christoph90 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 05: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 https://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