% \iffalse meta-comment
%
%% File: latex-lab-bib.dtx (C) Copyright 2023 LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
%
% The development version of the bundle can be found below
%
%    https://github.com/latex3/latex2e/required/latex-lab
%
% for those people who are interested or want to report an issue.
%
\def\ltlabbibdate{2023-07-20}
\def\ltlabbibversion{0.81a}
%<*driver>
\documentclass{l3doc}
\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-bib.dtx}
\end{document}
%</driver>
%
% \fi
%
% \title{The \textsf{latex-lab-bib} package\\
% Changes and additions to the kernel related to tagging and links in citations and 
% bibliography entries}
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabbibversion\ \ltlabbibdate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
% \providecommand\hook[1]{\texttt{#1}}
%
% \begin{abstract}
% \end{abstract}
%
% \section{Introduction}
%
% The followings contains small changes to improve tagging of
% bibliography entries and citations. 
% 
% The tagging of the standard bibliography is actually quite straightforward:
% A bibliography is typically a list with a heading and the code which tags sectioning
% commands and lists handles that. 
% 
% There are here only two problems: 
% 
% \begin{itemize}
% \item The structure number of the \texttt{LI} element
% created by a \cs{bibitem} must be recorded somehow to allow to reference it in 
% a \cs{cite}. 
% \item \pkg{hyperref} redefines the item command and so breaks the list structure
% see \url{https://github.com/latex3/latex2e/discussions/1010#discussioncomment-5565418}
% \end{itemize}
% 
% Both problems are rather easy to resolve, but it must be checked if other packages 
% interfere again by redefining the commands.
% 
% More difficult is the tagging of citation commands. Citations should be inside 
% a Reference structure and contain a /Ref entry pointing to the relevant 
% item in the bibliography. For simple citations like 
% \enquote{[1]} or \enquote{Doody (2023)} this is easy, but it is not obvious how
% to handle combined citations like \enquote{Doody (2003,2018)} (or even compressed citations
% like \enquote{[1-3]}). The current implementation follows the links: whatever hyperref would
% link is set as the reference.
% 
% There exist various packages which over the years tried to improve and extend
% the bibliography commands. We discuss here three: natbib, chapterbib and biblatex.
% 
% \begin{description}
% \item[natbib] It is rather easy to support natbib: it has hooks for links and the tagging code
% can follow. Only a bit coordination with hyperref is needed to avoid that hyperref
% remove the tagging code again.
% 
% \item[chapterbib] In standard LaTeX every bib entry has an unique label which points to the 
% (mandatory and unique) bibliography and the target created by hyperref 
% has the simple form \texttt{cite.}\meta{key}.
% If a package that support multiple bibliographies is used (e.g. chapterbib)
% this is no longer works: a bib entry \texttt{doody} 
% can in one chapter get the label \enquote{[1]}
% and in the other \enquote{[5]} or even \enquote{Doo19} and naturally links
% should jump to the relevant chapter bibliography. chapterbib solves this
% by creating bib keys with a suffix: when reading the \texttt{.aux} files it will
% create the keys \texttt{doody@-1} and \texttt{doody@-2} where the number is related
% to the chapter/include, and in the document and in the document \verb+\cite{doody}+
% will look for \texttt{doody@-1} and \texttt{doody@-2} depending on the number of the
% current include. For some unknown reason chapterbib uses two commands
% to handle the suffix: the command \cs{@extra@binfo} is written to the aux-files 
% and used when processing the \cs{bibcite} commands, 
% but in the document \cs{@extra@b@citeb} is used. Supporting this is 
% straightforward: one only has to take care that the tagging code uses
% \cs{@extra@b@citeb} in the relevant places too.
% 
% \item[biblatex] biblatex supports multiple bibliographies out-of-the-box. 
% It numbers the link target by refsection and uses then the name
% \verb+\the\c@refsection @+\meta{key}.
% 
% Printing a bibliography is not required, in this case you get an engine warning
% and links jump to the begin of the document:
% \begin{verbatim}
% name{cite.0@doody} has been referenced but does not exist
% \end{verbatim}
% 
% Bibliographies can be printed more than once by refsection. To avoid duplicated
% target, biblatex stores the names of the targets in a list and if later
% it detects that a target name has already been used in a
% bibliography no new target is created for this item. This means a citation
% will normally jump to the first bibliography which shows the entry.
% 
% The tagging code has to mimic this code. This means that it can't label every item,
% but has to test if this anchor is already known.
% \end{description}
% 
% 
% \section{Implementation}
%    \begin{macrocode}
%<*package>
%<@@=tag>
%    \end{macrocode}
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-bib} {\ltlabbibdate} {\ltlabbibversion}
  {Code related to the tagging of bibliography and cite command}
%    \end{macrocode}
% We need at least the block tagging code.
%    \begin{macrocode}
\RequirePackage{latex-lab-testphase-block}  
%    \end{macrocode}
%
% At first we suppress the patches from hyperref. This will only work with the next
% hyperref!
%    \begin{macrocode}
\def\hyper@nopatch@bib{}
%    \end{macrocode}

% \begin{macro}{\@extra@binfo,\@extra@b@citeb}
% These are taken from hyperref, they are for chapterbib compability (and also
% signal to chapterbib not to change the citation commands)
%    \begin{macrocode}
\providecommand*\@extra@binfo{}%
\providecommand\@extra@b@citeb{}
%    \end{macrocode}
% \end{macro}
% 
% \begin{variable}{\l_@@_bib_citekey_tl}
%  We can't pass the cite key everywhere as argument so we store it:
%    \begin{macrocode}
\tl_new:N\l_@@_bib_citekey_tl
%    \end{macrocode}
% \end{variable}
% 
%\subsection{Handling the bibliography}
% \begin{macro}{\@lbibitem}
% The item command if an optional argument is used. 
% 
% We only prepend some code. 
%    \begin{macrocode}
\AddToHookWithArguments{cmd/@lbibitem/before}
 {
%    \end{macrocode} 
% we store the target name for the label.
%    \begin{macrocode} 
   \tl_set:Nn\l_@@_bib_citekey_tl{#2}
 }  
%    \end{macrocode}
% The target is added at the begin of the paragraph. We give that a label as
% it perhaps need to be removed by packages
%    \begin{macrocode}  
\AddToHookWithArguments{cmd/@lbibitem/before}[latex-lab-testphase-bib/target]
 { 
   \AddToHookNext{para/begin}
     {
       \makebox[0pt][r]{\MakeLinkTarget*{cite.#2\@extra@b@citeb}\hspace{\leftmargin}}
     }
 }
%    \end{macrocode} 
% we make a copy to be able to reinstate the definition. This is e.g.
% currently needed with hyperref.
%    \begin{macrocode}
\let\@kernel@copy@lbibitem\@lbibitem       
%    \end{macrocode}
% \end{macro}
% 
% \begin{macro}{\@bibitem}
% Similar for \cs{@bibitem}. 
% TODO: If hyperref is loaded we will get a second target from the refstepcounter,
% but this is ignored for now. 
%    \begin{macrocode}
\AddToHookWithArguments{cmd/@bibitem/before}
 {
%    \end{macrocode}
% we store the target name for the label.
%    \begin{macrocode} 
   \tl_set:Nn\l_@@_bib_citekey_tl{#1}
 }  
%    \end{macrocode}
%
% The target is added at the begin of the paragraph. We give that a label as
% it perhaps need to be removed by packages
%    \begin{macrocode}   
\AddToHookWithArguments{cmd/@bibitem/before}[latex-lab-testphase-bib/target]
 {
   \AddToHookNext{para/begin}
     {
       \makebox[0pt][r]{\MakeLinkTarget*{cite.#1\@extra@b@citeb}\hspace{\leftmargin}}
     }
 }
%    \end{macrocode}  
%    \begin{macrocode}
\let\@kernel@copy@bibitem\@bibitem           
%    \end{macrocode}
% \end{macro}
% 
% TODO The LI-structure should set a label, we redefine the internal command locally for 
% now, but perhaps this need a recipe? 
% 
%    \begin{macrocode}
\AddToHook{env/thebibliography/begin}
  {
    \cs_set:Npn \__block_list_item_begin:
     { 
       \tag_struct_begin:n
         {
          tag=\LItag,
          label= cite.\l_@@_bib_citekey_tl\@extra@b@citeb
         }
     }
  }
%    \end{macrocode}
%
% \subsection{Handling citation commands}
% We redefine similar to hyperref the \cs{bibcite} command to inject link and
% structure. Even if it looks a bit odd it is now used for many years and so 
% hopefully compatible with various packages. But differently to hyperref we use
% the new hooks with arguments.
% TODO: consider hook name. 
%    \begin{macrocode}
\NewMirroredHookPairWithArguments{bibcite/before}{bibcite/after}{2}  
\def\bibcite#1#2{%
   \@newl@bel{b}{#1\@extra@binfo}{%
      \UseHookWithArguments{bibcite/before}{2}{#1}{#2}
       #2
      \UseHookWithArguments{bibcite/after}{2}{#1}{#2} 
       }%
     }% 
\let\@kernel@copy@bibcite\bibcite         
%    \end{macrocode}
% Now we add the tagging structure.
% TODO: with the next tagpdf version it should no longer be 
% needed to exand the ref key.
%    \begin{macrocode}
\AddToHookWithArguments{bibcite/before}
  {
    \tag_mc_end_push:
    \exp_args:Nx\tagstructbegin{tag=Reference,ref=cite.#1\@extra@b@citeb}
    \tagmcbegin{}
  }
\AddToHookWithArguments{bibcite/after}[tag]
  {
    \tag_mc_end:
    \tagstructend
    \tag_mc_begin_pop:n{}
  }
%    \end{macrocode}
% At last the code for hyperref, the link will be inside the reference, but
% this can be changed with a rule.
%    \begin{macrocode}
\AddToHook{package/hyperref/after}
  {
    \AddToHookWithArguments{bibcite/before}
     {
       \hyper@linkstart{cite}{cite.#1\@extra@b@citeb}
     }
    \AddToHookWithArguments{bibcite/after}{\hyper@linkend}
  }
%    \end{macrocode}
%
% \subsection{Natbib and biblatex support}
%  When hyperref is loaded, both natbib and biblatex use \cs{hyper@natlinkstart}
%  and \cs{hyper@natlinkend} to handle the links. We can use the generic hooks to 
%  add the tagging code (and the link code from hyperref).
%  We need in part different code for both systems: 
%  with biblatex we have to take care that only the first
%  structure sets a label, and if 
%  hyperref is not loaded (or deactived) we will need additional code
%  but this currently doesn't exist.
%  We assume that no document loads both package -- that will probably break.
%    \begin{macrocode}
\newcommand\hyper@natlinkstart[1]{}
\newcommand\hyper@natlinkend{}
%    \end{macrocode}
% With natbib we need to change the hooks to avoid duplicated target as it sets
% the anchor too. We can not simply empty \cs{hyper@natanchorstart} as that is 
% used by biblatex.
%    \begin{macrocode}
\AddToHook{package/natbib/after}
 {
   \RemoveFromHook{cmd/@bibitem/before} [latex-lab-testphase-bib/target]
   \RemoveFromHook{cmd/@lbibitem/before}[latex-lab-testphase-bib/target]
 }
%    \end{macrocode}
% This can be shared by both packages: it will work with natbib with and without hyperref.
% With biblatex it will work without hyperref as long as \cs{@extra@b@citeb} is empty
%    \begin{macrocode}
\AddToHookWithArguments{cmd/hyper@natlinkstart/before}
 {
   \leavevmode
   \tag_mc_end_push:
   \exp_args:Nx\tag_struct_begin:n{tag=Reference,ref=cite.#1\@extra@b@citeb}
   \tag_mc_begin:n{}
 }
\AddToHook{cmd/hyper@natlinkend/after}
 {
  \tag_mc_end:
  \tag_struct_end:
  \tag_mc_begin_pop:n{}
 }
      
%    \end{macrocode}
% if hyperref is loaded we have to revert its definition of the natbib hooks
% and add its code through the generic hooks. 
% TODO: allow to suppress the natbib code in hyperref. 
% 
%    \begin{macrocode}
\AddToHook{package/hyperref/after}
  {
    \renewcommand\hyper@natlinkstart[1]{}
    \renewcommand\hyper@natlinkend{}
    \AddToHookWithArguments{cmd/hyper@natlinkstart/before}
      {
        \Hy@backout{#1}%
%    \end{macrocode}
%  natbib passes the \cs{@extra@b@citeb} in the argument, and biblatex
%  the refsection, so we only need to add the prefix \texttt{cite.}.
%    \begin{macrocode}
          \hyper@linkstart{cite}{cite.#1}%
          \def\hyper@nat@current{#1}
      } 
    \AddToHook{cmd/hyper@natlinkend/after}
      {  
        \hyper@linkend
      }
  }
    
%    \end{macrocode}
% and now special biblatex code. The list item code has to test if the 
% anchor is already known:
%    \begin{macrocode}
\AddToHook{cmd/blx@bibinit/after}
  {
    \cs_set:Npn \__block_list_item_begin:
     { 
       \xifinlist{\the\c@refsection @\abx@field@entrykey}{\blx@anchors}
        {
          \tag_struct_begin:n
           {
            tag=\LItag,
           }
        }   
        {
          \tag_struct_begin:n
           {
            tag=\LItag,
            label= cite.\the\c@refsection @\abx@field@entrykey
           }
        }   
     }
  }
%    \end{macrocode}
% biblatex without hyperref is currently not supported but we at least avoid that it
% errors:
%    \begin{macrocode}
\AddToHook{package/biblatex/after}
 {
  \appto\blx@mknohyperref
   {
    \let\blx@anchors\@empty
    \protected\def\blx@anchor{%
       \xifinlist{\the\c@refsection @\abx@field@entrykey}{\blx@anchors}
         {}
         {\listxadd\blx@anchors{\the\c@refsection @\abx@field@entrykey}}}%
   }
 }  
%    \end{macrocode}
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%    \begin{macrocode}
%<*latex-lab>
\ProvidesFile{bib-latex-lab-testphase.ltx}
        [\ltlabbibdate\space v\ltlabbibversion\space 
         latex-lab wrapper bib]

\RequirePackage{latex-lab-testphase-bib}

%</latex-lab>
%    \end{macrocode}
