% \iffalse meta-comment % %% File: xfrac.dtx % % Copyright (C) 2004,2008-2010 Morten Hoegholm % (C) 2011,2012,2014-2020 The LaTeX3 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 "l3packages bundle" (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/latex3 % % for those people who are interested. % %<*driver|package> % The version of expl3 required is tested as early as possible, as % some really old versions do not define \ProvidesExplPackage. \RequirePackage{expl3}[2018/02/21] %\@ifpackagelater{expl3}{2018/02/21} % {} % {% % \PackageError{xfrac}{Support package l3kernel too old} % {% % Please install an up to date version of l3kernel\MessageBreak % using your TeX package manager or from CTAN.\MessageBreak % \MessageBreak % Loading xfrac will abort!% % }% % \endinput % } \RequirePackage{amstext,graphicx,l3keys2e,textcomp,xparse,xtemplate} % %<*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} % % \fi % % \title{^^A % The \textsf{xfrac} package\\ Split-level fractions^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released 2020-05-15} % % \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. % % Another example: If we want \cs{sfrac} to produce split fractions % without doing anything at all, we can choose the collection % |plainmath|, which is defined as % \begin{verbatim} % \DeclareCollectionInstance{plainmath}{xfrac}{mathdefault}{math} % { % denominator-bot-sep = 0 pt, % numerator-bot-sep = 0 pt, % numerator-top-sep = \c_max_dim, % scaling = false, % slash-right-mkern = 0 mu, % slash-left-mkern = 0 mu % } % \end{verbatim} % This creates an alternative version of the instance |mathdefault| % with settings as specified by the keys. In the default math setup % \key{numerator-top-sep} is set to 0~pt, and here we set % \key{numerator-bot-sep} to 0~pt as well, so in order to avoid % over-specification (and an error message) we must set % \key{numerator-top-sep} to \cs{c_max_dim}. We activate (obeying % normal scoping rules) it with: % \begin{verbatim} % \UseCollection{xfrac}{plainmath} % \end{verbatim} % Then |$\sfrac{8}{13}$| produces^^A % \begingroup % \UseCollection{xfrac}{plainmath} % $\sfrac{8}{13}$ and just typing |$8/13$| gives the same result: % $8/13$. % \endgroup % % \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} % % \begin{macrocode} \ProvidesExplPackage{xfrac}{2020-05-15}{} {L3 Experimental split-level fractions} % \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 } \ProcessKeysOptions { xfrac } % \end{macrocode} % \end{variable} % % \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} \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} { \AssignTemplateKeys \mode_if_math:TF { \cs_set_eq:NN \@@_text_or_math:n \text \cs_set:Npx \@@_denominator_font_change: { \tex_fam:D \l_@@_denominator_font_tl } \cs_set:Npx \@@_numerator_font_change: { \tex_fam:D \l_@@_numerator_font_tl } \cs_set:Npx \@@_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} \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 , numerator-top-sep = 0 pt , 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. % \begin{macrocode} \DeclareInstance { xfrac } { mathdefault } { math } { } % \end{macrocode} % % \begin{macrocode} \DeclareCollectionInstance { plainmath } { xfrac } { mathdefault } { math } { denominator-bot-sep = 0 pt , numerator-bot-sep = 0 pt , numerator-top-sep = \c_max_dim , scale-factor = 1 , scale-relative = false , scaling = true , slash-right-mkern = 0 mu , slash-left-mkern = 0 mu } % \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} % % \end{macrocode} % % \end{implementation} % % \PrintIndex