% \iffalse meta-comment
%
%% File: tensor.dtx
%%
% Copyright (C) 2023 Philip G. Ratcliffe <philip.ratcliffe@uninsubria.it>
%
% 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
%
%    http://www.latex-project.org/lppl.txt
%
% This file is part of the "tensor package" (the Work in LPPL)
% and all files in that package must be distributed together.
%
% The released version of this package is available from CTAN.
%
% This package has the LPPL maintenance status "maintained".
%
% The current maintainer of this package is Philip G. Ratcliffe.
%
% \fi
%
% \iffalse
%
%<package>\NeedsTeXFormat{LaTeX2e}[1995/12/01]
%<package>\ProvidesPackage{tensor}
%<package>   [2023/07/18 v2.2 tensor indices package (PGR)]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{tensor}
\NewDocElement[macrolike=false]{Argument}{argument}
\NewDocElement[macrolike=false]{Option}{option}
%
\CodelineIndex
\EnableCrossrefs
\RecordChanges
\DoNotIndex{\let,\def,\gdef,\newcommand,\renewcommand}
\DoNotIndex{\if,\else,\fi,\ifx,\fi,\iffalse,\fi,\iftrue,\fi}
\DoNotIndex{\@empty,\expandafter,\makebox,\relax,\string,\the,\z@}
\DoNotIndex{\MessageBreak,\on@line}
%
\begin{document}
  \DocInput{tensor.dtx}
