% \iffalse meta-comment
%
%% File: xfrac.dtx
%
% Copyright (C) 2004,2008-2010 Morten Hoegholm
%           (C) 2011,2012,2014-2024 The 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
%
% This file is part of the "xfrac package" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/latex3/xfrac
%
% for those people who are interested.
%
%<*driver|package>
\RequirePackage{amstext,graphicx}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\usepackage{nicefrac,xfrac} ^^A Need nicefrac for demo purposes
\providecommand*\key[1]{\textbf{#1}}
\newcommand*\switch[2]{{\fontfamily{#1}\selectfont #2}}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{xfrac} package\\ Split-level fractions^^A
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2024-06-04}
%
% \maketitle
%
% \begin{documentation}
%
% The \pkg{xfrac} package defines a document command \cs{sfrac}
% with the following syntax:
% \begin{quote}
%   \cs{sfrac}\oarg{instance}\marg{num}\oarg{sep}\marg{denom}
% \end{quote}
% Let's show a few examples:
% \begin{verbatim}
%   \sfrac{1}{2},  $\sfrac{1}{2}$,
%   $\mathbf{3\times\sfrac{1}{2}}$
%   \quad \fontfamily{ppl}\selectfont Palatino: \sfrac{1}{2}
%   \quad \fontfamily{ptm}\selectfont Times: \sfrac{1}{2}
% \end{verbatim}
% \begin{quote}
%   \sfrac{1}{2}, $\sfrac{1}{2}$, $\mathbf{3\times\sfrac{1}{2}}$
%   \quad \fontfamily{ppl}\selectfont Palatino: \sfrac{1}{2}
%   \quad \fontfamily{ptm}\selectfont Times: \sfrac{1}{2}
% \end{quote}
% You'll notice something interesting: not only does the \cs{sfrac}
% command work as it should in math mode, it also gets the job done
% for other fonts as well.
%
% \section{A Bit of History}
%
% \subsection{The Past}
%
% One of the first exercises in \emph{The \TeX{}Book} is to design a
% macro for split level fractions. The solution presented is fairly
% simple, using a \emph{virgule} (a slash) for separating the two
% components. It looks okay because the text font and math font of
% Computer Modern look almost identical.
%
% The proper symbol to use instead of the virgule is a \emph{solidus}
% which does not exist in Computer Modern. It is however available in
% the European Computer Modern fonts, but I'll get back to that.
%
% \subsection{The Present}
%
% The most common way to produce split level fractions within \LaTeXe{}
% is by means of the \pkg{nicefrac} package. Part of the reason it
% has found widespread use is due to the strange design of the
% built-in text fractions of the EC fonts, which look like this:
% \textonehalf{}. The package is very simple to use but there are a few
% issues:
% \begin{itemize}
%   \item It uses the virgule instead of the solidus.
%   \item Font size of numerator and denominator is bigger than in the
%     built-in symbol. Compare Palatino: \switch{ppl}{\nicefrac{1}{2}}
%     \emph{vs.}~\switch{ppl}{\textonehalf}.
%  \item It doesn't correct for fonts using text figures such as in the
%     \pkg{eco} package. Compare \switch{cmor}{\nicefrac{1}{2}} and
%     \switch{cmor}{\nicefrac{8}{9}}.
%  \item In math mode, it doesn't always pick up the correct math
%     alphabet.
% \end{itemize}
% In short: \pkg{nicefrac} doesn't attempt to be the answer to
% everything and so this is not a criticism of the package. It works
% quite well for Computer Modern which was pretty much what was widely
% available at the time it was developed. Users these days, however,
% have a choice of many fonts when they write their documents.
%
% \subsection{The Future}
%
% Fonts are wildly different; one macro that works fine for Computer
% Modern obviously doesn't work well at all in Palatino. For one we
% have to make the separator symbol configurable, and we need to
% take care of several details as well: font scaling of the
% numerator/denominator pair (ND), font selection of ND, \emph{etc.} If we
% are to have a single package for this in the future we have to define a
% totally generic interface for the fraction commands and then adjust
% parameters depending on the current font. What you see in this
% prototype implementation of \pkg{xfrac} is just that.
%
% \section{Advanced User Interface}
%
% \subsection{Text mode}
%
% The usual problem in text mode has a name: Computer Modern. The
% solidi of all the Computer Modern fonts leave a lot to be desired,
% although things are potentially looking better as the Latin Modern
% fonts are becoming more stable and widespread. As long as the
% default fonts are Computer Modern variants we must however work
% around this. One idea that comes to mind is to see what happens
% when you use a solidus from another font instead. Let's try with
% Times:
% \begin{quote}
%   \DeclareInstance{xfrac}{cmr2}{text}
%     {slash-symbol-font = ptm}
%   \enquote{You take \sfrac[cmr2]{1}{2} cup of sugar, \ldots}
% \end{quote}
% That looks quite good actually, so it was probably very difficult
% to obtain that result. Nope, it was extremely easy---if you happen
% to know about \emph{instances}:
% \begin{verbatim}
%   \DeclareInstance{xfrac}{cmr}{text}
%     {slash-symbol-font = ptm}
%  \end{verbatim}
% So we define an instance with the name |cmr| from the template
% |text| which in turn is of object type |xfrac|. You'll notice
% the |cmr| is also the name of the font family for Computer Modern
% Roman and the reasoning behind is that every font family should
% have it's own settings, and if a document command is to work well
% in that scheme, letting it use the name of the current font family
% seems like a good idea. Thus the \cs{sfrac} command checks to see
% whether an instance with same name as the current font family
% exists and uses it if the test is true; otherwise the default
% setting is used. Here we defined the instance to be used for the
% font family |cmr| and just told it to use the Times font for
% typesetting the slash symbol which turns out to be a solidus by
% default.
%
% The option \texttt{cm-recommended} which is loaded by default uses
% the Times solidus for Computer Modern Roman and Computer Modern
% Sans Serif and the Palatino solidus for Computer Modern Typewriter
% Type. This looks quite good. Should you however not want this you
% can use the option \texttt{cm-standard} which produces somewhat
% acceptable results using Computer Modern exclusively.
%
% So what about old style figures? If you use the \pkg{eco}
% package you might define an instance similar to this (`cmor' is
% the name of the roman font activated by \pkg{eco}):
%  \DeclareInstance{xfrac}{cmor}{text}
%    {
%      slash-symbol-font = ptm,
%      numerator-font    = cmr,
%      denominator-font  = cmr
%   }
% \begin{verbatim}
%   \DeclareInstance{xfrac}{cmor}{text}
%     {
%       slash-symbol-font = ptm,
%       numerator-font    = cmr,
%       denominator-font  = cmr
%     }
% \end{verbatim}
% We also use regular Computer Modern Roman for typesetting ND, so
% we end up with \switch{cmor}{\sfrac{1}{2}} and
% \switch{cmor}{\sfrac{8}{9}} instead of
% \switch{cmor}{\nicefrac{1}{2}} and \switch{cmor}{\nicefrac{8}{9}}.
% Much better.
%
% There are also situations where other tricks are useful. If you
% don't have the inferior and superior figures available in a font,
% or the font doesn't have a wider design for small font sizes, you
% can cheat by manually scaling the ND-pair. I got nice results for
% Adobe's Stempel Garamond (with small caps and old style figures)
% with the following setup:
% \begin{verbatim}
%   \DeclareInstance{xfrac}{pegj}{text}
%     {
%       numerator-font   = pegx,
%       denominator-font = pegx,
%       scale-factor     = 0.9,
%       h-scale          = 1.1
%    }
% \end{verbatim}
% We use the font family |pegx| (Stempel Garamond with real small
% caps) for typesetting the ND-pair. Additionally the key
% \key{scale-factor} specifies that the font size used for the
% ND-pair should be $0.9$ of the height of the solidus, and the key
% \key{h-scale} specifies that the ND-pair should be scaled an extra
% 10\,\% horizontally.
%
% Should you be so fortunate the have a font with inferior and
% superior figures like in the Monotype Janson example from Philipp
% Lehman's excellent \emph{The Font Installation Guide}. In that
% example Philipp defines the font families |mjn0| for the inferior
% figures and |mjn1| for the superior. Thus to get the \cs{sfrac}
% command to use them on the fly for the font family |mjnj| (Janson,
% old style figures) we would say
% \begin{verbatim}
%   \DeclareInstance{xfrac}{mjnj}{text}
%     {
%       numerator-font      = mjn1,
%       denominator-font    = mjn0,
%       scaling             = false,
%       numerator-bot-sep   = 0 pt,
%       denominator-bot-sep = 0 pt
%     }
%   \end{verbatim}
% I think this example is a very clean way to do it. An alternative
% approach could be to use the keys \key{numerator-format} and
% \key{denominator-format} to process the arguments and let them
% determine what to do.
%
% \subsection{Math Mode}
%
% In math mode the choices are a lot fewer because first of all
% \TeX{} comes with a built-in limitation of $16$ math families.
% Additionally we will not need a solidus for typesetting split
% fractions in math, as tradition is to use a virgule instead. We
% define the basic |mathdefault| instance to simply use the math
% family in use when the instance is run. So if we're in normal math
% like |$\sfrac{7}{9}$| we simply get family~$-1$. If we're inside a
% \cs{mathbf} we're in family~$4$ (in the standard setup at least),
% and so the fraction is typeset with the same math family. Simple,
% isn't?
%
% You can also declare instances for the math families, but I really
% don't see why you would. If you do then name them according to the
% scheme \texttt{mathfam\meta{N}}, where \meta{N} is the family number, and
% only do it if you \emph{really} know how to set up math fonts.
% That is, if \cs{DeclareMathAlphabet} is unbeknownst to you, then
% just don't go there.
%
% \section{The Template Interface}
%
% \begin{TemplateInterfaceDescription}{xfrac}
%
% \TemplateArgument{1}{The numerator}
%
% \TemplateArgument{2}{The separator}
%
% \TemplateArgument{3}{The denominator}
%
% \TemplateSemantics
%
% Typesets arguments 1 and 3 separated by argument 2, which in text
% mode by default is a \emph{solidus}. This is taken from
% \pkg{textcomp} where it is denoted \cs{textfractionsolidus}.
% This is the character used for the ready made split level
% fractions such as \textonehalf{}---except in the (European) Computer
% Modern fonts. In math mode a \emph{virgule} is used instead as
% this is more appropriate and it is always available in the math
% fonts. The solidus is a text symbol only.
%
% \end{TemplateInterfaceDescription}
%
% \begin{TemplateDescription}{xfrac}{text}
%
% \TemplateKey{numerator-font}{tokenlist}
%   {Font family specification to use for the numerator.}
%   {\cs{f@family}}
%
% \TemplateKey{numerator-format}{function 1 arg}
%   {Action to be taken on the numerator.}
%   {Process argument unchanged}
%
% \TemplateKey{slash-symbol}{tokenlist}
%   {The separator symbol. If not specified the default value will be
%   used instead.}
%   {Solidus (\cs{textfractionsolidus})}
%
% \TemplateKey{slash-symbol-font}{tokenlist}
%   {Font family specification to use for the separator symbol.}
%   {\cs{f@family}}
%
% \TemplateKey{slash-symbol-format}{function 1 arg}
%   {Action to be taken on the separator symbol.}
%   {Process argument unchanged}
%
% \TemplateKey{denominator-font}{tokenlist}
%   {Font family specification to use for the denominator.}
%   {\cs{f@family}}
%
% \TemplateKey{denominator-format}{function 1 arg}
%   {Action to be taken on the denominator.}
%   {Process argument unchanged}
%
% \TemplateKey{h-scale}{real}
%   {Factor by which the numerator and denominator should be
%   horizontally scaled. It should only be used if the real superior
%   and inferior fonts are not available. For instance Stempel
%   Garamond looks excellent if scaled 10\,\% extra horizontally, \emph{i.e.},
%   by a factor of 1.1.}
%   {1}
%
%  \TemplateKey{v-scale}{real}
%    {Same as \key{h-scale} only vertically. Probably not of much use
%    but added for completeness.}
%    {1}
%
% \TemplateKey{scale-factor}{real}
%   {Fraction of the size of \key{slash-symbol}. Used for setting the
%   font size of numerator and denominator. Usually a value of app.\
%   \sfrac{5}{6} produces fine results. It should only be used if the
%   real superior and inferior fonts are not available. As an example
%   Stempel Garamond looks better if the factor is 0.9.}
%   {0.83333}
%
% \TemplateKey{scale-relative}{choice}
%   {If set to |true| the font size of the numerator and denominator
%   is scaled with respect to the height of the \key{slash-symbol}. If
%   set to |false| the font is scaled with respect to the total height
%   of the \key{slash-symbol}.}
%   {true}
%
% \TemplateKey{scaling}{choice}
%   {If set to |true| the fonts are allowed to scale. If set to
%   |false| they are not. See the `Janson' example for an application.}
%   {true}
%
% \TemplateKey{numerator-top-sep}{length}
%   {Dimension specifying the space between the top of the
%   \key{slash-symbol} and the top of the numerator. If not specified,
%   the depth of the solidus will be used, because this value will
%   make the fraction look even.}
%   {Unspecified}
%
% \TemplateKey{numerator-bot-sep}{length}
%   {Dimension specifying the lift of the numerator from the
%   baseline.}
%   {Unspecified}
%
% \TemplateKey{denominator-bot-sep}{length}
%   {Dimension specifying the lift of the denominator from the
%   baseline.}
%   {Unspecified}
%
% \TemplateKey{slash-right-kern}{length}
%   {Dimension specifying the kerning between the \key{slash-symbol}
%   and the numerator.}
%   {\texttt{0pt}}
%
% \TemplateKey{slash-left-kern}{length}
%   {Dimension specifying the kerning between the \key{slash-symbol}
%   and the denominator.}
%   {\texttt{0pt}}
%
% \TemplateKey{math-mode}{choice}
%   {Are we in math mode or not?}
%   {false}
%
% \TemplateKey{phantom}{tokenlist}
%   {A character that suits the common cases. As we would mostly want
%   to use numbers in text mode we choose a \enquote{tall} number, while in
%   math it is somewhat different.}
%   {8}
%
%  \TemplateSemantics
%
%  This template is also the foundation for the \enquote{math} template. The
%  keys \key{slash-right-mkern} and \key{slash-left-mkern} can only
%  be used in math mode and are not shown here.
%
% \end{TemplateDescription}
%
% \begin{TemplateDescription}{xfrac}{math}
%
% \TemplateKey{numerator-font}{tokenlist}
%   {Font family specification to use for the numerator.}
%   {\cs{number}\cs{fam}}
%
% \TemplateKey{slash-symbol}{tokenlist}
%   {The separator symbol. If not specified the default value will be
%   used instead.}
%   {Virgule ($/$)}
%
% \TemplateKey{slash-symbol-font}{tokenlist}
%   {Font family specification to use for the separator symbol.}
%   {\cs{number}\cs{fam}}
%
% \TemplateKey{denominator-font}{tokenlist}
%   {Font family specification to use for the denominator.}
%   {\cs{number}\cs{fam}}
%
% \TemplateKey{scale-factor}{real}
%   {Fraction of the size of \key{slash-symbol}. In math mode we
%   cannot rely on the fonts to be able to scale, but giving a default
%   scale of 0.7 fits into the regular size changing scheme---the
%   default scheme has values $(D,T,S,SS)=(1,1,0.7,0.5)$ whereas we
%   with a default \key{scale-factor} of 0.7 get $(1,1,0.7,0.49)$.
%   That's close enough.}
%   {0.7}
%
% \TemplateKey{scale-relative}{choice}
%   {If set to |true| the font size of the numerator and denominator
%   is scaled with respect to the height of the \key{slash-symbol}. If
%   set to |false| the font is scaled with respect to the total height
%   of the \key{slash-symbol}.}
%   {false}
%
% \TemplateKey{scaling}{choice}
%   {If set to |true| the fonts are allowed to scale. If set to
%   |false| they are not. See the |plainmath| example for an application.}
%   {true}
%
% \TemplateKey{numerator-top-sep}{length}
%   {Dimension specifying the space between the top of the
%   \key{slash-symbol} and the top of the numerator. If not specified,
%   the depth of the virgule will be used, because this value will
%   make the fraction look even.}
%   {\texttt{0pt}}
%
% \TemplateKey{denominator-bot-sep}{length}
%   {Dimension specifying the lift of the denominator from the
%   baseline.}
%    {\texttt{0pt}}
%
% \TemplateKey{slash-right-mkern}{muskip}
%   {Same as \key{slash-right-kern} but for math mode only and should
%   be specified in \texttt{mu} units.}
%   {\texttt{-2mu}}
%
% \TemplateKey{slash-left-mkern}{muskip}
%   {Same as \key{slash-left-kern} but for math mode only and should
%   be specified in \texttt{mu} units.}
%   {\texttt{-1mu}}
%
% \TemplateKey{math-mode}{choice}
%   {Are we in math mode or not?}
%   {true}
%
% \TemplateKey{phantom}{tokenlist}
%   {A character that suits the common cases. In math we have a high
%   risk of using a parenthesis, so we choose that. Text mode is
%   another story.}
%   {(^^A)
%   }
%
% \TemplateSemantics
%
% This template is a restricted version of the |text| template. Only
% the keys that are different from the |text| template are shown
% here. Also bear in mind that the attributes \key{slash-left-kern}
% and \key{slash-right-kern} have no meaning in this template.
%
% \end{TemplateDescription}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{xfrac} implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=xfrac>
%    \end{macrocode}
%
% Load \pkg{expl3} \enquote{up-front} only if required.
%    \begin{macrocode}
\@ifundefined{ExplLoaderFileDate}
  {\RequirePackage{expl3}}
  {}
%    \end{macrocode}
%
% Make sure that the version of \pkg{l3kernel} in use is sufficiently new.
% We use \cs{ExplFileDate} as \cs{@ifpackagelater} doesn't work for pre-loaded
% \pkg{expl3} in the absence of the package.
%    \begin{macrocode}
\@ifl@t@r\ExplLoaderFileDate{2018-02-21}
  {}
  {%
    \PackageError{xfrac}{Support package expl3 too old}
      {%
        You need to update your installation of 'l3kernel'.\MessageBreak
        Loading~xfrac~will~abort!%
      }%
    \endinput
  }%
%    \end{macrocode}
%
%    \begin{macrocode}
\ProvidesExplPackage{xfrac}{2024-06-04}{}
  {Split-level fractions}
%    \end{macrocode}
%
% \begin{macro}{\IfFormatAtLeastTF}
%   Not present in older kernels: use the \LaTeXe{} mechanism as this is correct
%   for this case.
%    \begin{macrocode}
\providecommand \IfFormatAtLeastTF { \@ifl@t@r \fmtversion }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\IfFormatAtLeastTF { 2020-02-02 }
  { }
  { \RequirePackage { textcomp } }
%    \end{macrocode}
%
%    \begin{macrocode}
\IfFormatAtLeastTF { 2020-10-01 }
  { }
  { \RequirePackage { xparse } }
%    \end{macrocode}
%
% \begin{variable}{\l_@@_cm_std_bool}
%   There is one option to support.
%    \begin{macrocode}
\keys_define:nn { xfrac }
  {
    cm-recommended .choice:,
    cm-recommended /
      false        .code:n     =
        { \bool_set_true:N \l_@@_cm_std_bool },
    cm-recommended /
      true         .code:n     =
        { \bool_set_false:N \l_@@_cm_std_bool },
    cm-recommended .default:n  = { true },
    cm-standard    .bool_set:N = \l_@@_cm_std_bool
  }
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
\IfFormatAtLeastTF { 2022-06-01 }
  { \ProcessKeyOptions }
  {
    \RequirePackage { l3keys2e }
    \ProcessKeysOptions { xfrac }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\IfFormatAtLeastTF { 2024-06-01 }
  { }
  { \RequirePackage { xtemplate } }
\cs_if_exist:NF \IfInstanceExistsTF
  { \cs_new_eq:NN \IfInstanceExistsTF \IfInstanceExistTF }
%    \end{macrocode}
%
% \begin{variable}{\l_@@_slash_box}
% \begin{variable}{\l_@@_tmp_box}
%   In keeping with the \LaTeX3 philosophy, rather than use generic
%   scratch boxes and get confused, \pkg{xfrac} reserves its own named
%   working space.
%    \begin{macrocode}
\box_new:N \l_@@_slash_box
\box_new:N \l_@@_tmp_box
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\@@_tmp:w}
%   Used for the raised boxes: weird as it does not take an argument
%    but the \cs{raisebox} does.
%    \begin{macrocode}
\cs_new:Npn \@@_tmp:w { }
%    \end{macrocode}
% \end{macro}
%
%
% \subsection{Initialisation of variables}
%
% Variables used in templates have to be set up: there is not
% much to say about these, other than that they must exist.
%
% \begin{variable}{\l_@@_denominator_bot_sep_dim}
% \begin{variable}{\l_@@_numerator_bot_sep_dim}
% \begin{variable}{\l_@@_numerator_top_sep_dim}
% \begin{variable}{\l_@@_slash_left_sep_dim}
% \begin{variable}{\l_@@_slash_right_sep_dim}
% Fixed lengths.
%    \begin{macrocode}
\dim_new:N \l_@@_denominator_bot_sep_dim
\dim_new:N \l_@@_numerator_bot_sep_dim
\dim_new:N \l_@@_numerator_top_sep_dim
\dim_new:N \l_@@_slash_left_sep_dim
\dim_new:N \l_@@_slash_right_sep_dim
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_slash_left_muskip}
% \begin{variable}{\l_@@_slash_right_muskip}
%   Math mode skips.
%    \begin{macrocode}
\muskip_new:N \l_@@_slash_left_muskip
\muskip_new:N \l_@@_slash_right_muskip
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_hscale_fp}
% \begin{variable}{\l_@@_scale_factor_fp}
% \begin{variable}{\l_@@_vscale_fp}
%   Floating point values.
%    \begin{macrocode}
\fp_new:N \l_@@_hscale_fp
\fp_new:N \l_@@_scale_factor_fp
\fp_new:N \l_@@_vscale_fp
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_denominator_font_tl}
% \begin{variable}{\l_@@_numerator_font_tl}
% \begin{variable}{\l_@@_phantom_tl }
% \begin{variable}{\l_@@_slash_symbol_tl}
% \begin{variable}{\l_@@_slash_symbol_font_tl}
%   Token lists, which include floating-point numbers and math(s)
%   skips.
%    \begin{macrocode}
\tl_new:N \l_@@_denominator_font_tl
\tl_new:N \l_@@_numerator_font_tl
\tl_new:N \l_@@_phantom_tl
\tl_new:N \l_@@_slash_symbol_tl
\tl_new:N \l_@@_slash_symbol_font_tl
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\@@_fontscale:}
% \begin{macro}{\@@_math:n}
% \begin{macro}{\@@_denominator_font_change:}
% \begin{macro}{\@@_denominator_format:n}
% \begin{macro}{\@@_numerator_font_change:}
% \begin{macro}{\@@_numerator_format:n}
% \begin{macro}{\@@_relscale:}
% \begin{macro}{\@@_slash_symbol_font_change:}
% \begin{macro}{\@@_slash_symbol_format:n}
% \begin{macro}{\@@_text_or_math:n}
%   Functions, either things which are calculated \enquote{on the fly}
%   (no argument required) or are functions taking one argument in the
%   code.
%    \begin{macrocode}
\cs_new:Npn \@@_fontscale: { }
\cs_new:Npn \@@_math:n #1 { }
\cs_new:Npn \@@_denominator_font_change: { }
\cs_new:Npn \@@_denominator_format:n #1 { }
\cs_new:Npn \@@_numerator_font_change: { }
\cs_new:Npn \@@_numerator_format:n #1 { }
\cs_new:Npn \@@_relscale: { }
\cs_new:Npn \@@_slash_symbol_font_change: { }
\cs_new:Npn \@@_slash_symbol_format:n #1 { }
\cs_new:Npn \@@_text_or_math:n #1 { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{The template}
%
% There is only one object type in \pkg{xfrac}, rather unimaginatively
% named \texttt{xfrac}.
%    \begin{macrocode}
\IfFormatAtLeastTF { 2024-06-01 }
  { \NewTemplateType }
  { \DeclareObjectType }
    { xfrac } { 3 }
%    \end{macrocode}
%
% A single template interface is used for both text and math(s), which
% does make a few things a little complex later.
%    \begin{macrocode}
\DeclareTemplateInterface { xfrac } { text } { 3 }
  {
    denominator-bot-sep : length     = \c_max_dim           ,
    denominator-font    : tokenlist  = \f@family            ,
    denominator-format  : function 1 = #1                   ,
    h-scale             : real       = 1                    ,
    math-mode           : choice { false , true }
                                   = false                  ,
    numerator-font      : tokenlist  = \f@family            ,
    numerator-format    : function 1 = #1                   ,
    numerator-bot-sep   : length     = \c_max_dim           ,
    numerator-top-sep   : length     = \c_max_dim           ,
    phantom             : tokenlist  = 8                    ,
    scale-factor        : real       = 0.83333              ,
    scale-relative      : choice { false , true }
                                     = true                 ,
    scaling             : choice { false , true }
                                     = true                 ,
    slash-left-kern     : length     = 0 pt                 ,
    slash-left-mkern    : muskip     = -2 mu                ,
    slash-right-kern    : length     = 0 pt                 ,
    slash-right-mkern   : muskip     = -1 mu                ,
    slash-symbol        : tokenlist  = \textfractionsolidus ,
    slash-symbol-font   : tokenlist  = \f@family            ,
    slash-symbol-format : function 1 = #1                   ,
    v-scale             : real       = 1                    ,
  }
%    \end{macrocode}
% Most of the variable binding is quite simple: of course, the choices
% are a little more complicated. That is particularly true where
% these have to set up \enquote{on the fly} functions.
%    \begin{macrocode}
\DeclareTemplateCode { xfrac } { text } { 3 }
  {
    denominator-bot-sep = \l_@@_denominator_bot_sep_dim ,
    denominator-font    = \l_@@_denominator_font_tl     ,
    denominator-format  = \@@_denominator_format:n      ,
    h-scale             = \l_@@_hscale_fp               ,
    math-mode           =
      {
        false = \cs_set_eq:NN \@@_math:n \use:n,
        true  = \cs_set_eq:NN \@@_math:n \ensuremath
      },
    numerator-font      = \l_@@_numerator_font_tl       ,
    numerator-format    = \@@_numerator_format:n        ,
    numerator-bot-sep   = \l_@@_numerator_bot_sep_dim   ,
    numerator-top-sep   = \l_@@_numerator_top_sep_dim   ,
    phantom             = \l_@@_phantom_tl              ,
    scale-factor        = \l_@@_scale_factor_fp         ,
    scale-relative      =
      {
        false =
          \cs_set:Npn \@@_relscale:
            {
              \dim_eval:n
                { \box_ht:N \l_@@_tmp_box + \box_dp:N \l_@@_tmp_box }
            },
        true  =
          \cs_set:Npn \@@_relscale:
            { \dim_eval:n { \box_ht:N \l_@@_slash_box } }
      },
    scaling             =
      {
        false = \cs_set_eq:NN \@@_fontscale: \prg_do_nothing:,
        true  =
          \cs_set:Npn \@@_fontscale:
            {
              \fontsize
                { \fp_to_dim:n { \l_@@_scale_factor_fp * \@@_relscale: } }
                { \c_zero_dim }
              \selectfont
            }
      },
    slash-left-kern     = \l_@@_slash_left_sep_dim      ,
    slash-left-mkern    = \l_@@_slash_left_muskip       ,
    slash-right-kern    = \l_@@_slash_right_sep_dim     ,
    slash-right-mkern   = \l_@@_slash_right_muskip      ,
    slash-symbol        = \l_@@_slash_symbol_tl         ,
    slash-symbol-font   = \l_@@_slash_symbol_font_tl    ,
    slash-symbol-format = \@@_slash_symbol_format:n     ,
    v-scale             = \l_@@_vscale_fp
  }
%    \end{macrocode}
% The implementation part starts with applying all of the settings
% from above. The first part of the set up is then to determine
% whether the surroundings are text or math(s), and react accordingly.
%    \begin{macrocode}
  {
    \mode_if_math:TF
      {
        \cs_set_eq:NN \@@_text_or_math:n \text
        \cs_set:Npe \@@_denominator_font_change:
          { \tex_fam:D \l_@@_denominator_font_tl }
        \cs_set:Npe \@@_numerator_font_change:
          { \tex_fam:D \l_@@_numerator_font_tl }
        \cs_set:Npe \@@_slash_symbol_font_change:
          { \tex_fam:D \l_@@_slash_symbol_font_tl }
      }
      {
        \cs_set_eq:NN \@@_text_or_math:n \mbox
        \cs_set:Npn \@@_denominator_font_change:
          {
            \fontfamily { \l_@@_denominator_font_tl }
            \selectfont
          }
        \cs_set:Npn \@@_numerator_font_change:
          {
            \fontfamily { \l_@@_numerator_font_tl }
            \selectfont
          }
        \cs_set:Npn \@@_slash_symbol_font_change:
          {
            \fontfamily { \l_@@_slash_symbol_font_tl }
            \selectfont
          }
      }
%    \end{macrocode}
% Everything is now either inside \cs{text} or an \cs{mbox}, depending
% upon the surroundings. First, there are some boxes to set up.
%    \begin{macrocode}
    \@@_text_or_math:n
      {
        \m@th
        \hbox_set:Nn \l_@@_tmp_box
          { \@@_math:n { \vphantom { ( ) } } }
        \hbox_set:Nn \l_@@_slash_box
          {
            \@@_math:n
              {
                \@@_slash_symbol_format:n
                  {
                    \@@_math:n
                      {
                        \@@_slash_symbol_font_change:
                        \IfNoValueTF {#2}
                          { \l_@@_slash_symbol_tl } {#2}
                      }
                  }
              }
          }
%    \end{macrocode}
% Check on the numerator separator dimensions. The code starts with the
% assumption that neither has been given, as this can then be used to
% set up a default, which is also used when both values are set
% erroneously.
%    \begin{macrocode}
        \cs_set:Npn \@@_tmp:w
          {
            \raisebox
              {
                \dim_eval:n
                  {
                    \box_ht:N \l_@@_slash_box
                    - \box_dp:N \l_@@_slash_box
                    - \height
                  }
              }
          }
        \dim_compare:nNnTF
          { \l_@@_numerator_top_sep_dim } = { \c_max_dim }
          {
            \dim_compare:nNnF
              { \l_@@_numerator_bot_sep_dim } = { \c_max_dim }
              {
                \cs_set:Npn \@@_tmp:w
                  {
                    \raisebox
                      { \dim_use:N \l_@@_numerator_bot_sep_dim }
                  }
              }
          }
          {
            \dim_compare:nNnTF
              { \l_@@_numerator_bot_sep_dim } = { \c_max_dim }
                {
                  \cs_set:Npn \@@_tmp:w
                    {
                      \raisebox
                        {
                          \dim_eval:n
                            {
                              \box_ht:N \l_@@_slash_box
                              - \dim_use:N \l_@@_numerator_top_sep_dim
                              - \height
                            }
                        }
                    }
                }
                {
                  \msg_error:nn { xfrac }
                    { over-specified-numerator-sep }
                }
          }
%    \end{macrocode}
%  Typeset the numerator.
%    \begin{macrocode}
        \@@_tmp:w
          {
            \@@_fontscale:
            \@@_numerator_format:n
              {
                \scalebox
                  { \fp_use:N \l_@@_hscale_fp }
                  [ \fp_use:N \l_@@_vscale_fp ]
                  {
                    \@@_math:n
                      {
                        \@@_numerator_font_change:
                        {
                          \vphantom { \l_@@_phantom_tl }
                          #1
                        }
                      }
                  }
              }
          }
        \@@_math:n
          { % THIS IS JUST WRONG!
            \mode_if_math:TF
              { \tex_mskip:D \l_@@_slash_right_muskip }
              { \tex_hskip:D \l_@@_slash_right_sep_dim }
          }
%    \end{macrocode}
%  Typeset the separator.
%    \begin{macrocode}
        \box_use:N \l_@@_slash_box
        \@@_math:n
          {
            \mode_if_math:TF
              { \tex_mskip:D \l_@@_slash_left_muskip }
              { \tex_hskip:D \l_@@_slash_left_sep_dim }
          }
%    \end{macrocode}
%  Typeset the denominator.
%    \begin{macrocode}
        \dim_compare:nNnTF
          { \l_@@_denominator_bot_sep_dim } = { \c_max_dim }
          {
            \cs_set:Npn \@@_tmp:w
              { \raisebox { - \box_dp:N \l_@@_slash_box } }
          }
          {
            \cs_set:Npn \@@_tmp:w
              {
                \raisebox
                  { \dim_use:N \l_@@_denominator_bot_sep_dim }
              }
          }
        \@@_tmp:w
          {
            \@@_fontscale:
            \@@_denominator_format:n
              {
                \scalebox
                  { \fp_use:N \l_@@_hscale_fp }
                  [ \fp_use:N \l_@@_vscale_fp ]
                  {
                    \@@_math:n
                      {
                        \@@_denominator_font_change:
                        {
                          \vphantom { \l_@@_phantom_tl }
                          #3
                        }
                      }
                  }
              }
          }
      }
  }
%    \end{macrocode}
%
% Since math(s) and text mode are wildly different entities we define a
% separate template for each. You already saw the \enquote{text}
% template, and here is the \enquote{math} template.
%    \begin{macrocode}
\IfFormatAtLeastTF { 2024-06-01 }
  {
    \DeclareTemplateCopy { xfrac } { math } { text }
    \EditTemplateDefaults { xfrac } { math }
  }
  { \DeclareRestrictedTemplate { xfrac } { text } { math } }
    {
      numerator-font      = \number \fam ,
      slash-symbol        = /            ,
      slash-symbol-font   = \number \fam ,
      denominator-font    = \number \fam ,
      scale-factor        = 0.7          ,
      scale-relative      = false        ,
      scaling             = true         ,
      denominator-bot-sep = 0 pt         ,
      math-mode           = true         ,
      phantom             = ( % )
    }
%    \end{macrocode}
%
%\subsection{The standard instances}
%
% For the default instances we just use the relevant templates with
% the default settings.
%
%  The default \enquote{text} instance.
%    \begin{macrocode}
\DeclareInstance { xfrac } { default } { text } { }
%    \end{macrocode}
%
%  The default \enquote{math(s)} instance. We annot set the
%  |numerator-top-sep| in the restricted template above.
%    \begin{macrocode}
\DeclareInstance { xfrac } { mathdefault } { math }
  { numerator-top-sep = 0pt }
%    \end{macrocode}
%
% Default Computer Modern setup. Far from optimal, but better than
% nothing.
%    \begin{macrocode}
\DeclareInstance { xfrac } { cmr } { text }
  {
    denominator-bot-sep = 0 pt    ,
    numerator-top-sep   = 0.2 ex  ,
    slash-left-kern     = -0.1 em ,
    slash-right-kern    = -0.1 em
  }
\DeclareInstance { xfrac } { cmss } { text }
  {
    denominator-bot-sep = 0 pt    ,
    numerator-top-sep   = 0.2 ex  ,
    slash-left-kern     = -0.1 em ,
    slash-right-kern    = -0.1 em
  }
\DeclareInstance { xfrac } { cmtt } { text }
  {
    denominator-bot-sep = 0 pt    ,
    numerator-top-sep   = 0.2 ex  ,
    slash-left-kern     = -0.1 em ,
    slash-right-kern    = -0.1 em
  }
%    \end{macrocode}
%
% We can do better for the Computer Modern fonts. For cmr and cmss
% we choose Times, and for cmtt use Palatino.
%    \begin{macrocode}
\bool_if:NF \l_@@_cm_std_bool
  {
    \DeclareInstance { xfrac } { cmr } { text }
      { slash-symbol-font = ptm }
    \DeclareInstance { xfrac } { cmss } { text }
      { slash-symbol-font = ptm }
    \DeclareInstance { xfrac } { cmtt } { text }
      { slash-symbol-font = ppl }
  }
%    \end{macrocode}
%
% Things works slightly better with Latin Modern.
%    \begin{macrocode}
\DeclareInstance { xfrac } { lmr } { text }
  {
    denominator-bot-sep = 0 pt     ,
    numerator-top-sep   = 0.1 ex   ,
    slash-left-kern     = -0.15 em ,
    slash-right-kern    = -0.15 em
  }
\DeclareInstance { xfrac } { lmss } { text }
  {
    denominator-bot-sep = 0 pt     ,
    numerator-top-sep   = 0 pt     ,
    slash-left-kern     = -0.15 em ,
    slash-right-kern    = -0.15 em
  }
\DeclareInstance { xfrac } { lmtt } { text }
  {
    denominator-bot-sep = 0 pt     ,
    numerator-top-sep   = 0 pt     ,
    slash-left-kern     = -0.15 em ,
    slash-right-kern    = -0.15 em
  }
%    \end{macrocode}
%
% \subsection{The user command}
%
% \begin{macro}{\sfrac}
%   Currently there is just a single user command. \cs{sfrac} takes
%   two mandatory arguments: numerator and denominator. It can take an
%   optional argument between the mandatory specifying the separator
%   like this:
%   \begin{verbatim}
%     \sfrac{7}[/]{12}
%   \end{verbatim}
%   It also has an optional argument that comes before the first
%   mandatory argument. If used it will use that instance instead of
%   the auto-detected one, so a user who has defined the instance
%   \enquote{cmr2} may use
%   \begin{verbatim}
%     \sfrac[cmr2]{7}{12}
%   \end{verbatim}
%   and get the settings from \enquote{cmr2} instead of the settings of
%   the current font family.
%    \begin{macrocode}
\NewDocumentCommand \sfrac { o m o m }
  {
    \mode_if_math:TF
      {
        \IfInstanceExistsTF { xfrac } { mathfam \number \fam }
          { \UseInstance { xfrac } { mathfam \number \fam } }
          { \UseInstance { xfrac } { mathdefault } }
        {#2} {#3} {#4}
      }
      {
        \IfInstanceExistsTF { xfrac } {#1}
          { \UseInstance { xfrac } {#1} }
          {
            \IfInstanceExistsTF { xfrac } { \f@family }
              { \UseInstance { xfrac } { \f@family } }
              { \UseInstance { xfrac } { default } }
          }
        {#2} {#3} {#4}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Messages}
%
% Just the one.
%    \begin{macrocode}
\msg_new:nnnn { xfrac } { over-specified-numerator-sep }
  { You~have~specified~both~"numerator-top-sep"~and~"numerator-bot-sep". }
  { I~will~pretend~that~you~didn't~specify~either~of~them. }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
