summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/xfrac/xfrac.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/xfrac/xfrac.dtx')
-rw-r--r--macros/latex/contrib/xfrac/xfrac.dtx1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/macros/latex/contrib/xfrac/xfrac.dtx b/macros/latex/contrib/xfrac/xfrac.dtx
new file mode 100644
index 0000000000..55c26ca76f
--- /dev/null
+++ b/macros/latex/contrib/xfrac/xfrac.dtx
@@ -0,0 +1,1146 @@
+% \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-02-13}
+%
+% \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-02-13}{}
+ {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 } }
+% \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
+ {
+ \IfInstanceExistTF { xfrac } { mathfam \number \fam }
+ { \UseInstance { xfrac } { mathfam \number \fam } }
+ { \UseInstance { xfrac } { mathdefault } }
+ {#2} {#3} {#4}
+ }
+ {
+ \IfInstanceExistTF { xfrac } {#1}
+ { \UseInstance { xfrac } {#1} }
+ {
+ \IfInstanceExistTF { 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