\end{document}
%</driver>
% \fi
%
% \CheckSum{342}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v1.0}{1996/06/03}{original version}
% \changes{v2.0}{2004/04/01}{extended \cs{tensor}, added \cs{indices} and
%   \cs{nuclide}, substituted \cs{newcommand} with \cs{DeclareRobustCommand} in
%   user commands, documented and packaged}
%
% \GetFileInfo{tensor.sty}
%
% \DoNotIndex{\CodelineIndex,\EnableCrossrefs,\RecordChanges}
%
% \title{%
%   The \textsf{tensor}\relax
%   \,\thanks{%
%     Based on and extending the original package of the same name by Mike Piff
%     (1996/06/03).}
%   \space
%   package for \LaTeX2e
% }
% \author{%
%   Philip G. Ratcliffe\relax
%   \,\thanks{E-mail: \textsf{philip.ratcliffe@uninsubria.it}}
% \\
%   Dipartimento di Scienza e Alta Tecnologia
% \\
%   Universit\`a degli Studi dell'Insubria---Como
% }
%
% \date{(\fileversion, last revision \filedate)}
%
% \maketitle
%
% \begin{abstract}
% This is a complete revision and extension of Mike Piff's original |tensor|
% package; it defines two commands for typesetting tensors with mixed upper and
% lower indices in which the correct horizontal spacing must be observed.
% Various forms of alignment are available and spaces may be replaced by dots
% or other symbols. Consistent preposing of indices is now made possible while
% backwards compatibility is maintained. A special-purpose command to typeset
% nuclides is also defined.
% \end{abstract}
%
% \section{Introduction}
%
% It is common in both physics and mathematics to use tensors with mixed upper
% and lower indices in which the relative horizontal positions and spacing are
% significant, for example
% \begin{displaymath}
%   \Gamma\indices{^\mu_{\nu\rho}},\quad R\indices{^\mu_\nu^\rho_\sigma}
%   \quad\mathrm{or}\quad
%   \epsilon\indices{^\mu^\nu^\rho_\sigma}.
% \end{displaymath}
% The macros defined in this package automatically maintain consistent
% horizontal positioning. Another common need addressed is the
% preposing of upper and lower indices, as in
% \begin{displaymath}
%   \tensor
%     [_{\rm H}]
%     {\langle q',t' \vert \mathcal{U}(t,t') \vert q,t\rangle}
%     {_{\rm H}}
%   \quad\mathrm{or}\quad
%   \nuclide[14][6]{C}.
% \end{displaymath}
% Note the correct spacing of the pre-index H in the above example. It should
% also be noted that constant vertical positioning is maintained for lone
% indices; consider the following (examine carefully the last lower index $o$
% on the right):
% \begin{displaymath}
%   {\rm M}\indices*{^o_o} \vert \tensor[_o]{{\rm M}}{}
%   \quad\mbox{\emph{cf.}}\quad
%   {\rm M}^o_o \vert _o{\rm M},
% \end{displaymath}
% where the former group was typeset using \cs{indices}, the latter using `|_|'
% and `|^|'.
%
% \section{Usage}
%
% Two robust math-mode commands, \cs{tensor} and \cs{indices}, are defined (the
% first of which remains backwards compatible with Mike Piff's original
% definition). A new, robust text- and math-mode command, \cs{nuclide}, is also
% defined specifically for typesetting nuclides, as in the above example.
%
% \subsection{User commands}
%
% \DescribeMacro{\indices}
% To produce a mathematical expression (typically a tensor) with mixed upper
% and lower indices, simply enter
% \meta{object}|\indices{|%
%   |^|\meta{sup$_{\,1}$}|_|\meta{sub$_{\,1}$}%
%   |^|\meta{sup$_{\,2}$}|_|\meta{sub$_{\,2}$}%
% \dots|}|.
% Thus, in math mode it is sufficient to type \emph{e.g.}
% \begin{center}
%   |M\indices{^a_b^{cd}_e}|\quad to obtain\quad
%   $M\indices{^a_b^{cd}_e}$.
% \end{center}
%
% \DescribeMacro{\tensor}
% This variant has been retained in a completely backwards compatible form
% while also being considerably extended; the syntax for the previous
% expression is |\tensor{M}{^a_b^{cd}_e}|, for which the resulting output is
% identical. The extended form of \cs{tensor} defined here has an optional
% argument for indices to be placed \emph{before} the tensor, thus:
% \begin{center}
%   |\tensor[^a_b^c_d]{M}{^e_f^g_h}|\quad produces\quad
%   $\tensor[^a_b^c_d]{M}{^e_f^g_h}$.
% \end{center}
% A fairly robust (if somewhat crude) attempt is made to ensure the correct
% spacing and skew of the preposed indices with respect to the tensor object
% itself.
%
% Note that also \cs{sb} and \cs{sp} may be used in place of `|_|' and `|^|'
% respectively for both the above macros.
%
% \DescribeMacro{\indices*}
% \DescribeMacro{\tensor*}
% These two macros have starred forms, which collapse the spacing (\emph{i.e.}
% return to standard form). While \cs{indices*} is clearly redundant (and is
% included merely for symmetry), \cs{tensor*} also \emph{right} justifies the
% \emph{pre}-index strings, so that \emph{e.g.} nuclides may be typeset as
% follows (though see below for a purpose-built command):
% \begin{center}
%   |\tensor*[^{14}_6]{\mathrm{C}}{}|\quad produces\quad
%   $\tensor*[^{14}_6]{\mathrm{C}}{}$.
% \end{center}
% For those familiar with the |amsmath| package, this is more-or-less a
% generalisation of (though \emph{not intended} as a substitute for) the
% \cs{sideset} command (which itself is \emph{only valid} for objects defined
% with \cs{mathop}). Note that to use \cs{tensor*} as a substitute for
% \cs{sideset}, it is necessary to insert a \cs{nolimits} command, thus:
% \begin{center}
%   |\tensor*[^*_*]{\prod\nolimits}{^*_*}|\quad produces\quad
%   $\displaystyle\tensor*[^*_*]{\prod\nolimits}{^*_*}$.
% \end{center}
% The output appears identical to that of |\sideset{_*^*}{_*^*}{\prod}|.
%
% \DescribeArgument{*}
% The \cs{indices*} and \cs{tensor*} forms \emph{alone}, allow a |*| to also be
% placed as the first entry in either index-list argument, causing alignment
% (\emph{left} justification) of the successive pairs of upper and lower
% indices. A warning is issued if a |*| appears in an argument string of either
% \emph{non}-starred commands. Thus,
% \begin{center}
%   |\tensor*{M}{*^{i_1}_{m_1}^{i_2}_{m_2}^{i_3}_{m_3}^{i_4}_{m_4}}|
% \\[2ex]
%   produces\hspace{\stretch{2}}
%   $\tensor*{M}{*^{i_1}_{m_1}^{i_2}_{m_2}^{i_3}_{m_3}^{i_4}_{m_4}}$\quad
%   (\emph{cf.} $M^{i_1i_2i_3i_4}_{m_1m_2m_3m_4}$).
%   \hspace*{\stretch{2}}
% \end{center}
% Note that \emph{no warning} is issued for improper pairing of successive
% indices.
%
% \DescribeMacro{\indexmarker}
% In analogy with the |tensind| package, the command \cs{indexmarker} (by
% default empty) may redefined (using \cs{renewcommand}) to introduce a visible
% place marker for the index spaces (though not all |tensind| functionality is
% reproduced here); a simple possibility is
% \begin{center}
% \vspace*{-2ex}
% |\renewcommand\indexmarker{\cdot}|,
% \\
%   after which,\hspace*{\stretch{2}}
% \\
%   |\tensor{M}{^a_b^c_d}|
% \\[1ex]
%   produces\hspace*{\stretch{2}}\null
% \\
%   $\renewcommand\indexmarker{\cdot}\tensor{M}{^a_b^c_d}$\quad instead of\quad
%   $\tensor{M}{^a_b^c_d}$\,.
% \end{center}
%
% \DescribeMacro{\nuclide}
% This command, available in both math and text modes, is defined with the same
% purpose and result as the \cs{isotope} command (from the package of the same
% name). The syntax is
% \begin{center}
%   |\nuclide[|\meta{mass no.}|][|\meta{atomic no.}|]{|\meta{symbol}|}|.
% \end{center}
% Thus, the earlier example of $\nuclide[14][6]{C}$ is obtained with
% |\nuclide[14][6]{C}| while |\nuclide[4][2]{\alpha}| gives
% $\nuclide[4][2]{\alpha}$. As indicated by the square brackets, the
% \meta{mass no.} and \meta{atomic no.} arguments are optional. Note that there
% is a little more space (|1mu|) between the numbers and the chemical symbol
% than appears in the example constructed manually with \cs{tensor*}.
%
% All the above-defined commands may be used recursively, \emph{i.e.} a
% \cs{tensor} may occur as an index to another \cs{tensor} and should behave
% according to the current superscript--subscript level. The user commands are
% defined here as `robust'; they may thus appear as so-called moving arguments,
% \emph{i.e.} to \cs{caption}, \cs{section} \emph{etc}.
%
% \DescribeMacro{\nuclideFont}
% \DescribeMacro{\massnumFont}
% By default, the fonts used in \cs{nuclide} for the chemical symbol, mass and
% atomic numbers are \cs{mathrm}; \emph{i}.\emph{e}., \cs{nuclideFont} (for the
% chemical symbol) is initially defined as \cs{mathrm} and \cs{massnumFont}
% (for the mass/atomic numbers) as \cs{nuclideFont} (for backwards
% compatibility). This then now allows for independent font variation of the
% chemical symbol and mass/atomic numbers. Both macros may be reset with
% \cs{renewcommand} to \cs{mathsf}, \cs{mathbf}, \cs{mathtt} \emph{etc}., or
% simply \cs{relax} (this last for \cs{nuclideFont} has the chemical symbol
% font default to \cs{mathit} for correct spacing, while for \cs{massnumFont}
% the mass and atomic numbers revert to standard math font).
%
% \subsection{Package options}
%
% As of v2.2, the package includes four options relating to the vertical
% alignment of indices. \LaTeX's behaviour in this regard is not always optimal
% or what the user may desire. Consider the following output (constructed using
% `|_|' and `|^|'.):
% \begin{displaymath}
%   \epsilon\indices{^\mu_\rho^\nu_{\tilde\lambda}} \;
%   g\indices{^\mu^\nu} \,.
% \end{displaymath}
% While the indices within each single mathematical object are mutually
% vertically aligned correctly, between separate objects they may not be. This
% is because \LaTeX\ sets the baseline according to the height and depth of the
% given indices on a per-object basis. To obviate such behaviour, this package
% takes the simplest route of using \cs{smash} to hide the height and depth of
% each superscript and subscript string so that they are always set with the
% same baselines. This naturally leads to a somewhat cramped form (superscripts
% are set a little too low and subscripts high) and so a specially defined
% \cs{strut} is included, which slightly raises superscripts and lowers
% subscripts; by default, this is only implemented in displayed math, as the
% impact on inline text may be too disruptive.
%
% \DescribeOption{align}
% \DescribeOption{text}
% \DescribeOption{nosmash}
% \DescribeOption{nostrut}
% The options thus introduced are |align|, |text|, |nosmash| and |nostrut|. The
% first implements both \cs{smash} and a \cs{strut} as outlined above, with
% |text| extending the implementation of the \cs{strut} to inline text, while
% |nosmash| and  |nostrut| cancel the single effects (using both entirely
% negates |align|). Option ordering is irrelevant and the last three are
% inoperative without the first.
%
% The desired effects are implemented via two internal commands, which may also
% be redefined by the user.
% \DescribeMacro{\tensorSmash}
% The first, \cs{tensorSmash}, is set equal to \cs{smash}, which then takes each
% index string as an argument.
% \DescribeMacro{\tensorStrut}
% The second, \cs{tensorStrut}, is set equal to the height of `|l|' and depth
% of `|j|' in the relevant font, (by default though only inside displayed math
% environments) and is appended to each \cs{smash}'ed index string.
%
% \subsection{Caveats}
%
% Grouping of multi-token indices should be performed as normal (\emph{i.e.}
% via enclosure within a brace pair |{|\,|}|). Moreover, owing to the method by
% which index strings are parsed, any index constructs such as |\mathrm{H}|
% must also be entirely enclosed in braces, thus: |\indices{_{\mathrm{H}}^x}|.
%
% Spacing is not guaranteed to always appear optimal, especially when between
% \emph{pre}-pended indices and the tensor object itself. Recall too that
% screen viewing often distorts small spaces owing to resolution effects.
%
% \subsection{External package requirements}
%
% No external packages are required or called.
%
% \subsection{Package conflicts}
%
% There are few conflicts with standard \LaTeX2e\ packages; a problem with the
% |color| package in the first version has now been corrected, as too a
% recently flagged problem with the |underscore| package.
%
% However, the macros defined here fail as arguments of \cs{bm} from the |bm|
% package (due to parsing conflicts) or, consequently, of macros defined by the
% \cs{maybebm} package. A work around for, say, a chapter or section header is
% \begin{center}
%   |{\let\nuclideFont\maybebm \nuclide[4][2]{\textup{He}}}|,
% \end{center}
% which should render \nuclide[\mathbf4][\mathbf2]{\textbf{He}} in the header,
% but \nuclide[4][2]{\textup{He}} in the contents listing.
%
% \StopEventually{\PrintChanges\PrintIndex}
%
% \section{Implementation}
%
% \subsection{User options}
%
% First, the package options with their related \cs{if}\dots\ conditionals are
% defined and processed.
%    \begin{macrocode}
\newif\iftnsr@Aln
\DeclareOption{align}{\tnsr@Alntrue}
\newif\iftnsr@Txt
\DeclareOption{text}{\tnsr@Txttrue}
\newif\iftnsr@Sma \tnsr@Smatrue
\DeclareOption{nosmash}{\tnsr@Smafalse}
\newif\iftnsr@Str \tnsr@Strtrue
\DeclareOption{nostrut}{\tnsr@Strfalse}
\ProcessOptions
%    \end{macrocode}
%
% \subsection{User commands}
%
% The |tensor| package defines three basic user commands:
% \begin{macro}{\tensor}
% The first takes three possible arguments (an optional index string to be
% \emph{preposed}, the tensor object, the index string) and also has a starred
% form, which suppresses spacing (it is backwards compatible with Mike Piff's
% original version).
%    \begin{macrocode}
\DeclareRobustCommand\tensor{%
  \tnsr@Prp
  \@ifstar{\tnsr@Spcfalse\tnsr@Aux}{\tnsr@Spctrue\tnsr@Aux}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\indices}
