% Annotate LaTeX Equations
% 
% (c) 2022 by ST John, https://github.com/st--/
% Licensed under MIT License
% 
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{annotate-equations}
  [2023/05/06 v0.2.2 easily annotate equations using TikZ]

%%% lualatex compatibility, from https://tex.stackexchange.com/a/351520/171664
\RequirePackage{ifluatex}
\ifluatex
\RequirePackage{luatex85}
\RequirePackage{pdftexcmds}
  \makeatletter
  \let\pdfstrcmp\pdf@strcmp
  \let\pdffilemoddate\pdf@filemoddate
  \makeatother
\fi
%%%

\RequirePackage{tikz}
\RequirePackage{xcolor}

\usetikzlibrary{backgrounds}
\usetikzlibrary{arrows,shapes}
\usetikzlibrary{tikzmark} % for \tikzmarknode
\usetikzlibrary{calc} % for computing the midpoint between two nodes, e.g. at ($(p1.north)!0.5!(p2.north)$) 


%%%%% SETTINGS %%%%%

\newcommand{\eqnhighlightheight}{}  % colorbox will shrink to content
\renewcommand{\eqnhighlightheight}{\mathstrut} % colorbox will always have full height

\newcommand{\eqnhighlightshade}{17}  % light
%\renewcommand{\eqnhighlightshade}{47}  % dark

\newcommand{\eqnannotationstrut}{\strut} % Package default
\newcommand{\eqnannotationfont}{\sffamily\footnotesize}


\providecommand\EAmarkanchor{north} % default set to "above"
\providecommand\EAwesteast{east} % default set to "right"
\providecommand\EAlabelanchor{south} % default set to "label above"
% for pgfkeys, see https://tex.stackexchange.com/a/34318/171664
% for no-value keys, see https://tex.stackexchange.com/a/401848/171664
\pgfkeys{
    /eqnannotate/.is family, /eqnannotate,
    above/.code = {\renewcommand\EAmarkanchor{north}},
    below/.code = {\renewcommand\EAmarkanchor{south}},
    left/.code = {\renewcommand\EAwesteast{west}},
    right/.code = {\renewcommand\EAwesteast{east}},
    label above/.code = {\renewcommand\EAlabelanchor{south}},
    label below/.code = {\renewcommand\EAlabelanchor{north}},
}

\tikzset{annotate equations/arrow/.style={}}
\tikzset{annotate equations/text/.style={font=\eqnannotationfont}}

%%%%% %%%%%%%% %%%%%


