summaryrefslogtreecommitdiff
path: root/macros/optex/base/unimath-macros.opm
diff options
context:
space:
mode:
Diffstat (limited to 'macros/optex/base/unimath-macros.opm')
-rw-r--r--macros/optex/base/unimath-macros.opm404
1 files changed, 404 insertions, 0 deletions
diff --git a/macros/optex/base/unimath-macros.opm b/macros/optex/base/unimath-macros.opm
new file mode 100644
index 0000000000..96f87a6a9b
--- /dev/null
+++ b/macros/optex/base/unimath-macros.opm
@@ -0,0 +1,404 @@
+%% This is part of the OpTeX project, see http://petr.olsak.net/optex
+
+\_codedecl \loadmath {Unicode Math fonts <2022-12-01>} % preloaded in format
+
+ \_doc -----------------------------
+ \`\loadmath` `{<Unicode-math font>}` loads the given font. It does:
+ \begitems
+ * define \`\_unimathfont` as `<Unicode-math font>`,
+ * redefine `\normalmath` and `\boldmath` macros to their Unicode counterparts,
+ * load the `\_unimathfont` by `\normalmath`,
+ * print information about the loaded font on the terminal,
+ * redefine all encoding dependent setting by `\input unimath-codes.opm`,
+ * protect new loading by setting \`\_ifmathloading` to false.
+ \enditems
+ \`\noloadmath` disallows Unicode-math loading by \`\_mathloadingfalse`.\nl
+ \`\doloadmath` allows Unicode-math loading by \`\_mathloadingtrue`.
+ \_cod -----------------------------
+
+\_newifi \_ifmathloading \_mathloadingtrue
+
+\_def\_noloadmath{\_mathloadingfalse}
+\_def\_doloadmath{\_mathloadingtrue}
+
+\_def\_loadmath#1{%
+ \_ifmathloading
+ \_initunifonts
+ \_isfont{#1}\_iffalse
+ \_opwarning{Math font "#1" not found, skipped...}%
+ \_else
+ \_def\_unimathfont{#1}%
+ \_let\_normalmath = \_normalunimath \_let\_boldmath = \_boldunimath
+ \_normalmath
+ \_wterm {MATH-FONT: "#1" -- unicode math prepared.}%
+ \_ifx\_ncharrmA\_undefined \_opinput {unimath-codes.opm}\_fi
+ \_mathloadingfalse
+ \_fi\_fi}
+
+\_public \loadmath \noloadmath \doloadmath ;
+
+ \_doc -----------------------------
+ \`\loadboldmath` `{<bold-font>} \to {<normal-font>}`
+ defines \`\_unimathboldfont` as `<bold-font>` only if `\_unimathfont` is
+ defined as `<normal-font>`. It is used when \^`\boldmath` macro is run.
+ When no `\_unimathboldfont` is defined then the `\boldmath` macro
+ use \"fake bold" generated by `embolden` \LuaTeX/ font feature.
+ \_cod -----------------------------
+
+\_def\_loadboldmath#1#2\to #3{%
+ \_def\_tmp{#3}\_ifx\_unimathfont\_tmp % do work only if #3 is loaded as normal Math
+ \_isfont{#1}\_iffalse
+ \_opwarning{Bold-Math font "#1" not found, skipped...}
+ \_else
+ \_def\_unimathboldfont{#1}%
+ \_wterm {MATH-FONT: "#1" -- unicode math bold prepared.}%
+ \_fi\_fi}
+
+\_public \loadboldmath ;
+
+ \_doc -----------------------------
+ The Unicode version of the \^`\normalmath` and \^`\boldmath` macros
+ are defined here as \`\_normalunimath` and \`\_boldunimath` macros.
+ They are using \`\_setunimathdimens` in a similar sense as
+ \^`\_setmathdimens`.
+ \nl
+ You can combine more fonts if you register them to another
+ math families (5, 6, 7, etc.) in the \^`\normalmath` macro.
+ \nl
+ The default value of \^`\_normalunimath` shows a combination of base Unicode-math
+ font at family 1 with 8bit Math font at family 4. See definition of `\script` macro where
+ `\fam4` is used.
+ \_cod -----------------------------
+
+\_def\_normalunimath{%
+ \_setmathfamily 0 \_tenrm % font for non-math objects in math mode
+ \_loadumathfamily 1 {\_unimathfont}{} % Base font
+ \_loadmathfamily 4 rsfs % script
+ \_setunimathdimens
+}%
+\_def\_boldunimath{%
+ \_setmathfamily 0 \_tenbf % font for non-math objects in math mode
+ \_ifx\_unimathboldfont \_undefined
+ \_loadumathfamily 1 {\_unimathfont}{embolden=1.7;} % Base faked bold
+ \_else
+ \_loadumathfamily 1 {\_unimathboldfont}{} % Base real bold font
+ \_fi
+ \_loadmathfamily 4 rsfs % script
+ \_setunimathdimens
+}%
+\_def\_setunimathdimens{% PlainTeX sets these dimens for 10pt size only:
+ \_delimitershortfall=0.5\_fontdimen6\_textfont1
+ \_nulldelimiterspace=0.12\_fontdimen6\_textfont1
+ \_setmathparam\_Umathspaceafterscript \_scriptspacefactor
+ \_setbox0=\_hbox{\_everymath{}$\_fam1\_displaystyle{0\_atop0}$}%
+ \_Umathfractiondelsize\_displaystyle = \_dimexpr(\_ht0-\_Umathaxis\_displaystyle)*2\_relax
+ \_setbox0=\_box\_voidbox
+}
+
+ \_doc -----------------------------
+ If you try the example above about
+ \~`\loadboldmath``{[xitsmath-bold]} \to {[xitsmath-regular]}`
+ then you can find a bug in XITSMath-Bold font: the symbols for norm
+ $\|x\|$ are missing. So, we have to define `\_boldmath` macro manually.
+ The missing symbol is loaded from family 5 as no-bold variant in our example:
+ \begtt
+ \loadmath{[xitsmath-regular]}
+ \def\_boldmath{%
+ \_loadumathfamily 1 {[xitsmath-bold]}{} % Base font
+ \_loadmathfamily 4 rsfs % script
+ \_loadumathfamily 5 {[xitsmath-regular]}{}
+ \_def\|{\_Udelimiter 0 5 "02016 }% % norm delimiter from family 5
+ \_setmathdimens
+ }
+ \endtt
+
+ \`\_loadumathfamily` `<number> {<font>}{<font features>}`
+ loads the given Unicode-math fonts in three sizes
+ using single <font> with different `mathsize=1,2,3` font features.
+ The math font family is set with given `<number>`.
+ The `<font features>` are added to the default
+ \`\_mfontfeatures` and to the size-dependent features `ssty=1`
+ if script size is asked or `ssty=2` if scriptscriptsize is asked.\nl
+ \`\_mparams` can insert additional font features
+ dependig on the current `\_mfam`.\nl
+ The \^`\_mfactor` `<family><space>` sets scaling factor,
+ see section~\ref[math-preload] for more information.\nl
+ The \`\_textmff`, \`\_scriptmff` and \`\_sscriptmff` are font
+ features for text, script and sscript sizes respectively. They are
+ locally re-defined in \^`\mathbox` macro.
+ \_cod -----------------------------
+
+\_def\_umathname#1#2{"#1:\_mfontfeatures#2"}
+\_def\_mfontfeatures{mode=base;script=math;}
+
+\_def\_loadumathfamily{\_afterassignment\_loadumathfamilyA \_chardef\_mfam}
+\_def\_loadumathfamilyA #1#2 {\_mfactor
+ \_font\_mF \_umathname{#1}{\_textmff \_mparams #2} at\_sizemtext \_textfont \_mfam=\_mF
+ \_font\_mF \_umathname{#1}{\_scriptmff \_mparams #2} at\_sizemtext \_scriptfont \_mfam=\_mF
+ \_font\_mF \_umathname{#1}{\_sscriptmff\_mparams #2} at\_sizemtext \_scriptscriptfont\_mfam=\_mF
+}
+\_def\_textmff {ssty=0;mathsize=1;}
+\_def\_scriptmff {ssty=1;mathsize=2;}
+\_def\_sscriptmff{ssty=2;mathsize=3;}
+\_def\_mparams{}
+
+ \_doc -----------------------------
+ Unicode math font includes all typical math alphabets together, user needs not to
+ load more \TeX/ math families. These math alphabets are encoded by
+ different parts of Unicode table. We need auxiliary macros for setting
+ mathcodes by selected math alphabet.
+ \nl
+ \`\_umathrange` `{<from->-<to>}<class><family>\<first>` sets `\Umathcode`s
+ of the characters in the interval `<from>-<to>` to `\<first>`,
+ `\<first>+1`, `\<first>+2`
+ etc., but \`\_umathcharholes` are skipped
+ (`\_umathcharholes` are parts of the Unicode table not designed for math
+ alphabets, they cause that the math alphabets are
+ not continuously spread out in the table; I mean that the
+ designers were under the influence of drugs when they created
+ this part of the Unicode table).
+ The `<from>-<to>` clause includes characters like~`A-Z`.
+ \nl
+ \`\_umahrangegreek` `\<first>` is the same as
+ `\_umathrange {<alpha>-<omega>}\<first>`.
+ \nl
+ \`\_umahrangeGREEK` `\<first>` is the same as
+ `\_umathrange {<Alpha>-<Omega>}\<first>`.
+ \nl
+ \`\_greekdef` `<control sequences> \_relax` defines each control sequence
+ as a normal character with codes `\_umathnumB`, `\_umathnumB+1`,
+ `\_umathnumB+2` etc. It is used for redefinig the contol sequences for
+ math Greek `\alpha`, `\beta`, `\gamma` etc.
+ \_cod -----------------------------
+
+\_newcount\_umathnumA \_newcount\_umathnumB
+
+\_def\_umathcorr#1#2{\_ea#1\_ea{\_the#2}}
+\_def\_umathprepare#1{\_def\_umathscanholes##1[#1]##2##3\_relax{##2}}
+\_def\_umathvalue#1{\_ea\_umathscanholes\_umathcharholes[#1]{#1}\_relax}
+
+\_def\_umathcharholes{% holes in math alphabets:
+ [119893]{"210E}[119965]{"212C}[119968]{"2130}[119969]{"2131}%
+ [119971]{"210B}[119972]{"2110}[119975]{"2112}[119976]{"2133}[119981]{"211B}%
+ [119994]{"212F}[119996]{"210A}[120004]{"2134}%
+ [120070]{"212D}[120075]{"210C}[120076]{"2111}[120085]{"211C}[120093]{"2128}%
+ [120122]{"2102}[120127]{"210D}[120133]{"2115}[120135]{"2119}
+ [120136]{"211A}[120137]{"211D}[120145]{"2124}%
+}
+\_def\_umathrange#1#2#3#4{\_umathnumB=#4\_def\_tmp{#2 #3 }\_umathrangeA#1}
+\_def\_umathrangeA#1-#2{\_umathnumA=`#1\_relax
+ \_loop
+ \_umathcorr\_umathprepare\_umathnumB
+ \_Umathcode \_umathnumA = \_tmp \_umathcorr\_umathvalue{\_umathnumB}
+ \_ifnum\_umathnumA<`#2\_relax
+ \_advance\_umathnumA by1 \_advance\_umathnumB by1
+ \_repeat
+}
+\_def\_umathrangeGREEK{\_umathrange{^^^^0391-^^^^03a9}}
+\_def\_umathrangegreek{\_umathrange{^^^^03b1-^^^^03d6}}
+\_def\_greekdef#1{\_ifx#1\_relax \_else
+ \_begingroup \_lccode`X=\_umathnumB \_lowercase{\_endgroup \_def#1{X}}%
+ \_advance\_umathnumB by 1
+ \_ea\_greekdef \_fi
+}
+
+ \_doc -----------------------------
+ \`\addUmathfont` `<fam> {[<normal-font>]}{<ffeatures>} {[<bold-font>]}{<ffeatures>} {<factor>}`
+ allocates new <fam> using \^`\newfam` and adds loading this font to the
+ \~`\normalmath` and \~`\boldmath` macros. Note that allocationos using
+ \^`\newfam` starts from 43 because numbers 1--42 are reserved for direct
+ usage without \^`\newfam`.
+ We use \^`\aheadto` here because we want to read the main family 1 as
+ last one (for definitive setting of math parameters).
+ \_cod -----------------------------
+
+\_def\_addUmathfont #1#2#3#4#5#6{% #1: fam (will be set), #2#3: normal font, #4#5: bold font
+ \_ifx\_ncharrmA\_undefined \_errmessage{basic Unicode math font must be loaded first}%
+ \_else \_isfont{#2}\_iffalse \_opwarning{font #2 is unavailable}%
+ \_else
+ \_newfam#1\_relax
+ \_sdef{_mfactor:\_the\_numexpr#1\_relax}{#6}%
+ \_global\_aheadto\_normalmath{\_loadumathfamily #1{#2}{#3} }%
+ \_ifx\_relax#4\_relax
+ \_global\_aheadto\_boldmath{\_loadumathfamily #1{#2}{embolden=1.7;} }%
+ \_else
+ \_global\_aheadto\_boldmath{\_loadumathfamily #1{#4}{#5} }%
+ \_fi
+ \_normalmath
+ \_wterm{add-MATH-FONT: #1=\the#1, "#2", \ifx"#4"\else bold: "#4"\fi}%
+ \_fi \_fi
+}
+
+ \_doc -----------------------------
+ \`\mathchars` `<fam> {<list of sequences>}`
+ saves <fam> to \`\_mafam` and runs for each sequence from the <list of sequences>
+ the relevant code settings.
+ The `\directlua` chunk prints the 8-digits hexadecimal code of the
+ sequence followed by the sequence itself. The digts are scanned by \`\_mathcharsB`
+ and new `\Umathcode` is declared.\nl
+ If there exist \_d:<sequence> (i.e.\ it is delimiter) then `\Udelcode` is
+ redeclared too. Finally, in case of `\int`-like operators the
+ `\_intop` sequence is redeclared by `\Umathchardef`. Note that the used
+ primitives have the syntax:
+ \begtt \catcode`<=13
+ \Umathchardef <sequence> = <math class> <math family> <slot number>
+ \Umathcode <code> = <math class> <math family> <slot number>
+ \Udelcode <code> = <math family> <slot number>
+ \endtt
+ \_cod -----------------------------
+
+\_def\_mathchars {\_afterassignment\_mathcharsA \_chardef\_mafam=}
+\_def\_mathcharsA #1{\_foreach #1\_do{%
+ \_ifcsname _d:\_csstring##1\_endcsname \_ea \_mathcharsD \_csname _d:\_csstring##1\_endcsname
+ \_else \_mathcharsC ##1\_fi
+}}
+\_def\_mathcharsC #1{\_ea\_mathcharsB
+ \_directlua{tex.print(string.format("\_pcent08X", \_the\_Umathcode#1))}#1%
+}
+\_def\_mathcharsB #1#2#3#4#5#6#7#8#9{% #9 is given \math-sequence
+ \_ifcsname _\_csstring#9op\_endcsname
+ \_ea \_Umathchardef \_csname _\_csstring#9op\_endcsname=1 \_mafam #9\_relax
+ \_else
+ \_Umathcode "#4#5#6#7#8=\_numexpr"#3/2\_relax \_mafam "#4#5#6#7#8
+ \_fi
+}
+\_def\_mathcharsD #1{\_mathcharsC #1\_relax \_Udelcode #1=\_mafam #1\_relax}
+
+ \_doc -----------------------------
+ \`\mathcodes` `<fam> {<list of pairs>}` sets mathcodes of given
+ characters with explicit <class>es. Each pair can be `<class>{<list of chars>}`
+ and `<list of chars>` can include \`\Urange` `<from>-<to>`.
+ This is reason why we apply `\expanded` to the `<list of chars>`
+ before reading it by \^`\foreach`: the \^`\Urange` is expandable
+ and expands to the relevant list of characters.
+ \_cod -----------------------------
+
+\_def\_mathcodes{\_afterassignment\_mathcodesA\_chardef\_mafam=}
+\_def\_mathcodesA#1{%
+ \_foreach #1\_do ##1##2{%
+ \_ea\_foreach\_expanded{##2}\_do{\_Umathcode `####1=##1\_mafam`####1}%
+ }%
+}
+\_def\_Urange #1-#2{\_fornum `#1..`#2\_do{\_Uchar##1 }}
+
+\_public \addUmathfont \mathchars \mathcodes \Urange ;
+
+\_endcode
+
+
+The \^`\loadmath` `{<Unicode-math font>}` macro loads math fonts and
+redefines all default math-codes using `\input unimath-codes.opm`.
+If Unicode-math font is loaded then \^`\_mathloadingfalse`
+is set, so the new Unicode-math font isn't loaded until \^`\doloadmath` is used.
+
+\^`\loadboldmath` `{<bold-font>} \to {<normal-font>}` loads bold variant only
+if `<normal-font>` was sucessully loaded by the previous `\loadmath`. For example:
+
+\begtt
+\loadmath {[xitsmath-regular]}
+\loadboldmath {[xitsmath-bold]} \to {[xitsmath-regular]}
+\endtt
+There are very few Unicode-math fonts with full \~`\boldmath` support.
+I know only XITSMath-Bold and KpMath-Bold. If \^`\loadboldmath` is not used
+then \"faked bold" created from \~`\normalmath` is used by default.
+
+The {\em main math font} is loaded by \^`\loadmath` (typically indirectly using
+\^`\fontfam`) and you can load more {\em additional math fonts} by
+\^`\addUmathfont`:
+\begtt \catcode`<=13
+\addUmathfont \famname {[<normal-font>]}{<ffeatures>} {[<bold-font>]}{<ffeatures>} {<factor>}
+\endtt
+The `\famname` is a control sequence declared by \^`\addUmathfont` for later
+use. It gets math family number. The `<factor>` is decimal number for size
+corrections in view of the main math font. If it is empty then <factor>=1.
+If <bold-font> is empty, the \"faked bold" derived from <normal-font> is used.
+Example:
+\begtt
+\fontfam[lm] % does \lodmath{[latinmodern-math]}
+\addUmathfont \xits {[XITSMath-Regular]}{} {[XITSMath-Bold]}{} {}
+\endtt
+%
+declares `latinmodern-math` as main math font (its bold variant is \"faked bold").
+The additional math font family `\xits` is declared in the example. It uses
+`XITSMath-Regular` for normal printing and `XITSMath-Bold` for bold printing.
+
+All characters used in math formula are printed from main math font by
+default. But you can re-declare characters for printing from
+additional font by \^`\mathchars` `\famname {<list of sequences>}`. For
+example:
+
+\begtt
+\mathchars \xits {\stareq \triangleq \veeeq \wedgeq}
+\endtt
+%
+sets the characters `\stareq`, `\triangleq`, `\veeeq`, `\wedgeq` from
+the `\xits` additional font. The <list of sequences> can include
+control sequences from the `unicode-table.tex`, but no math
+accents. These contol sequences can be printed by `\input print-unimath.opm`.
+
+The \^`\mathchars` macro keeps the class and slot of declared math objects
+and re-declares only family of them. It is applied to all control
+sequences given in the parameter. The relevant math codes are re-declared.
+
+Use `\addto\selector{\fam\famname}` if you want to print whole math alphabet
+from an additional math font. For example `\addto\cal{\fam\xits}`
+declares all `\cal` characters from the `\xits` font loaded by
+\^`\addUmathfont`.
+
+The \^`\mathcodes` macro provides comfortable settings of math codes of math
+objects. Its syntax is \^`\mathcodes` `<family> {<list-of-pairs>}`. Each pair
+in the <list-of-pairs> is `<class-number><character>` (separated by optional
+space) or `<class-number>{<list-of-characters>}`. The <list-of-characters>
+includes declared characters or \^`\Urange` `<from>-<to>` which is equal to the
+list of characters beginning <from> and ending <to>, for example
+`\Urange a-d` is equal to `abcd`.
+
+The \^`\mathcodes` macro declares mathcode of given characters internally by
+\begtt \catcode`<=13
+\Umathcode `<character> = <class-number> <family> `<character>
+\endtt
+
+The \^`\mathcodes` macro sets math codes of given Unicode characters.
+The relevant control sequence from `unicode-table.tex` changes its
+behavior too. For example, If you change math code of × then the
+`\times` control sequence will behave like new declared ×.
+
+
+\secc Unicode-math macros preloaded in the format
+
+\printdoc unimath-macros.opm
+
+
+\secc[unimath-codes] Macros and codes set when `\loadmath` is processed firstly
+
+The file `unimath-codes.opm` is loaded when the \^`\loadmath` is used. The
+macros here redefines globally all encoding dependent settings declared in
+the section~\ref[math-macros].
+
+\printdoc unimath-codes.opm
+\printdoctail unimath-codes.opm
+
+\secc Printing all Unicode math slots in used math font
+
+\printdoctail print-unimath.opm
+\printdoc print-unimath.opm
+
+\_endinput
+
+2022-12-01 reading number by \_loadumathfamily more robust
+2022-11-18 \mathchars improved, \Udelcodes are set too, \addUmathfont uses \ahead
+2022-11-17 \Umathchardef replaced by \chardef
+2022-11-16 \resetmathchars removed, \mathchars, \mathcodes introduced
+2022-11-13 \_setfontfamily 0 added.
+2022-07-22 \Umathspaceafterscript setting added.
+2022-06-10 \addUmathfont and \resetmathchars added.
+2021-08-16 \_loadumathfamily simplified, used mathsize= font feature.
+2021-08-16 nomathparam font feature used for families > 3 (bug fixed).
+2021-08-02 ssty fontfeatures rewritten; fam2, fam3 unused, \scriptspace not set
+2021-04-04 \_setunimathdimens: \setbox0=\box\voidbox added
+2021-03-09 \_setunimathdimes: \_begin/end/group instead {}, bug fixed
+2021-02-15 \_textmff, \_scriptmff and \_sscriptmff introduced
+2021-02-15 \_expandafter -> \_ea
+2020-06-07 \Umathfractiondelsize (for \choose brackets) corrected, see https://tug.org/pipermail/luatex/2020-June/007365.html
+2020-04-15 \_setmathdimens -> \_setuniathdimens
+2020-02-25 implemented