% The second is a `\emph{lightweight}' form, which is placed immediately
% \emph{following} the tensor object, takes just one argument (the index
% string) and also has a starred form (this form was \emph{not} however present
% in the original package).
% \changes{v2.1}{2004/12/20}{added starred form, for symmetry with
%   \cs{tensor*}}
%    \begin{macrocode}
\DeclareRobustCommand\indices{%
  \tnsr@Prp
  \@ifstar{\tnsr@Spcfalse\ndcs@Aux}{\tnsr@Spctrue\ndcs@Aux}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\nuclide}
% This additional new command takes one direct argument (an optional mass
% number) and two indirect arguments (an optional atomic number, the chemical
% symbol---these last two are handled by an auxiliary macro). Since usage is
% common in text, math mode is ensured.
%    \begin{macrocode}
\DeclareRobustCommand\nuclide[1][]{%
  \ncld@Mno{#1}%
  \ncld@Aux
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\nuclideFont}
% \begin{macro}{\massnumFont}
% These set the fonts for \cs{nuclide}; the defaults are \cs{mathrm} for both
% \cs{nuclideFont} and \cs{massnumFont}. They may be redefined as \emph{e.g.}
% \changes{v2.2}{2023/07/18}{added independent mass/atomic-no.\ font control}
% \cs{mathsf}, \cs{mathbf}, \cs{mathtt}, \cs{mathit} \emph{etc}., or even
% simply \cs{relax} or \cs{renewcommand}\cs{nuclideFont}|{}|.
%    \begin{macrocode}
\newcommand\nuclideFont{\mathrm}
\newcommand\massnumFont{\nuclideFont}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Internal token registers}
%
% \begin{macro}{\tnsr@Sps}
% \begin{macro}{\tnsr@Sbs}
% \begin{macro}{\tnsr@Spe}
% \begin{macro}{\tnsr@Sbe}
% The token registers that hold the upper and lower index strings, and the most
% recent upper and lower index elements respectively:
%    \begin{macrocode}
\newtoks\tnsr@Sps
\newtoks\tnsr@Sbs
\newtoks\tnsr@Spe
\newtoks\tnsr@Sbe
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ncld@Mno}
% This token register temporarily holds the mass number for \cs{nuclide}.
%    \begin{macrocode}
\newtoks\ncld@Mno
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal switches}
%
% \begin{macro}{\iftnsr@Spc}
% The switch to select or suppress index element spacing.
%    \begin{macrocode}
\newif\iftnsr@Spc
%    \end{macrocode}
% \end{macro}
%
% \subsection{Internal macros}
%
% \begin{macro}{\tnsr@Prp}
% \begin{macro}{\tnsr@Wrn}
% Here we simply reset token registers and the warning macro before commencing.
%    \begin{macrocode}
\newcommand\tnsr@Wrn{}
\newcommand\tnsr@Prp{%
  \tnsr@Sps{}%
  \tnsr@Sbs{}%
  \def\tnsr@Wrn{}
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ndcs@Aux}
% This (lightweight) auxiliary macro for \cs{indices} takes one argument (an
% index string); it calls \cs{tnsr@Set}, prints the indices and then issues any
% warnings.
%    \begin{macrocode}
\newcommand\ndcs@Aux[1]{%
  \tnsr@Erx
  \def\tnsr@Obj{}%
  \tnsr@Set{#1}%
  \tnsr@Fin
  \tnsr@Wrn
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Aux}
% This auxiliary macro for \cs{tensor} takes three possible arguments (an
% optional pre-index string, the tensor object, the post-index string) and
% passes everything via \cs{mathpalette} to \cs{tnsr@Plt}.
%    \begin{macrocode}
\newcommand\tnsr@Aux[3][]{%
  \tnsr@Erx
  \mathpalette{\tnsr@Plt{#1}{#3}}{#2}%
  \tnsr@Wrn
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Plt}
% This takes four arguments (the pre-index string---may be empty, the
% post-index, the current math style, the tensor object) and calls
% \cs{tnsr@Set} separately for both pre- and post-index strings.
%    \begin{macrocode}
\newcommand\tnsr@Plt[4]{%
  \def\tnsr@Obj{#3#4}%
  \def\tnsr@Tmp{#1}%
  \ifx\tnsr@Tmp\@empty\else
    \tnsr@Set{#1}%
    \hphantom{{}\tnsr@Fin}%
    \tnsr@Sps\expandafter{%
      \expandafter\tnsr@Krn\expandafter{\the\tnsr@Sps}%
    }%
    \tnsr@Sbs\expandafter{%
      \expandafter\tnsr@Krn\expandafter{\the\tnsr@Sbs}%
    }%
  \fi
  \tnsr@Set{#2}%
  #4\tnsr@Fin
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Set}
% This takes one argument (a pre- or post-index string) and starts processing.
%    \begin{macrocode}
\newcommand\tnsr@Set[1]{%
  \let\tnsr@Swx\relax
  \tnsr@Pro#1\tnsr@Err
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Krn}
% This has one argument (a processed index string) and inserts the necessary
% offsets.
% \changes{v2.1}{2004/12/20}{slightly altered spacing}
%    \begin{macrocode}
\newcommand\tnsr@Krn[1]{%
  \settowidth\@tempdima{$\m@th\tnsr@Obj^{#1}\mkern-1mu$}%
  \kern-\@tempdima
  #1
  \settowidth\@tempdima{$\m@th\tnsr@Obj$}%
  \kern\@tempdima
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Pro}
% This is the index-string processing macro, it takes one argument (an index
% string):
% \changes{v2.2}{2023/07/18}{substituted \cs{ifx} with \cs{if} to avoid
%   \textsf{underscore} package conflict}
%    \begin{macrocode}
\newcommand\tnsr@Pro[1]{%
  \ifx#1\tnsr@Err
    \let\tnsr@Nxt\relax
  \else
    \if#1*
      \iftnsr@Spc
        \gdef\tnsr@Wrn{%
          \PackageWarning{tensor}{%
            '*' not allowed in argument here; I shall ignore it.%
            \MessageBreak Either remove it or use '\string\tensor*'%
          }%
        }%
      \else
        \let\tnsr@Swx\tnsr@Swa
      \fi
      \let\tnsr@Nxt\tnsr@Pro
    \else
      \if#1^
        \def\tnsr@Nxt{\tnsr@Add{\tnsr@Sps}{\tnsr@Sbs}{\tnsr@Spe}}%
      \else
        \if#1_
          \def\tnsr@Nxt{\tnsr@Add{\tnsr@Sbs}{\tnsr@Sps}{\tnsr@Sbe}}%
        \else
          \tnsr@Err
          \let\tnsr@Nxt\tnsr@Pro
        \fi
      \fi
    \fi
  \fi
  \tnsr@Nxt
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Swa}
% Here we flip the state of \cs{tnsr@Swx} to \cs{tnsr@Swb}.
%    \begin{macrocode}
\newcommand\tnsr@Swa{\let\tnsr@Swx\tnsr@Swb}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Swb}
% Here we flip the state of \cs{tnsr@Swx} to \cs{tnsr@Swa} then calculate and
% insert the necessary padding for horizontal index alignment.
%    \begin{macrocode}
\newcommand\tnsr@Swb{%
  \let\tnsr@Swx\tnsr@Swa
  \settowidth\@tempdima{$\m@th\tnsr@Obj{}^{\the\tnsr@Spe}$}%
  \settowidth\@tempdimb{$\m@th\tnsr@Obj{}_{\the\tnsr@Sbe}$}%
  \addtolength\@tempdima{-\@tempdimb}%
  \ifdim\@tempdima=\z@\else
    \ifdim\@tempdima>\z@
      \tnsr@Sbs\expandafter\expandafter\expandafter{%
        \expandafter\the\expandafter\tnsr@Sbs
        \expandafter\kern\the\@tempdima
      }%
    \else
      \@tempdima=-\@tempdima
      \tnsr@Sps\expandafter\expandafter\expandafter{%
        \expandafter\the\expandafter\tnsr@Sps
        \expandafter\kern\the\@tempdima
      }%
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Add}
% This macro takes four arguments (the token-register target for the next index
% token, the token-register target for the phantom element, the token-register
% target for the most-recent element, the next index token). It adds the next
% index token to the upper or lower string and (if spacing is \emph{on}) a
% place-holder (\cs{tnsr@Hph}) of the same size to the lower or upper string,
% respectively. It also calls \cs{tnsr@Swx} to flip state (if activated). The
% use of \cs{leavevmode} avoids conflict with the |color| package.
% \changes{v2.1}{2004/12/20}{added \cs{leavevmode}, to avoid \textsf{color}
%   package conflict}
%    \begin{macrocode}
\newcommand\tnsr@Add[4]{%
  #1\expandafter{\the#1\leavevmode{#4}}%
  \iftnsr@Spc
    #2\expandafter{\the#2\tnsr@Hph{#4}}%
  \fi
  #3{\leavevmode{#4}}%
  \tnsr@Swx
  \tnsr@Pro
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Hph}
% The place-holder macro, uses \cs{mathpalette} to call the contents
% \cs{tnsr@Mph}:
%    \begin{macrocode}
\newcommand\tnsr@Hph{\expandafter\mathpalette\expandafter\tnsr@Mph}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Mph}
% The place-holder macro contents:
% \changes{v2.1}{2004/12/20}{substituted \cs{hbox} with \cs{makebox}}
%    \begin{macrocode}
\newcommand\tnsr@Mph[2]{%
  \settowidth\@tempdima{$\m@th#1{#2}$}%
  \makebox[\@tempdima][c]{$\m@th#1\indexmarker$}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\indexmarker}
% The default (blank) placeholder for index spacing:
% \changes{v2.1}{2004/12/20}{added capability to insert place holders}
%    \begin{macrocode}
\newcommand\indexmarker{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Fin}
% Finally, we put the index strings into place:
% \changes{v2.2}{2023/07/18}{added vertical alignment capability}
%    \begin{macrocode}
\newcommand\tnsr@Fin{%
  ^{\tensorSmash{\the\tnsr@Sps}\tnsr@Str}%
  _{\tensorSmash{\the\tnsr@Sbs}\tnsr@Str}%
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tensorSmash}
% Initialise \cs{tensorSmash} as \cs{relax} and then conditionally set it equal
% to \cs{smash} (it is user redefinable).
%    \begin{macrocode}
\let\tensorSmash\relax
\iftnsr@Aln
  \iftnsr@Sma
    \let\tensorSmash\smash
  \fi
\fi
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tensorStrut}
% \begin{macro}{\tnsr@Str}
% Initialise \cs{tensorStrut} as \cs{relax} and then conditionally set it to
% the height and depth of `|jl|'. By default, it is only applied to displayed
% math environments (passed on via \cs{tnsr@Str}, which is \cs{def}'ed  as
% \cs{tensorStrut} to be user redefinable), but always (\emph{i.e.} extended to
% inline text) if the package option |text| is present.
%    \begin{macrocode}
\newcommand\tensorStrut{}
\let\tnsr@Str\relax
\iftnsr@Aln
  \iftnsr@Str
    \renewcommand\tensorStrut{\vphantom{jl}}
    \iftnsr@Txt
      \def\tnsr@Str{\tensorStrut}
    \else
      \everydisplay\expandafter{\the\everydisplay\let\tnsr@Str\tensorStrut}
    \fi
  \fi
\fi
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ncld@Aux}
% This auxiliary macro takes two arguments (an optional atomic number and the
% chemical symbol). The mass number is passed on via \cs{ncld@Mno}. Math mode
% is ensured since usage is common in text. The spacing is increased by |1mu|
% for better appearance.
%    \begin{macrocode}
\newcommand\ncld@Aux[2][]{%
  \ensuremath{%
    \tensor*[^{\massnumFont{\the\ncld@Mno}}_{\massnumFont{#1}}]%
      {\mkern1mu{\mathit{\nuclideFont{#2}}{}}}{}%
  }%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tnsr@Err}
% This is invoked in the only error situations considered.
%    \begin{macrocode}
\newcommand\tnsr@Err{}
\newcommand\tnsr@Erx{%
  \def\tnsr@Err{%
    \global\let\tnsr@Err\relax
    \PackageError{tensor}{%
      Misordered sub/superscript items\on@line;
      \MessageBreak index tokens may have been lost.
      \MessageBreak Press <return> and I shall try to continue%
    }{Index string probably has extra/missing '^' or '_'.}%
  }%
}
%    \end{macrocode}
% \end{macro}
%
% \Finale
%
\endinput
%%
%% End of file 'tensor.dtx'.