\newcommand*{\eqnhighlightcolorbox}[2]{%
% \colorbox sets the second argument in text mode, so for use within equations we wrap it in $ $ again
    \mathchoice% to get right font size in each mode:
        {\colorbox{#1}{$\displaystyle #2$}}%
        {\colorbox{#1}{$\textstyle #2$}}%
        {\colorbox{#1}{$\scriptstyle #2$}}%
        {\colorbox{#1}{$\scriptscriptstyle #2$}}%
}

%%% the fbox with 0pt rule fixes the height of eqnmark vs eqnmarkbox issue
\newcommand*{\eqnhighlightfbox}[2]{%
% \fbox sets the second argument in text mode, so for use within equations we wrap it in $ $ again
    \mathchoice% to get right font size in each mode:
        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\displaystyle\color{#1}#2$}\endgroup}%
        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\textstyle\color{#1}#2$}\endgroup}%
        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\scriptstyle\color{#1}#2$}\endgroup}%
        {\begingroup\setlength{\fboxrule}{0pt}\fbox{$\scriptscriptstyle\color{#1}#2$}\endgroup}%
}

% . is the current color

\newcommand*{\eqnhighlight}[2]{\begingroup\colorlet{currentcolor}{.}\eqnhighlightcolorbox{#1!\eqnhighlightshade}{\eqnhighlightheight #2}\endgroup}
\newcommand*{\eqncolor}[2]{\begingroup\colorlet{currentcolor}{.}\eqnhighlightfbox{#1}{\eqnhighlightheight #2}\endgroup}

%%% Arguments to \eqnmark[box]: [highlight color]{node name}{term to highlight}
\newcommand*{\eqnmarkbox}[3][currentcolor]{\addvalue{#2}{#1}\tikzmarknode{#2}{\eqnhighlight{#1}{#3}}}
\newcommand*{\eqnmark}[3][currentcolor]{\addvalue{#2}{#1}\tikzmarknode{#2}{\eqncolor{#1}{#3}}}

% Store current color in a dictionary (lookup table),
% from https://tex.stackexchange.com/a/48931/171664 :
\def\addvalue#1#2{\expandafter\gdef\csname eqnannotate@data@#1\endcsname{#2}}
\def\usevalue#1{%
  \ifcsname eqnannotate@data@#1\endcsname
    \csname eqnannotate@data@#1\expandafter\endcsname
  \else
    currentcolor%
  \fi
}


%%%%% Helpers for swapping north/south / west/east / -/+ depending on above/below / left/right etc.:
\newcommand*{\swapNorthSouth}[1]{%
    \ifnum\pdfstrcmp{#1}{south}=0 north\else south\fi
}
\newcommand*{\swapWestEast}[1]{%
    \ifnum\pdfstrcmp{#1}{east}=0 west\else east\fi
}
\newcommand*{\EAxshift}[1]{%
    \ifnum\pdfstrcmp{#1}{east}=0 -0.3ex\else 0.3ex\fi
}
%%%%%


\newcounter{eqnannotatenode}
\newcommand*{\eqnannotateCurrentNode}{eqnannotatenode\theeqnannotatenode}


\newcommand{\annotatetwo}[5][]{%
    \begingroup% %%% so we don't leak the \def's below
    \stepcounter{eqnannotatenode}%
    %%% #1: (optional) extra args for \node e.g. yshift=...
    \pgfkeys{/eqnannotate, #2}% %%% all configuration options
    \def\myEAmarkOne{#3}%
    \def\myEAmarkTwo{#4}%
    \colorlet{currentcolor}{.}
    \def\myEAtext{#5}%
    \def\myEAcolor{\usevalue{\myEAmarkOne}}%
    \begin{tikzpicture}[overlay,remember picture,>=stealth,nodes={align=left,inner ysep=1pt},<-]
        % default anchor is at center
		\node[anchor=\swapNorthSouth{\EAmarkanchor},color=\myEAcolor!85,
			annotate equations/text,#1
			]  % color blended with white to 85%, any (optional) extra args #1
            (\eqnannotateCurrentNode)   % use counter-based "local node"
            at ($(\myEAmarkOne.\EAmarkanchor)!0.5!(\myEAmarkTwo.\EAmarkanchor)$)  % centered between the two nodes
            {\myEAtext\eqnannotationstrut};
        % double arrow to two uses within the equation:
        \draw [<->,color=\myEAcolor, annotate equations/arrow] (\myEAmarkOne.\EAmarkanchor) |- ([yshift=0.1ex] \eqnannotateCurrentNode.\EAlabelanchor) -| (\myEAmarkTwo.\EAmarkanchor);  % from node 1 via annotation to node 2, with anchor #6 each
    \end{tikzpicture}%
    \endgroup% %%% close group again
}


%%% \extractfirst from https://tex.stackexchange.com/a/115733/171664
\RequirePackage{expl3}
\RequirePackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\extractfirst}{mm}
 {
  \tl_set:Nx #1 {\clist_item:Nn #2 { 1 } }
 }
\ExplSyntaxOff
%%%

\newcommand{\annotate}[4][]{%
    \begingroup% %%% so we don't leak the \def's below
    \stepcounter{eqnannotatenode}%
    %
    %
    %
    % #1: (optional) extra args for \node e.g. yshift=...
    \pgfkeys{/eqnannotate, #2}
    \def\myEAmarks{#3}%
    \extractfirst\myEAmark\myEAmarks% %%% get first node for color and annotation
    \def\myEAtext{#4}%
    %
    %
    \colorlet{currentcolor}{.}
    \def\myEAcolor{\usevalue{\myEAmark}}%
    %
    \def\EAspace{ }  % workaround: did not find any other way of getting a space into \myEAlabelanchor without upsetting LaTeX/PGF/... somehow
    \edef\myEAlabelanchor{\EAlabelanchor\EAspace\EAwesteast}%
    %
    %
    \def\myEAxshift{\EAxshift{\EAwesteast}}%
    \begin{tikzpicture}[overlay,remember picture,>=stealth,nodes={align=left,inner ysep=1pt},<-]
		\node[anchor=\swapNorthSouth{\EAmarkanchor} \swapWestEast{\EAwesteast},
			color=\myEAcolor!85,annotate equations/text,#1] % TODO for some reason, passing #1 through command doesn't work...
                % anchor=west: align left edge of text on top of tikzmark in equation
                % should be north west for below and south west for above ...
            (\eqnannotateCurrentNode) at (\myEAmark.\EAmarkanchor)  % \EAmarkanchor north: above the equation, south: below
            {\myEAtext\eqnannotationstrut};
        \foreach \EAmark in \myEAmarks
        \draw [color=\myEAcolor, annotate equations/arrow] (\EAmark.\EAmarkanchor)  % arrow from the equation
                % \EAmarkanchor north: above the equation, south: below
            |- ([xshift=\myEAxshift,yshift=0.1ex] \eqnannotateCurrentNode.\myEAlabelanchor);
                % - south east: we want line to end at bottom right of annotation text;
                % - negative xshift makes it a little bit shorter;
                % - yshift for aesthetics (\strut is ever so slightly too tall).
    \end{tikzpicture}%
    \endgroup% %%% close group again
}

\endinput
%%
%% End of file
