texlive[74285] Master/texmf-dist: optex (25feb25)

commits+karl at tug.org commits+karl at tug.org
Tue Feb 25 21:43:09 CET 2025


Revision: 74285
          https://tug.org/svn/texlive?view=revision&revision=74285
Author:   karl
Date:     2025-02-25 21:43:08 +0100 (Tue, 25 Feb 2025)
Log Message:
-----------
optex (25feb25)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/man/man1/optex.1
    trunk/Master/texmf-dist/doc/man/man1/optex.man1.pdf
    trunk/Master/texmf-dist/doc/optex/base/README
    trunk/Master/texmf-dist/doc/optex/base/optex-doc.pdf
    trunk/Master/texmf-dist/doc/optex/base/optex-doc.tex
    trunk/Master/texmf-dist/doc/optex/base/optex-math.tex
    trunk/Master/texmf-dist/doc/optex/base/optex-userdoc.tex
    trunk/Master/texmf-dist/tex/optex/base/bib-iso690.opm
    trunk/Master/texmf-dist/tex/optex/base/cite-bib.opm
    trunk/Master/texmf-dist/tex/optex/base/f-fbb.opm
    trunk/Master/texmf-dist/tex/optex/base/f-newcm.opm
    trunk/Master/texmf-dist/tex/optex/base/fams-ini.opm
    trunk/Master/texmf-dist/tex/optex/base/fonts-resize.opm
    trunk/Master/texmf-dist/tex/optex/base/logos.opm
    trunk/Master/texmf-dist/tex/optex/base/luatex-ini.opm
    trunk/Master/texmf-dist/tex/optex/base/math-macros.opm
    trunk/Master/texmf-dist/tex/optex/base/more-macros.opm
    trunk/Master/texmf-dist/tex/optex/base/optex-tricks.opm
    trunk/Master/texmf-dist/tex/optex/base/optex.ini
    trunk/Master/texmf-dist/tex/optex/base/optex.lua
    trunk/Master/texmf-dist/tex/optex/base/others.opm
    trunk/Master/texmf-dist/tex/optex/base/pdfuni-string.opm
    trunk/Master/texmf-dist/tex/optex/base/unimath-codes.opm
    trunk/Master/texmf-dist/tex/optex/base/unimath-macros.opm
    trunk/Master/texmf-dist/tex/optex/demo/op-slides.tex
    trunk/Master/texmf-dist/tex/optex/pkg/math.opm
    trunk/Master/texmf-dist/tex/optex/pkg/minim.opm

Added Paths:
-----------
    trunk/Master/texmf-dist/tex/optex/base/f-alegreya.opm

Modified: trunk/Master/texmf-dist/doc/man/man1/optex.1
===================================================================
--- trunk/Master/texmf-dist/doc/man/man1/optex.1	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/doc/man/man1/optex.1	2025-02-25 20:43:08 UTC (rev 74285)
@@ -13,7 +13,7 @@
 .if n .ds LX LaTeX
 .\"=====================================================================
 .SH NAME
-optex \- OPmac and Plain TeX for LuaTeX engine.
+optex \- OPmac and Plain TeX for LuaHBTeX engine.
 .SH SYNOPSIS
 .B optex
 [ first line ]
@@ -26,7 +26,7 @@
 .IR "Web2C: A TeX implementation" .
 .PP
 .B OpTeX 
-is LuaTeX macro package initialized as the LuaTeX format optex.fmt.
+is LuaTeX macro package initialized as the LuaHBTeX format optex.fmt.
 It is based on Plain TeX macros by Donald Knuth and on OPmac macros from
 csplain package. For more information about it see
 http://petr.olsak.net/optex web page.

Modified: trunk/Master/texmf-dist/doc/man/man1/optex.man1.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/optex/base/README
===================================================================
--- trunk/Master/texmf-dist/doc/optex/base/README	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/doc/optex/base/README	2025-02-25 20:43:08 UTC (rev 74285)
@@ -22,6 +22,16 @@
 
 History:
 
+<1.17> Feb 2025:
+       OpTeX uses luahbtex instead luatex as default engine (from TeXlive 2025)
+       Default PDF version changed from 1.5 to 1.7
+       f-alegreya added
+       math.opm: \mathselector (for using text fonts in math mode) introduced
+       \it, \rm in math mode use script=latn, no italic corrections between letters
+       \pdfstring implemented using Lua, newly used for PDF outlines
+       optex.lua modified
+       several OpTeX tricks added
+       minor bugs fixed
 <1.16> Dec 2024:
        JSON files and tree structure support as a set of OpTeX tricks
        CSV databases support as a set of OpTeX tricks
@@ -82,7 +92,7 @@
        Minor improvements and bug fixing.
 <1.07> May 2022:
        Tikz's \foreach works only in its environment.
-       \lipsum syntax enlarged by dot after paragraph num, example: \lipusm[3.].
+       \lipsum syntax enlarged by dot after paragraph num, example: \lipsum[3.].
        f-baskervald.opm added.
        expandable \isinlist implemented.
        bibstyles \. replaced by \: }due to collision with \oldaccents).

Modified: trunk/Master/texmf-dist/doc/optex/base/optex-doc.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/optex/base/optex-doc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/optex/base/optex-doc.tex	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/doc/optex/base/optex-doc.tex	2025-02-25 20:43:08 UTC (rev 74285)
@@ -20,9 +20,9 @@
 \tit Format Based on Plain \TeX/ and OPmac\fnotemark1
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-\hfill Version 1.16
+\hfill Version 1.17
 
-\centerline{\it Petr Olšák, 2020, 2021, 2022, 2023, 2024}
+\centerline{\it Petr Olšák, 2020, 2021, 2022, 2023, 2024, 2025}
 
 \bigskip
 \centerline{\url{http://petr.olsak.net/optex}}
@@ -35,7 +35,7 @@
 \bigskip
 \noindent
 \OpTeX/ is \LuaTeX/ format with Plain \TeX/ and OPmac. Only \LuaTeX/ engine
-is supported. 
+is supported (more exactly: \LuaHBTeX/ engine is used from 2025).
 
 \OpTeX/ should be a modern Plain \TeX/ with power from OPmac (Fonts
 Selection System, colors, graphics, references, hyperlinks,

Modified: trunk/Master/texmf-dist/doc/optex/base/optex-math.tex
===================================================================
--- trunk/Master/texmf-dist/doc/optex/base/optex-math.tex	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/doc/optex/base/optex-math.tex	2025-02-25 20:43:08 UTC (rev 74285)
@@ -324,10 +324,10 @@
 This syntax requires to process all math lists in two steps: the first step
 expands all macros and creates structured data of processed math list. The
 second step reads the output of the first step, switches between math
-styles and creates definitive output. So, macros (working in the first step)
-cannot know the current math
-style because it is set only in the second step. \TeX/ supports the primitive
-\x`\matchchioce``{<D>}{<T>}{<S>}{<SS>}` which prepares four math lists in the
+styles and creates definitive output. Macros are working only in the first step
+and they cannot know the current math
+style because it is set in the second step. \TeX/ supports the primitive
+\x`\mathchoice``{<D>}{<T>}{<S>}{<SS>}` which prepares four math lists in the
 first step and only one of these four lists are used in the second step. We
 can put different macros into each of the four parameters of `\mathchoice`.
 Plain \TeX/ supports the macro \x`\mathpalette` which gives a more comfortable

Modified: trunk/Master/texmf-dist/doc/optex/base/optex-userdoc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/optex/base/optex-userdoc.tex	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/doc/optex/base/optex-userdoc.tex	2025-02-25 20:43:08 UTC (rev 74285)
@@ -9,7 +9,7 @@
 %%%%%%%%%%%%%%%%%%%%%%%%%
 
 \new
-\OpTeX/ is compiled as a format for \LuaTeX/. Maybe there is a command
+\OpTeX/ is compiled as a format for \LuaHBTeX/. Maybe there is a command
 `optex` in your \TeX/ distribution. Then you can write into the command line
 
 \begtt
@@ -1258,8 +1258,8 @@
 \enditems
 
 \new
-Note that another two possibilities documented in OPmac (using external
-Bib\TeX/ program) isn't supported because Bib\TeX/ is an old program that does not
+Note that the other two possibilities documented in OPmac (using external
+Bib\TeX/ program) aren't supported because Bib\TeX/ is an old program that does not
 support Unicode. And Biber seems to be not compliant with Plain \TeX.
 
 \medskip\noindent
@@ -1984,8 +1984,8 @@
 \tpg[xparshape]\t\xparshape\
 behaves like `\parshape` but its declaration is valid for more paragraphs.
 
-\tpg[xreplstring]\t\xreplstring\
-behaves like \~`\replstring` but is expandable and adds more features.
+\tpg[xreplstring]\t\xreplstring, \t\ereplstring\
+behave like \~`\replstring` but are expandable and add more features.
 
 }
 

Modified: trunk/Master/texmf-dist/tex/optex/base/bib-iso690.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/bib-iso690.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/bib-iso690.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -611,7 +611,7 @@
 
 \begtt
 year   = 2000,
-option = "yearpint:{© 2000}",
+option = "yearprint:{© 2000}",
 \endtt
 Output:  © 2000,  sorted by:  2000.
 
@@ -647,7 +647,7 @@
 
 If the `urlalso` option is used, then the added text has the form
 \"Available also from" or \"Dostupné také z:" (if `cs` language is
-current).
+in use).
 
 
 \seccc The citedate field
@@ -654,13 +654,13 @@
 
 This is the citation date. The field must be in the form year/month/day. It
 means, that the two slashes must be written here. The output depends on the
-current language. Example:
+selected language. Example:
 
 \begtt
 citedate = "2004/05/21",
 \endtt
-Output when `en` is current:    [cit. 2004-05-21].\nl
-Output when `cs` is current:    [vid. 21.~5.~2004].
+Output when `en` is used:    [cit. 2004-05-21].\nl
+Output when `cs` is used:    [vid. 21.~5.~2004].
 
 
 \seccc The howpublished field

Modified: trunk/Master/texmf-dist/tex/optex/base/cite-bib.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/cite-bib.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/cite-bib.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -150,12 +150,12 @@
    The `<bib-marks>` (in numeric or text form) are saved in \^`\_savedcites`
    macro separated by commas.
    The \`\_printsavedcites` prints them by normal order or sorted if
-   \`\sortcitations` is specified or condensed if \`\shordcitations` is
+   \`\sortcitations` is specified or condensed if \`\shortcitations` is
    specified.\nl
-   The `\sortcitations` appends the dummy number 300000 and we suppose that normal
+   The \^`\sortcitations` appends the dummy number 300000 and we suppose that normal
    numbers of bib-entries are less than this constant.
    This constant is removed after the sorting algorithm.
-   The \`\shortcitations` sets simply `\_lastcitenum=1`.
+   The \^`\shortcitations` sets simply `\_lastcitenum=1`.
    The macros for <bib-marks> printing follows (sorry, without detail
    documentation). They are documented in `opmac-d.pdf` (but only in Czech).
    \_cod -----------------------------

Added: trunk/Master/texmf-dist/tex/optex/base/f-alegreya.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/f-alegreya.opm	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/optex/base/f-alegreya.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -0,0 +1,33 @@
+%% This is part of the OpTeX project, see http://petr.olsak.net/optex
+
+\_famdecl [Alegreya] \Alegreya {Humanist serif and sans serif family}
+        {\medium \bolder \caps} {\rm \bf \it \bi} {}
+        {[Alegreya-Regular]}
+        {\_def\_fontnamegen {[Alegreya\_sansV-\_currV]:\_capsV\_fontfeatures}}
+
+\_wlog{\_detokenize{%
+Modifier:^^J
+ \caps ...... caps & small caps^^J
+ \sans ...... sans serif^^J
+ \normal .... \rm Regular, \bf Bold, \it Italic, \bi BoldItalic^^J
+ \medium .... \rm Medium, \bf ExtraBold, \it MediumItalic, \bi ExtraBoldItalic^^J
+ \bolder .... \rm Bold, \bf Black, \it BoldItalic, \bi BlackItalic^^J
+}}
+
+\_moddef \resetmod {\_fsetV caps={},sans={} \_fvars Regular Bold Italic BoldItalic }
+\_moddef \caps     {\_fsetV caps=+smcp;\_ffonum; }
+\_moddef \medium   {\_fvars Medium ExtraBold MediumItalic ExtraBoldItalic }
+\_moddef \bolder   {\_fvars Bold Black BoldItalic BlackItalic }
+\_moddef \sans     {\_fsetV sans=Sans }
+\_moddef \normal   {\_fvars Regular Bold Italic BoldItalic }
+
+
+\_initfontfamily % new font family must be initialized
+
+%\_loadmath {[texgyretermes-math]}
+
+\_endcode
+
+See the file `f-heros.opm` for information about principles of such
+font-macro-files.
+


Property changes on: trunk/Master/texmf-dist/tex/optex/base/f-alegreya.opm
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/texmf-dist/tex/optex/base/f-fbb.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/f-fbb.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/f-fbb.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_famdecl [fbb] \FBembo {Bembo–like fonts derived from Cardo}
+\_famdecl [fbb] \FBembo {Bembo-like fonts derived from Cardo}
         {\caps \swash} {\rm \bf \it \bi} {adjusted Garamond-Math}
         {[fbb-Regular]}
         {\_def\_fontnamegen {[fbb-\_currV]:script=latn;\_capsV\_swaV\_fontfeatures}}

Modified: trunk/Master/texmf-dist/tex/optex/base/f-newcm.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/f-newcm.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/f-newcm.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -29,6 +29,7 @@
 \_initfontfamily % new font family must be initialized
 
 \_loadmath {[NewCMMath-Regular]}
+\_loadboldmath{[NewCMMath-Bold]} \to {[NewCMMath-Regular]}
 
 \_endcode
 
@@ -36,11 +37,17 @@
 NewCMMath-Book Unicode math font too. Use the following declaration in this
 case:
 
-\loadmath{NewCMMath-Book}
+\loadmath{[NewCMMath-Book]}
+\loadboldmath{NewCMMath-Bold} \to {[NewCMMath-Book]}
 \fontfam[newcm]
 \book\rm
 
+or for sans serif math you can use:
 
+\loadmath{[NewCMSansMath-Regular]}
+\fontfam[newcm]
+\sans\rm
+
 See the file `f-heros.opm` for information about principles of such
 font-macro-files.
 

Modified: trunk/Master/texmf-dist/tex/optex/base/fams-ini.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/fams-ini.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/fams-ini.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -134,6 +134,14 @@
      \caps: {\rm\bf\it\bi} }
 \_famalias [Antykwa Poltawskiego] \_famalias [Poltawskiego] \_famalias [APoltawskiego]
 
+\_famfrom {Juan Pablo del Peral, www.huertatipografica.com}
+
+\_faminfo [Alegreya] {Humanist serif and sans serif family} {f-alegreya}
+   { -: {\rm\bf\it\bi} \medium: {\rm\bf\it\bi} \bolder: {\bf\bi}
+    \caps: {\rm\bf\it\bi} \caps\medium: {\rm\bf\it\bi} \caps\bolder: {\bf\bi}
+    \sans: {\rm\bf\it\bi} \sans\medium: {\rm\bf\it\bi} \sans\bolder: {\bf\bi}
+    \caps\sans: {\rm\bf\it\bi} \caps\sans\medium: {\rm\bf\it\bi} \caps\sans\bolder: {\bf\bi} }
+
 \_famfrom {Michael Sharpe}
 \_faminfo [Baskerville] {Free variants of classical Baskerville} {f-baskerville}
    { -,\caps: {\rm\bf\it\bi} }

Modified: trunk/Master/texmf-dist/tex/optex/base/fonts-resize.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/fonts-resize.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/fonts-resize.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -353,8 +353,8 @@
 renderer (like in `pdftex`). The extended font renderer implemented in the
 Luaotfload package is started after \^`\initunifonts`.
 
-The \OpTeX/ format uses `luatex` engine by default but
-you can initialize it by `luahbtex` engine too. Then the harfbuzz library is
+The \OpTeX/ format uses `luahbtex` engine by default (from 2025).
+It means that the harfbuzz library is
 ready to use for font rendering as an alternative to built-in font renderer
 from Luaotfload. The harfbuzz library gives more features for rendering
 Indic and Arabic scripts. But it is not used as default, you need to specify

Modified: trunk/Master/texmf-dist/tex/optex/base/logos.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/logos.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/logos.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \TeX {Logos TeX, LuaTeX, etc. <2024-02-12>} % preloaded in format
+\_codedecl \TeX {Logos TeX, LuaTeX, etc. <2025-01-22>} % preloaded in format
 
    \_doc ----------------------------
    Despite plain \TeX/ each macro for logos ends by \`\ignoreslash`.
@@ -13,12 +13,13 @@
 \_protected\_def \_TeX {T\_kern-.1667em\_lower.5ex\_hbox{E}\_kern-.125emX\_ignoreslash}
 \_protected\_def \_OpTeX {Op\_kern-.1em\_TeX}
 \_protected\_def \_LuaTeX {Lua\_TeX}
+\_protected\_def \_LuaHBTeX {Lua{\_setfontsize{mag.9}\_resizethefont HB}\_TeX}
 \_protected\_def \_XeTeX {X\_kern-.125em\_phantom E%
    \_pdfsave\_rlap{\_pdfscale{-1}{1}\_lower.5ex\_hbox{E}}\_pdfrestore \_kern-.1667em \_TeX}
 
 \_def\_ignoreslash {\_isnextchar/\_ignoreit{}}
 
-\_public \TeX \OpTeX \LuaTeX \XeTeX \ignoreslash ;
+\_public \TeX \OpTeX \LuaTeX \LuaHBTeX \XeTeX \ignoreslash ;
 
    \_doc ----------------------------
    The  \`\ConTeXt` logo is implemented as in the \ConTeXt/ format itself.
@@ -72,5 +73,6 @@
 
 \_endcode
 
+2025-01-22  LuaHBTeX logo added.
 2024-02-12  ConTeXt logo added.
 2020-02-28  Released.

Modified: trunk/Master/texmf-dist/tex/optex/base/luatex-ini.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/luatex-ini.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/luatex-ini.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -96,6 +96,7 @@
 \_protected\_edef\_pdfinclusionerrorlevel {\_pdfvariable inclusionerrorlevel}
 \_protected\_edef\_pdfgentounicode        {\_pdfvariable gentounicode}
 \_protected\_edef\_pdfpagebox             {\_pdfvariable pagebox}
+\_protected\_edef\_pdfmajorversion        {\_pdfvariable majorversion}
 \_protected\_edef\_pdfminorversion        {\_pdfvariable minorversion}
 \_protected\_edef\_pdfuniqueresname       {\_pdfvariable uniqueresname}
 \_protected\_edef\_pdfhorigin             {\_pdfvariable horigin}
@@ -122,11 +123,12 @@
    \pdfobjcompresslevel \pdfdecimaldigits \pdfgamma \pdfimageresolution
    \pdfimageapplygamma \pdfimagegamma \pdfimagehicolor \pdfimageaddfilename
    \pdfpkresolution \pdfinclusioncopyfonts \pdfinclusionerrorlevel
-   \pdfgentounicode \pdfpagebox \pdfminorversion \pdfuniqueresname \pdfhorigin
-   \pdfvorigin \pdflinkmargin \pdfdestmargin \pdfthreadmargin \pdfpagesattr
+   \pdfgentounicode \pdfpagebox \pdfmajorversion \pdfminorversion \pdfuniqueresname
+   \pdfhorigin \pdfvorigin \pdflinkmargin \pdfdestmargin \pdfthreadmargin \pdfpagesattr
    \pdfpageattr \pdfpageresources \pdfxformattr \pdfxformresources \pdfpkmode ;
 
-\_pdfminorversion     = 5
+\_pdfmajorversion     = 1
+\_pdfminorversion     = 7 % was 5, see https://tug.org/pipermail/tex-live/2025-February/
 \_pdfobjcompresslevel = 2
 \_pdfcompresslevel    = 9
 \_pdfdecimaldigits    = 3
@@ -138,5 +140,6 @@
 
 \_endinput
 
+2025-02-11 default \pdfminorversion changed from 5 to 7
 2024-02-29 \pdfrunninglinkoff \pdfrunninglinkon added
 2020-02-21 released

Modified: trunk/Master/texmf-dist/tex/optex/base/math-macros.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/math-macros.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/math-macros.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 % This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \sin {Math macros plus mathchardefs <2024-11-19>} % preloaded in format
+\_codedecl \sin {Math macros plus mathchardefs <2024-12-21>} % preloaded in format
 
    \_doc -----------------------------
    The category code of the character `_` remains as the letter (11) and the mathcode
@@ -502,7 +502,7 @@
    \_cod -----------------------------
 
 \_def\_math{\_mathsurround\_zo}
-\_protected\_def\_skew #1#2#3{{\_muskip0=#1mu\_divide\_muskip0=by2 \_mkern\_muskip0
+\_protected\_def\_skew #1#2#3{{\_muskip0=#1mu\_divide\_muskip0by2 \_mkern\_muskip0
     #2{\_mkern-\_muskip0{#3}\_mkern\_muskip0}\_mkern-\_muskip0}{}}
 \_protected\_def\_overrightarrow #1{\_vbox{\_math\_ialign{##\_crcr
       \_rightarrowfill\_crcr\_noalign{\_kern-.1em \_nointerlineskip}
@@ -1112,6 +1112,7 @@
 
 \_endcode %---------------------------------------------------
 
+2024-12-21 \skew macro: bug fixed
 2024-11-19 \typosize used fo Uni-fonts in \mathbox in order to respect their sizes
 2024-06-02 don't apply \mathsbon twice
 2023-05-24 \matsbon: "local num" added

Modified: trunk/Master/texmf-dist/tex/optex/base/more-macros.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/more-macros.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/more-macros.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -180,7 +180,7 @@
    It means that user can write \code{\\sec text `&` text} for example.
    Inline verbatim works in title sections.
 
-   The verbatim scanner of `\scatoeol` keeps category 7 for `^` in
+   The verbatim scanner of `\scantoeol` keeps category 7 for `^` in
    order to be able to use `^^J` as comment character which means that
    the next line continues.
    \_cod -----------------------------
@@ -237,12 +237,11 @@
      after scanning by \^`\ea`: without this \TeX/
      removes braces from `<textA>{xxx}<textA>`.
    \enditems
-
-   The \^`\replstring` macro isn't expandable. But you can use
-   \ulink[http://petr.olsak.net/optex/optex-tricks.html\#xreplstring]{\OpTeX/ trick 0136}.
-   The expandable \^`\xreplstring` macro with more features is defined by Lua code here.
-   And \ulink[http://petr.olsak.net/optex/optex-tricks.html\#replmacro]{\OpTeX/ trick 0137}
-   defines \^`\replmacro` which enables more general modifications of macros by regular expressions.
+   The \^`\replstring` macro isn't expandable. But you can see
+   \ulink[http://petr.olsak.net/optex/optex-tricks.html\#xreplstring]{\OpTeX/ trick 0136}
+   and \ulink[http://petr.olsak.net/optex/optex-tricks.html\#replmacro]{\OpTeX/ trick 0137}.
+   These triks implement expandable alternatives and enable more general modifications
+   of macros by regular expressions.
    \_cod -----------------------------
 
    \_doc -----------------------------

Modified: trunk/Master/texmf-dist/tex/optex/base/optex-tricks.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/optex-tricks.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/optex-tricks.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \_undefined {OpTeX tricks ready to autoload <2024-12-09>} % chunks loaded on demand
+\_codedecl \_undefined {OpTeX tricks ready to autoload <2024-12-13>} % chunks loaded on demand
 
 % Selected OpTeX tricks are here, they are auto-loaded if the macro is used first
 % namespace: optextrick
@@ -283,7 +283,11 @@
 end,'global') % we want to keep the meanig after group
 }
 
-\_trick 0078 0145 0146 \algol \algolkw \algolcap \makeLOA \algolnum ;
+\_trick 0136 \ereplstring ;
+
+\_def\ereplstring#1#2#3{\_immediateassigned{\_def\.repl{#1}\_replstring\.repl{#2}{#3}}\.repl}
+
+\_trick 0078 0145 0146 \algol \algolkw \algolcap \makeLOA \algolnum \setaca ;
 %%%%%%%%%%%%%%%%%%%%%%
 
 \_newtoks \_hisyntaxalg
@@ -299,18 +303,22 @@
       \_do {\_replthis{\n#1\n}{\z K{#1}}}
 }
 \_def\.algolmath#1${\_catcodetable\_optexcatcodes \_scantextokens{#1}$}
-
+\_def\.addcoloneq{\_ifx\coloneq\_undefined \_else
+   \_mathcode`:="8000 \_adef:{\_isnextchar={\coloneq\_ignoreit}{\_Umathchar 6 1 `: }}\_fi
+}
 \:\_def\algol{\_catcode`$=3 %
    \_everymath={\.algolmath}%
    \_def\_ttfont{\_rm}%
-   \_def\var##1{{\_it\_adef _{\_vrule height.4pt width4pt depth0pt\_relax}##1}}
+   \_def\var##1{\_mathbox{\_it\_def\.tmp{##1}\_replstring\.tmp{_}{\.lowline}\.tmp}}
+   \_def\.lowline{\_vrule height.4pt width4pt depth0pt\_relax}%
+   \.addcoloneq
    \_catcode`\!=13
-   \_bgroup \_lccode`\~=`\!
-            \_lowercase{\_egroup \_protected\_def~##1~{\_ifx^##1^!\_else{\_bf##1}\_fi}}%
+   \_bgroup \_lccode`\~=`\! \_lowercase{\_egroup \_protected\_def~##1~}{\algolem{##1}}%
    \_hisyntax{ALG}%
 }
 \:\_def\algolkw#1{\_toksapp\_hisyntaxalg{\_replthis{\n#1\n}{\z K{#1}}}}
-\_ifx\algolcomment\_undefined \_def\algolcomment#1{/\kern-.2em/{\it #1}} \_fi
+\_ifx\algolcomment\_undefined \_protected\_def\algolcomment#1{/\_kern-.2em/{\_it #1}} \_fi
+\_ifx\algolem\_undefined      \_def\algolem#1{\_ifx^#1^!\_else{\_bf #1}\_fi}\_fi
 
 \_newcount\.anum
 \_def \.theanum  {\_othe\_chapnum.\_othe\_secnum.\_the\.anum}
@@ -346,6 +354,22 @@
 }
 \_def\.testindent#1#2\_iftrue {\_ea\_ifx#1\_dsp}
 
+\_newcount\.algollistnum
+\:\_def\setaca {\_aheadto\algol{\.algolsetcomments}}
+\_def\.algolsetcomments{\_incr\.algollistnum
+   \_tmpnum=0 \_tmpdim=-\_maxdimen
+   \_loop \_incr\_tmpnum
+      \_ifcsname _pos:\.alcomlabel \_endcsname
+         \_ifdim\_tmpdim<\_posx[\.alcomlabel] \_tmpdim=\_posx[\.alcomlabel] \_fi \_repeat
+   \_tmpnum=0
+   \_let\aca=\.algolcommentsalignment
+}
+\_def\.alcomlabel{comment:\_the\.algollistnum/\_the\_tmpnum}
+\_protected\_def \.algolcommentsalignment {\_incr\_tmpnum \_setpos[\.alcomlabel]%
+   \_ifdim\_tmpdim=-\_maxdimen \_else
+       \_ifdim\_posx[\.alcomlabel]=0pt \_else \_kern\_dimexpr\_tmpdim-\_posx[\.alcomlabel]\_relax
+   \_fi\_fi
+}
 \_globaldefs=0 % \refdecl needs to be processed when \localdefs=0
 \_refdecl{%
    \_def\.alglist{}^^J
@@ -1242,6 +1266,7 @@
 
 \_endcode
 
+2024-12-13 \algol: \algolem, \aca introduced
 2024-12-09 \exectree: bug in default macros fixed
 2024-11-26 \exectree, \jsonread etc. implemented
 2024-11-23 \dbcreate etc. implemented

Modified: trunk/Master/texmf-dist/tex/optex/base/optex.ini
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/optex.ini	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/optex.ini	2025-02-25 20:43:08 UTC (rev 74285)
@@ -21,7 +21,7 @@
 
 % OpTeX version
 
-\def\optexversion{1.16 Dec 2024}
+\def\optexversion{1.17 Feb 2025}
 \def\fmtname{OpTeX}
 \let\fmtversion=\optexversion
 

Modified: trunk/Master/texmf-dist/tex/optex/base/optex.lua
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/optex.lua	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/optex.lua	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,12 +1,64 @@
 -- This is part of the OpTeX project, see http://petr.olsak.net/optex
 
--- The basic lua functions and declarations used in \OpTeX/ are here
+-- Basic Lua functions and declarations used in \OpTeX/ are defined here
+--
+-- Local imports of standard Lua or \LuaTeX/ functions and constants are the first thing we do.
+-- They mostly serve one of several purposes:
+--
+-- \begitems
+-- * shorthands for commonly used functions,
+-- * speed of access for commonly executed functions,
+-- * common constants to be used consistently,
+-- * use of local definition that can't be externally overwritten.
+-- \enditems
 
 local fmt = string.format
 
+local node_id = node.id
+local node_subtype = node.subtype
+local glyph_id = node_id("glyph")
+local rule_id = node_id("rule")
+local glue_id = node_id("glue")
+local hlist_id = node_id("hlist")
+local vlist_id = node_id("vlist")
+local disc_id = node_id("disc")
+local kern_id = node_id("kern")
+local whatsit_id = node_id("whatsit")
+local pdfliteral_id = node_subtype("pdf_literal")
+local pdfsave_id = node_subtype("pdf_save")
+local pdfrestore_id = node_subtype("pdf_restore")
+local token_getmacro = token.get_macro
+
+local direct = node.direct
+local todirect = direct.todirect
+local tonode = direct.tonode
+local getfield = direct.getfield
+local setfield = direct.setfield
+local getwhd = direct.getwhd
+local getid = direct.getid
+local getlist = direct.getlist
+local setlist = direct.setlist
+local getleader = direct.getleader
+local getfont = direct.getfont
+local getattribute = direct.get_attribute
+local setattribute = direct.set_attribute
+local insertbefore = direct.insert_before
+local copy = direct.copy
+local traverse = direct.traverse
+local one_bp = tex.sp("1bp")
+
+local tex_print = tex.print
+local tex_setbox = tex.setbox
+local tex_getcount = tex.getcount
+local tex_setcount = tex.setcount
+local token_scanint = token.scan_int
+local token_scanlist = token.scan_list
+local token_setmacro = token.set_macro
+local font_getfont = font.getfont
+--
 -- \medskip\secc General^^M
 --
--- Define namespace where some \OpTeX/ functions will be added.
+-- Define namespace where \"public" \OpTeX/ functions will be added.
 
 local optex = _ENV.optex or {}
 _ENV.optex = optex
@@ -31,31 +83,28 @@
     if fh then
         local data = fh:read("*a")
         fh:close()
-        tex.print(md5.sumhexa(data))
+        tex_print(md5.sumhexa(data))
    end
 end
 
 -- The `optex.raw_ht ()` function measures the height plus depth of given
--- `\vbox` saved by `\setbox`. It solves \"dimension too large" problem with big boxes.
+-- `\vbox` saved by `\setbox`. It solves the \"dimension too large" problem with big boxes.
 -- It is used in the \^`\_rawht` macro.
 
 function optex.raw_ht()
-   local nod = tex.box[token.scan_int()]       -- read head node of the given box
-   local ht = 0
-   if not(nod==nil) and nod.id==1 then         -- given box must be \vbox
-      for n in node.traverse(nod.head) do
-         if n.id==0 or n.id==1 or n.id==2 then -- hbox or vbox or rule
+    local nod = tex.box[token.scan_int()]       -- read head node of the given box
+    local ht = 0
+    assert(nod ~= nil and nod.id == vlist_id, "given box must be a \\vbox")
+    for n in node.traverse(nod.head) do
+        if n.id == hlist_id or n.id == vlist_id or n.id == rule_id then
             ht = ht + n.height + n.depth
-         end
-         if n.id==12 then                      -- glue
+        elseif n.id == glue_id then
             ht = ht + n.width
-         end
-         if n.id==13 then                      -- kern
+        elseif n.id == kern_id then
             ht = ht + n.kern
-         end
-      end
-   end
-   tex.print(string.format('%.0f',ht/65536))
+        end
+    end
+    tex_print(fmt('%.0f', ht/65536))
 end
 
 --
@@ -220,7 +269,7 @@
         err("cannot create callback '%s' - it already exists", name)
     elseif not valid_callback_types[cbtype] then
         err("cannot create callback '%s' with invalid callback type '%s'", name, cbtype)
-    elseif ctype == "exclusive" and not default then
+    elseif cbtype == "exclusive" and not default then
         err("unable to create exclusive callback '%s', default function is required", name)
     end
 
@@ -259,12 +308,18 @@
         err("missing description when adding a callback to '%s'", name)
     end
 
-    for _, desc in ipairs(callback_description[name] or {}) do
+    local prev_descriptions = callback_description[name] or {}
+    for _, desc in ipairs(prev_descriptions) do
         if desc == description then
             err("for callback '%s' there already is '%s' added", name, description)
         end
     end
 
+    if callback_types[name] == "exclusive" and #prev_descriptions == 1 then
+        err("can't register '%s' as callback '%s' - exclusive callback occupied by '%s'",
+            description, name, prev_descriptions[1])
+    end
+
     if type(fn) ~= "function" then
         err("expected Lua function to be added as '%s' for callback '%s'", description, name)
     end
@@ -368,7 +423,6 @@
 
     local head = (...)
     local new_head
-    local changed = false
     for _, fn in iter(functions) do
         new_head = fn(head, select(2, ...))
         if new_head == false then
@@ -375,10 +429,9 @@
             return false
         elseif new_head ~= true then
             head = new_head
-            changed = true
         end
     end
-    return not changed or head
+    return head
 end
 call_callback = callback.call_callback
 --
@@ -395,7 +448,7 @@
     if new_head == false then
         node.flush_list(head)
         return nil
-    elseif new_head ~= true then
+    else
         head = new_head
     end
     -- mlist_to_hlist means either added functions or standard luatex behavior
@@ -406,10 +459,8 @@
     if new_head == false then
         node.flush_list(head)
         return nil
-    elseif new_head ~= true then
-        head = new_head
     end
-    return head
+    return new_head
 end)
 --
 -- For preprocessing boxes just before shipout we define custom callback. This
@@ -423,9 +474,6 @@
 -- achieve colors and possibly more).
 callback.create_callback("pre_shipout_filter", "list")
 
-local tex_setbox = tex.setbox
-local token_scanint = token.scan_int
-local token_scanlist = token.scan_list
 define_lua_command("_preshipout", function()
     local boxnum = token_scanint()
     local head = token_scanlist()
@@ -460,27 +508,76 @@
         return ""
     end
 end, "_tracingmacros")
--- \medskip\secc[lua-pdf-resources] Management of PDF page resources^^M
 --
--- Traditionally, pdf\TeX/ allowed managing PDF page resources (graphics
--- states, patterns, shadings, etc.) using a single toks register,
--- `\pdfpageresources`. This is insufficient due to the expected PDF object
--- structure and also because many \"packages" want to add page resources and
--- thus fight for the access to that register. We add a finer alternative,
--- which allows adding different kinds of resources to a global page resources
--- dictionary. Note that some resource types (fonts and XObjects) are already
--- managed by \LuaTeX/ and shouldn't be added!
+-- \medskip\secc[lua-pdf-utils] PDF object utilities^^M
 --
--- XObject forms can also use resources, but there are several ways to make
--- \LuaTeX/ reference resources from forms. It is hence left up to the user to
--- insert page resources managed by us, if they need them. For that, use
--- `pdf.get_page_resources()`, or the below \TeX/ alternative for that.
+-- The PDF format defines various kinds of \"objects": numbers, names, arrays,
+-- dictionaries. A PDF document is mostly a tree of these objects (i.e. objects
+-- contain other objects), with either direct (\"in-place") or indirect
+-- references.
 --
+-- These objects are saved in the PDF file in a serialized form, often
+-- compressed. While \LuaTeX/ takes care of the compression, and most of the
+-- structure of the PDF format, sometimes we want to insert our own PDF objects
+-- - and there are places where \LuaTeX/ allows us to use our own objects to
+-- insert anything, but it already expects a serialized form of the objects. The
+-- serialized form for some kinds of objects has various formatting and escaping
+-- rules, and is inconvenient to produce in \TeX/ especially when some of the
+-- e.g. names and strings are {\it user input}.
+--
+-- Here we define a couple of utilities for both Lua and \TeX/ that aid with
+-- representation and serialization of objects. The functions are exported, but
+-- may still evolve in incompatible ways.
+--
+-- A reference for the serialization is the \"Syntax" section of the PDF
+-- specification\fnote{\url{https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf}}.
+--
+-- \`\pdfname``{<name>}` serializes a \"PDF name" to bytes.
+local function name_escape(char)
+    return fmt("#%02X", char:byte())
+end
+--
+local function pdf_name(name)
+    -- Delimiters (i.e. "()<>[]{}/%") and control characters (0x00-0x1f, and 0x7f),
+    -- space (" ", 0x20) as well as number sign ("#", 0x23) characters have to be escaped
+    return "/" .. name:gsub("[%(%)<>%[%]{}/%%%c #]", name_escape)
+end
+optex.pdf_name = pdf_name
+define_lua_command("_pdfname", function()
+    tex_print(-2, pdf_name(token.scan_string()))
+end)
+--
+-- \`\pdfstring``{<string>}` serializes a PDF string to bytes.
+local function pdf_string(str)
+    local out = {"<FEFF"}
+    for _, c in utf8.codes(str) do
+        if c < 0x10000 then
+            out[#out+1] = fmt("%04X", c)
+        else
+            c = c - 0x10000
+            local high = bit32.rshift(c, 10) + 0xD800
+            local low = bit32.band(c, 0x3FF) + 0xDC00
+            out[#out+1] = fmt("%04X%04X", high, low)
+        end
+    end
+    out[#out+1] = ">"
+    return table.concat(out)
+end
+optex.pdf_string = pdf_string
+define_lua_command("_pdfstring", function()
+    tex_print(-2, pdf_string(token.scan_string()))
+end)
+--
+local function pdf_ref(id)
+    return fmt("%d 0 R", id)
+end
+optex.pdf_ref = pdf_ref
+--
 local pdfdict_mt = {
     __tostring = function(dict)
         local out = {"<<"}
         for k, v in pairs(dict) do
-            out[#out+1] = fmt("/%s %s", tostring(k), tostring(v))
+            out[#out+1] = fmt("%s %s", pdf_name(k), tostring(v))
         end
         out[#out+1] = ">>"
         return table.concat(out, "\n")
@@ -491,6 +588,25 @@
 end
 optex.pdf_dict = pdf_dict
 --
+tex.print ("\\_public \\pdfname \\pdfstring ;")
+--
+-- \medskip\secc[lua-pdf-resources] Management of PDF page resources^^M
+--
+-- Traditionally, pdf\TeX/ allowed managing PDF page resources (graphics
+-- states, patterns, shadings, etc.) using a single toks register,
+-- `\pdfpageresources`. This is insufficient due to the expected PDF object
+-- structure and also because many \"packages" want to add page resources and
+-- thus fight for the access to that register. We add a finer alternative,
+-- which allows adding different kinds of resources to a global page resources
+-- dictionary. Note that some resource types (fonts and XObjects) are already
+-- managed by \LuaTeX/ and shouldn't be added!
+--
+-- XObject forms can also use resources, but there are several ways to make
+-- \LuaTeX/ reference resources from forms. It is hence left up to the user to
+-- insert page resources managed by us, if they need them. For that, use
+-- `pdf.get_page_resources()`, or the below \TeX/ alternative for that.
+--
+--
 local resource_dict_objects = {}
 local page_resources = {}
 function pdf.add_page_resource(type, name, value)
@@ -497,7 +613,7 @@
     local resources = page_resources[type]
     if not resources then
         local obj = pdf.reserveobj()
-        pdf.setpageresources(fmt("%s /%s %d 0 R", pdf.get_page_resources(), type, obj))
+        pdf.setpageresources(fmt("%s %s %s", pdf.get_page_resources(), pdf_name(type), pdf_ref(obj)))
         resource_dict_objects[type] = obj
         resources = pdf_dict()
         page_resources[type] = resources
@@ -509,7 +625,7 @@
 end
 --
 -- New \"pseudo" primitives are introduced.
--- \`\_addpageresource``{<type>}{<PDF name>}{<PDF dict>}` adds more reources
+-- \`\_addpageresource``{<type>}{<PDF name>}{<PDF dict>}` adds more resources
 -- of given resource <type> to our data structure.
 -- \`\_pageresources` expands to the saved <type>s and object numbers.
 define_lua_command("_addpageresource", function()
@@ -516,7 +632,7 @@
     pdf.add_page_resource(token.scan_string(), token.scan_string(), token.scan_string())
 end)
 define_lua_command("_pageresources", function()
-    tex.print(pdf.get_page_resources())
+    tex_print(pdf.get_page_resources())
 end)
 --
 -- We write the objects with resources to the PDF file in the `finish_pdffile`
@@ -534,36 +650,6 @@
 -- to them. We do this by intercepting \TeX/ just before it ships out a page and
 -- inject PDF literals according to attributes.
 --
-local node_id = node.id
-local node_subtype = node.subtype
-local glyph_id = node_id("glyph")
-local rule_id = node_id("rule")
-local glue_id = node_id("glue")
-local hlist_id = node_id("hlist")
-local vlist_id = node_id("vlist")
-local disc_id = node_id("disc")
-local whatsit_id = node_id("whatsit")
-local pdfliteral_id = node_subtype("pdf_literal")
-local pdfsave_id = node_subtype("pdf_save")
-local pdfrestore_id = node_subtype("pdf_restore")
-local token_getmacro = token.get_macro
-
-local direct = node.direct
-local todirect = direct.todirect
-local tonode = direct.tonode
-local getfield = direct.getfield
-local setfield = direct.setfield
-local getwhd = direct.getwhd
-local getid = direct.getid
-local getlist = direct.getlist
-local setlist = direct.setlist
-local getleader = direct.getleader
-local getattribute = direct.get_attribute
-local insertbefore = direct.insert_before
-local copy = direct.copy
-local traverse = direct.traverse
-local one_bp = tex.sp("1bp")
---
 -- The attribute for coloring is allocated in `colors.opm`
 local color_attribute = registernumber("_colorattr")
 local transp_attribute = registernumber("_transpattr")
@@ -618,7 +704,9 @@
 -- \TeX/ works with nodes.
 local function is_color_needed(head, n, id, subtype) -- returns fill, stroke color needed
     if id == glyph_id then
-        return true, false
+        local font_id = getfont(n)
+        local mode = font_getfont(font_id).mode
+        return true, mode == 1 or mode == 2
     elseif id == glue_id then
         n = getleader(n)
         if n then
@@ -707,11 +795,7 @@
 -- attribute. On top of that, we take care of transparency resources ourselves.
 --
 -- The hook has to be registered {\em after} `luaotfload` is loaded.
-local setattribute = direct.set_attribute
-local token_setmacro = token.set_macro
 local color_count = registernumber("_colorcnt")
-local tex_getcount, tex_setcount = tex.getcount, tex.setcount
---
 local function set_node_color(n, color) -- "1 0 0 rg" or "0 g", etc.
     local attr = tonumber(token_getmacro("_color::"..color))
     if not attr then
@@ -763,10 +847,11 @@
 -- expand processor level despite the fact that `<tokens>` processes unexpandable commands.
 
 define_lua_command("_beglocalcontrol", function()
-	return tex.runtoks(token.get_next, true)
+	return tex.runtoks(token.get_next)
 end)
 
    -- History:
+   -- 2024-12-18 \pdfstring etc. introduced
    -- 2024-09-06 raw_ht() implemented
    -- 2024-06-02 more checking in add_to_callback and remove_from_callback
    -- 2024-02-18 \_beglocalcontrol added

Modified: trunk/Master/texmf-dist/tex/optex/base/others.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/others.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/others.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -163,12 +163,12 @@
 
 \_xargs \_regtrick \begfile \createfile \beglua \begLUA \logginglua
    \sethours \setminutes \setseconds \setweekday \showpglists \shownodes \runsystem
-   \directoutput \algol \algolkw \algolcap \algolnum \makeLOA \scaleto \scaletof \ttlineref \lref
-   \easylist \keepstyle \fcread \shadedframe \roundframe \cancel \ignoreinspic \keystroke
-   \colortab \crx \crtop \crbot \crmid \longtable \vcent \vbot \tnote \tabnodes \tablebefore
-   \framedblocks \twoblocks \pstart \settabs \import \incrpp \ispageodd
+   \directoutput \algol \algolkw \algolcap \algolnum \makeLOA \setaca \scaleto \scaletof
+   \ttlineref \lref \easylist \keepstyle \fcread \shadedframe \roundframe \cancel \ignoreinspic
+   \keystroke \colortab \crx \crtop \crbot \crmid \longtable \vcent \vbot \tnote
+   \tabnodes \tablebefore \framedblocks \twoblocks \pstart \settabs \import \incrpp \ispageodd
    \iniseccc \seccc \makeLOF \makeLOT \captionF \captionT \correctvsize \pgforeground
-   \onlyifnew \thedimen \rebox \leftfill \rightfill \lrfill \directchar
+   \onlyifnew \thedimen \rebox \leftfill \rightfill \lrfill \directchar \ereplstring
    \xreplstring \replmacro \tdnum \clipbox \ismatch \isinmacro \mathinexpr \xparshape
    \csvread \csvdecl \dbcreate \exectree \showtree \jsonread \jsoncnv ;
 \_sdef{_item:m}{\_loadtrick{\style m}\_cs{_item:m}}

Modified: trunk/Master/texmf-dist/tex/optex/base/pdfuni-string.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/pdfuni-string.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/pdfuni-string.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,28 +1,8 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \pdfunidef {PDFunicode strings for outlines <2021-02-08>} % preloaded in format
+\_codedecl \pdfunidef {PDFunicode strings for outlines <2024-12-18>} % preloaded in format
 
    \_doc -----------------------------
-   \`\_hexprint` is a command defined in Lua, that scans a number and expands
-   to its UTF-16 Big Endian encoded form for use in PDF hexadecimal strings.
-   \_cod -----------------------------
-
-\bgroup
-\_catcode`\%=12
-\_gdef\_hexprint{\_directlua{
-   local num = token.scan_int()
-   if num < 0x10000 then
-      tex.print(string.format("%04X", num))
-   else
-      num = num - 0x10000
-      local high = bit32.rshift(num, 10) + 0xD800
-      local low = bit32.band(num, 0x3FF) + 0xDC00
-      tex.print(string.format("%04X%04X", high, low))
-   end
-}}
-\egroup
-
-   \_doc -----------------------------
    \`\pdfunidef``\macro{<text>}` defines `\macro` as <text> converted to
    Big Endian UTF-16 and enclosed to \code{<>}. Example of usage:
    `\pdfunidef\infoauthor{Petr Olšák} \pdfinfo{/Author \infoauthor}`.\nl
@@ -33,9 +13,7 @@
    according to current values on selected macros from `\_regoul`. Then
    \`\_removeoutmath` converts `..$x^2$..` to `..x^2..`, i.e removes dollars.
    Then \`\_removeoutbraces` converts `..{x}..` to `..x..`.
-   Finally, the <text> is detokenized, spaces are preprocessed using \^`\replstring`
-   and then the \`\_pdfunidefB` is repeated on each character. It calls the
-   `\directlua` chunk to print hexadecimal numbers in the macro \^`\_hexprint`.\nl
+   Finally, the <text> is detokenized, and \^`\pdfstring` is applied.\nl
    Characters for quotes (and separators for quotes) are activated by first
    `\_scatextokens` and they are defined as the same non-active characters.
    But `\_regoul` can change this definition.
@@ -54,20 +32,10 @@
       \_ea\_edef \_ea#1\_ea{\_ea\_removeoutmath   #1$\_fin$}%  $x$ -> x
       \_ea\_edef \_ea#1\_ea{\_ea\_removeoutbraces #1{\_fin}}%  {x} -> x
       \_edef#1{\_detokenize\_ea{#1}}%
-      \_replstring#1{ }{{ }}%  text text -> text{ }text
-      \_catcode`\\=12 \_let\\=\_bslash
-      \_edef\_out{<FEFF}
-      \_ea\_pdfunidefB#1^%  text -> \_out in octal
       \_ea
    \_endgroup
-   \_ea\_def\_ea#1\_ea{\_out>}
+   \_ea\_edef\_ea#1\_ea{\_pdfstring\_ea{#1}}
 }
-\_def\_pdfunidefB#1{%
-   \_ifx^#1\_else
-      \_edef\_out{\_out \_hexprint `#1}
-   \_ea\_pdfunidefB \_fi
-}
-
 \_def\_removeoutbraces #1#{#1\_removeoutbracesA}
 \_def\_removeoutbracesA #1{\_ifx\_fin#1\_else #1\_ea\_removeoutbraces\_fi}
 \_def\_removeoutmath #1$#2${#1\_ifx\_fin#2\_else #2\_ea\_removeoutmath\_fi}
@@ -123,8 +91,10 @@
 corresponds to the text \"Cvičení je zátěž a ${\rm x} ∈ 𝕄$". Notice the 4 bytes
 for the last character, $𝕄$. (Even the whitespace would be OK in a PDF file,
 because it should be ignored by PDF viewers, but \LuaTeX\ doesn't allow it.)
+This conversion is done by the expandable \"pseudoprimitive " \^`\pdfstring`.
 
 \_endinput
 
+2024-12-18 \_pdfhexstring removed, used \_pdfstring.
 2021-02-08 \_octalprint -> \_hexprint
 2020-03-12 Released

Modified: trunk/Master/texmf-dist/tex/optex/base/unimath-codes.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/unimath-codes.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/unimath-codes.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \_ncharrmA {Uni math codes <2023-01-17>} % preloaded on demand by \loadmath
+\_codedecl \_ncharrmA {Uni math codes <2025-02-09>} % preloaded on demand by \loadmath
 
    \_doc -----------------------------
    Unicode math font includes all typical math alphabets together, user needs no
@@ -24,23 +24,21 @@
 
 \_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:
+\_def\_umathholes[#1]#2{\_ifx^#1^\_else
+   \_ea\_chardef \_csname _mh:#1\_endcsname=#2 \_ea\_umathholes\_fi}
+\_umathholes % 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}%
-}
+   [120122]{"2102}[120127]{"210D}[120133]{"2115}[120135]{"2119}%
+   [120136]{"211A}[120137]{"211D}[120145]{"2124}[]{}%
+\_let\_umathholes=\_undefined
+
 \_def\_umathrange#1#2#3#4{\_umathnumB=#4\_def\_classfam{#2 #3 }\_umathrangeA#1}
 \_def\_umathrangeA#1-#2{\_umathnumA=`#1\_relax
    \_loop
-      \_umathcorr\_umathprepare\_umathnumB
-      \_Umathcode \_umathnumA = \_classfam \_umathcorr\_umathvalue{\_umathnumB}
+      \_Umathcode \_umathnumA = \_classfam \_trycs{_mh:\_the\_umathnumB}\_umathnumB
       \_ifnum\_umathnumA<`#2\_relax
          \_advance\_umathnumA by1 \_advance\_umathnumB by1
    \_repeat
@@ -67,7 +65,8 @@
 
    \_doc -----------------------------
    The math alphabets are set by
-   \`\_rmvariables`, \`\_bfvariables`, \`\_itvariables`, \`\_bivariables`,
+   \`\_rmvariables`, \`\_rmletters`, \`\_bfvariables`, \`\_bfletters`,\nl
+   \`\_itvariables`, \`\_itletters`, \`\_bivariables`, \`\_biletters`,\nl
    \`\_calvariables`, \`\_bcalvariables`, \`\_frakvariables`,
    \`\_bfrakvariables`, \`\_bbvariables`,\nl \`\_sansvariables`,
    \`\_bsansvariables`, \`\_isansvariables`, \`\_bisansvariables`,
@@ -96,9 +95,13 @@
 \_chardef\_ncharttA="1D670   \_chardef\_nchartta="1D68A
 
 \_protected\_def\_rmvariables     {\_umathrange{A-Z}71\_ncharrmA \_umathrange{a-z}71\_ncharrma}
+\_protected\_def\_rmletters       {\_umathrange{A-Z}72\_ncharrmA \_umathrange{a-z}72\_ncharrma}
 \_protected\_def\_bfvariables     {\_umathrange{A-Z}71\_ncharbfA \_umathrange{a-z}71\_ncharbfa}
+\_protected\_def\_bfletters       {\_umathrange{A-Z}72\_ncharbfA \_umathrange{a-z}72\_ncharbfa}
 \_protected\_def\_itvariables     {\_umathrange{A-Z}71\_ncharitA \_umathrange{a-z}71\_ncharita}
+\_protected\_def\_itletters       {\_umathrange{A-Z}72\_ncharitA \_umathrange{a-z}72\_ncharita}
 \_protected\_def\_bivariables     {\_umathrange{A-Z}71\_ncharbiA \_umathrange{a-z}71\_ncharbia}
+\_protected\_def\_biletters       {\_umathrange{A-Z}72\_ncharbiA \_umathrange{a-z}72\_ncharbia}
 \_protected\_def\_calvariables    {\_umathrange{A-Z}71\_ncharclA \_umathrange{a-z}71\_ncharcla}
 \_protected\_def\_bcalvariables   {\_umathrange{A-Z}71\_ncharbcA \_umathrange{a-z}71\_ncharbca}
 \_protected\_def\_frakvariables   {\_umathrange{A-Z}71\_ncharfrA \_umathrange{a-z}71\_ncharfra}
@@ -217,8 +220,8 @@
 % For example, you need upright lowercase greek letters, you don't need
 % \bf and \bi behave as sans serif in math, ...
 
-\_protected\_def\_marm {\_inmath{\_rmvariables \_rmdigits}}
-\_protected\_def\_mait {\_inmath{\_itvariables \_itGreek}}
+\_protected\_def\_marm {\_inmath{\_rmletters \_rmdigits}}
+\_protected\_def\_mait {\_inmath{\_itletters \_itGreek}}
 \_protected\_def\_mabf {\_inmath{\_bsansvariables \_bsansgreek \_bsansGreek \_bsansdigits}}
 \_protected\_def\_mabi {\_inmath{\_bisansvariables \_bisansgreek \_bsansGreek \_bsansdigits}}
 \_protected\_def\_matt {\_inmath{\_ttvariables \_ttdigits}}
@@ -560,6 +563,9 @@
 \_endinput
 
 History:
+2026-02-09  \_umathholes use \_chardef
+2026-02-07  \_umathholes reimplemented
+2025-02-06  \_rmletters, \_itletters introduced
 2023-01-17  \int operators re-implemented
 2023-01-15  \mupalpha, \mupbeta etc. have codes from PUA
 2023-01-15  math control sequences are macros, they expand to math characters

Modified: trunk/Master/texmf-dist/tex/optex/base/unimath-macros.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/base/unimath-macros.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/base/unimath-macros.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -1,6 +1,6 @@
 %% This is part of the OpTeX project, see http://petr.olsak.net/optex
 
-\_codedecl \loadmath {Unicode Math fonts <2023-09-03>} % preloaded in format
+\_codedecl \loadmath {Unicode Math fonts <2025-02-06>} % preloaded in format
 
    \_doc -----------------------------
    \`\loadmath` `<optional-factor> {<Unicode-math font>}` loads the given font. It does:
@@ -61,8 +61,13 @@
    \_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`.
+   The base font \^`\_unimathfont` is loaded to family 1 with `script=math`
+   feature. It is generally used for all variables, digits and math symbols.
+   The same font is loaded to family 2 with `script=latn`. It can be used for
+   sequences of letters where we don't want to insert italic correction
+   between them. The default \^`\rm` and \^`\it` macros run \^`\_rmletters` and
+   \^`\_itletters` and they use family 2, so these selectors prohibit italic
+   corrections between letters.
    \nl
    You can combine more fonts if you register them to another
    math families (5, 6, 7, etc.) in the \^`\normalmath` macro.
@@ -70,11 +75,13 @@
    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.
+   The final macro \`\_setunimathdimens` does similar work as \^`\_setmathdimens`.
    \_cod -----------------------------
 
 \_def\_normalunimath{%
     \_setmathfamily 0 \_tenrm             % font for non-math objects in math mode
-    \_loadumathfamily 1 {\_unimathfont}{} % Base font
+    \_loadumathfamily 1 {\_unimathfont}{script=math;} % Base math font
+    \_loadumathfamily 2 {\_unimathfont}{script=latn;} % Base font, no italic corr. between letters
     \_loadmathfamily  4 rsfs              % script
     \_setunimathdimens
 }%
@@ -81,9 +88,11 @@
 \_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
+       \_loadumathfamily 1 {\_unimathfont}{script=math;embolden=1.7;} % Base faked bold
+       \_loadumathfamily 2 {\_unimathfont}{script=latn;embolden=1.7;} % Base faked, no italcor.
     \_else
-       \_loadumathfamily 1 {\_unimathboldfont}{} % Base real bold font
+       \_loadumathfamily 1 {\_unimathboldfont}{script=math;} % Base real bold font
+       \_loadumathfamily 2 {\_unimathboldfont}{script=latn;} % Base real bold, no italcorr.
     \_fi
     \_loadmathfamily  4 rsfs              % script
     \_setunimathdimens
@@ -131,7 +140,7 @@
    \_cod -----------------------------
 
 \_def\_umathname#1#2{"#1:\_mfontfeatures#2"}
-\_def\_mfontfeatures{mode=base;script=math;}
+\_def\_mfontfeatures{mode=base;}
 
 \_def\_loadumathfamily{\_afterassignment\_loadumathfamilyA \_chardef\_mfam}
 \_def\_loadumathfamilyA #1#2 {\_mfactor
@@ -160,16 +169,17 @@
    \_else
       \_newfam#1\_relax
       \_sdef{_mfactor:\_the\_numexpr#1\_relax}{#6}%
-      \_global\_aheadto\_normalmath{\_loadumathfamily #1{#2}{#3} }%
+      \_global\_aheadto\_normalmath{\_loadumathfamily #1{#2}{\_addUmathdefault #3} }%
       \_ifx\_relax#4\_relax
-         \_global\_aheadto\_boldmath{\_loadumathfamily #1{#2}{embolden=1.7;} }%
+         \_global\_aheadto\_boldmath{\_loadumathfamily #1{#2}{\_addUmathdefault embolden=1.7;#3} }%
       \_else
-         \_global\_aheadto\_boldmath{\_loadumathfamily #1{#4}{#5} }%
+         \_global\_aheadto\_boldmath{\_loadumathfamily #1{#4}{\_addUmathdefault #5} }%
       \_fi
       \_normalmath
       \_wterm{add-MATH-FONT: #1=\the#1, "#2", \ifx"#4"\else bold: "#4"\fi}%
    \_fi \_fi
 }
+\_def\_addUmathdefault {script=math;} % default font features when \_addUmathfont is used
 
    \_doc -----------------------------
    The math characters can be given directly (by their Unicode) or by a macro
@@ -345,6 +355,7 @@
 
 \_endinput
 
+2025-02-06 fam2 introduced: no italic corrections are inserted using fam2
 2023-09-03 mathsize does work (luaotfload v. 3.36 corrected the bug
 2023-08-28 mathsize doesn't work now
 2023-07-03 \loadmath: optional scaling factor introduced

Modified: trunk/Master/texmf-dist/tex/optex/demo/op-slides.tex
===================================================================
--- trunk/Master/texmf-dist/tex/optex/demo/op-slides.tex	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/demo/op-slides.tex	2025-02-25 20:43:08 UTC (rev 74285)
@@ -195,7 +195,7 @@
 ...
 \endtt
 
-* You can put the images or text wherever using `\putimege` or `\puttext`
+* You can put the images or text wherever using `\putimage` or `\puttext`
   macros...
 
 \pg; %------------------------------------------------------------------

Modified: trunk/Master/texmf-dist/tex/optex/pkg/math.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/pkg/math.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/pkg/math.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -3,7 +3,7 @@
 % This file can serve as an template for other package files
 % See end of the file for more information
 
-\_def\_math_version {0.16, 2024-10-17}
+\_def\_math_version {0.19, 2025-02-14}
 \_codedecl \replacemissingchars {Doing math more comfortably <\_math_version>}
 \_namespace{math}
 
@@ -414,7 +414,7 @@
 }
 \_def\.textvariables {\.unionly\textvariables {%
    \.textmathini \_mathcodes 6 {7{\_Urange a-z \_Urange A-Z}}%
-   \_addto\_marm {\_fam5 }\_addto\_mait{\_fam6 }%
+   \_def\_marm {\_fam5 }\_def\_mait{\_itGreek \_fam6 }%
    \_protected\_def\_itgreek    {\_umathrangegreek01\_greekita}%
    \_protected\_def\_rmgreek    {\_umathrangegreek01\_greekrma}%
    \_protected\_def\_itGreek    {\_umathrangeGREEK01\_greekitA}
@@ -433,6 +433,45 @@
 \_nspublic \textvariables \textdigits \textmoremath ;
 
    \_doc
+   \`\mathselector` `\sequence {<fontspec-A>} {<fontspec-B>} {<factor>} {<ffeatures>}`
+   declares `\sequence` as a new math selector of the math family `\sequence_fam`.
+   If such family is declared already then new setting is ignored.
+   The font is set by \o`\fontdef` and then its name without size clause and without font features
+   is saved to `\.mselF` using `\.mselA`. The line
+   `\_loadmathfamily <fam> {{<fontname>:<ffeatures>}}` is saved to \o`\_normalmath`
+   and analogical line is saved to \o`\_boldmath`.
+   Finally, if the declared `\sequence` is in `\rm`,`\it`,`\bf`,`\bi`,`\tt` then
+   `\_marm`, `\_mait`, etc.\ is defined else `\sequence` is defined.
+   It guarantees that the re-declaration of `\rm`, `\it`, etc.\ affects their
+   behavior only in math mode.
+   \_cod
+
+\_def\.mathselector #1#2#3#4#5{\.unionly\mathselector{%
+   \_ifcsname \_csstring#1_fam\_endcsname
+      \_opwarning{\_string#1 already defined as \_string\mathselector, ignored}%
+   \_else
+      \_ea\_newfam \_csname \_csstring#1_fam\_endcsname
+      \_ifx^#4^\_else \_sxdef{_mfactor:\_the\_numexpr\_cs{\_csstring#1_fam}}{#4}\_fi
+      \_ifx^#5^\_def\.mselFF{mode=base;script=latn}\_else \_def\.mselFF{#5}\_fi
+      \_fontdef\.mselF{#2}\_ea\.mselA \_fontname\.mselF :\_relax
+      \_edef\.tmp{\_noexpand \_loadmathfamily \_cs{\_csstring#1_fam}{{\.mselF:\.mselFF;}} }%
+      \_global \_ea\_aheadto \_ea\_normalmath \_ea{\.tmp}%
+      \_normalmath
+      \_ifx^#3^\_addto\.mselFF{;embolden=1.7}%
+      \_else \_fontdef\.mselF{#3}\_ea\.mselA \_fontname\.mselF :\_relax \_fi
+      \_edef\.tmp{\_noexpand \_loadmathfamily \_cs{\_csstring#1_fam}{{\.mselF:\.mselFF;}} }%
+      \_global \_ea\_aheadto \_ea\_boldmath \_ea{\.tmp}%
+      \_isinlist{\rm\it\bf\bi\tt}#1\_iftrue
+         \_ea\.mselB \_csname _ma\_csstring#1\_ea\_endcsname \_csname \_csstring#1_fam\_endcsname
+      \_else \_ea\.mselB \_ea#1\_csname \_csstring#1_fam\_endcsname
+   \_fi\_fi
+}}
+\_def\.mselA #1:#2\_relax{\_def\.mselF{#1}}
+\_def\.mselB #1#2{\_gdef#1{\_inmath{\_rmvariables \_rmdigits \_rmgreek \_rmGreek \_fam#2}}}
+
+\_nspublic \mathselector ;
+
+   \_doc
    \`\replacemissingchars``<family>` defines `\UnicodeMathSymbol` and reads
    `unimath-table.opm`, i.e.\ it does for each math character following
    if the character is missing in main math font and if it is present in
@@ -520,31 +559,25 @@
 
 \_newcount \.finalitalcorr
 \_directlua{
-   function math.final_ital_corr(head, style)
-        if style=="text" and tex.count.\_pkglabel _finalitalcorr>0 then
-            for n in node.traverse(head) do
-                if n.next == nil and n.id == 29 then % last is glyph
-                    local k = font.fonts[n.font].characters[n.char].italic
-                    if not(k==nil) and (k>0) then
-                        local kn = node.new("kern")
-                        kn.kern = k kn.subtype = 3
-                        node.insert_after(head, n, kn) % kern node is inserted
-                    end
-                end
-            end
+define_lua_command("\_pkglabel _enablefic", function()
+    lua.get_functions_table()[optex.registernumber("\_pkglabel _enablefic")] = function() 
+        % add the function to the callback only once
+        return tex.setcount("\_pkglabel _finalitalcorr", 1)
+    end
+    tex.setcount("\_pkglabel _finalitalcorr", 1)
+    luatexbase.add_to_callback("post_mlist_to_hlist_filter", function(head, style)
+        if style~="text" or tex.count.\_pkglabel _finalitalcorr<=0 then
+            return true
         end
+        local last = node.tail(head)
+        if last.id ~= node.id("glyph") then return true end % last is glyph
+        local k = font.fonts[last.font].characters[last.char].italic
+        if not k or k<=0 then return true end
+        local kn = node.new("kern", 3)
+        kn.kern = k
+        head = node.insert_after(head, n, kn) % kern node is inserted
         return head
-   end
-}
-\_def\.enablefic {\_directlua{ % math.final_ital_corr is registered to mlist_to_hlist
-   luatexbase.add_to_callback("mlist_to_hlist",
-       function(head, style, penalties)
-           head = node.mlist_to_hlist(head, style, penalties)
-           return math.final_ital_corr(head, style)
-       end, "italcorr after math")
-   }
-   \.finalitalcorr=1
-}
+    end, "italcorr after math") end)}
 \_nspublic \enablefic \finalitalcorr ;
 
 \_endnamespace
@@ -576,6 +609,7 @@
 * \~`\textvariables`, \~`\textdigits`, \~`\textmoremath`
   enables characters from used text font in math mode
   (variables, digits, more characters).
+* \~`\mathselector` declares a new math alphabet using text fonts.
 * \~`\replacemissingchars` allows to re-declare all characters missing in math font
   for printing them from additional math font.
 * \~`\enablefic` enables final italic correction of inline-math lists.
@@ -961,7 +995,82 @@
 described above. For example `\mathsetup{text=digits variables}` is equal to the
 declaration of `\textdigits` `\textvariables`.
 
+\sec Adding a new math alphabet from a text font
 
+Each individual Unicode math font includes several math alphabets together: default
+italic shape and others, which can be selected by `\rm`, `\it`, `\bf`,
+`\bi`, `\tt`, `\cal`, `\frak`, `\bbchar` in math mode. For example, if you
+use `\frak` in math mode, the fracture shapes from loaded Unicode math font are
+used.
+
+If you have a text font with a special alphabet, you can use it in your math formulas
+by a new math selector declared by the \~`\mathselector` macro. For example:
+
+\begtt
+\fontfam[lm]
+\load[math]
+\font\missaali=[Missaali-Regular] % Bold fraktur
+\mathselector \bfrak {\missaali} {\missaali} {} {}
+
+Test: $a = {\frak A}, b = {\bfrak A}_{\bfrak C}$.
+\endtt
+This example declares a new math selector `\bfrak`. When `\bfrak` is used in math mode,
+then the letters are rendered from `Missali-Regular.otf` font.
+
+\^`\mathselector` `\sequence {<fontspec-A>} {<fontspec-B>} {<factor>} {<ffeatures>}`
+declares a new font selector `\sequence` which can be used in math mode.
+This selector selects a text font given by <fontspec-A> in normal math mode
+and by <fontspec-B> in `\boldmath`.
+If <fontspec-B> is empty then faked bold font declared by <fontspec-A>
+is used for `\boldmath`. <fontspec-A> cannot be empty.
+
+The <fontspec-A> and <fontspec-B> declare text fonts. They can be:
+\begitems
+* a font switch deflared by the `\font` primitive,
+* an optional family selector followed by optional font modifiers
+  followed by a variant selector.
+  The actual font selected by this rule is configured as math selector.
+\enditems
+
+The <factor> parameter gives correction scaling factor according to the size
+of the main Unicode math font. If it is empty then factor 1 is assumed.
+
+The <ffeatures> parameter enables you to give font features used for loading
+given fonts. If it is empty, then default font features
+`mode=base;script=latn;` are used.
+
+\^`\mathselector` `\sequence` declares internally a new math family with
+the name `\sequence_fam`. The `\sequence` selector switches to this
+family. So, the declared text fonts work in all math sizes but only for math
+alphabets, Greek letters and digits, because other math symbols (+, =, etc.) are
+bounded (by default) to the fixed math family 1 where Unicode math font is loaded.
+
+Other example:
+\begtt
+\fontfam[lm]
+\mathselector \textit {\it} {\bi} {} {}
+   $AVA$         -- default italic variables from math font.\par
+   $\it AVA$     -- default italic letters from math font.\par
+   $\textit AVA$ -- italic letters from text font.
+\endtt
+You will probably see no difference between these three examples. Where is
+the difference? `$AVA$` uses italic shapes from the
+Unicode math font, `script=math` is specified. Italic corrections between
+characters are inserted. `$\it AVA$` uses the same shapes from the same math font,
+but `script=latn`. This disables italic corrections between
+characters and enables kerning and ligatures. But typical Unicode math font
+doesn't include tables for kerning and ligatures. So, these features
+typically don't work. Finally `$\textit AVA$` uses shapes from text font like
+`{\it ABC}` in text mode. If the font has data for kerning and ligatures
+(which is probably true) then you get this feature in math formulas.
+
+When you re-declare `\rm`, `\it`, `bf`, `\bi` or `\tt` by the `\mathselector` macro,
+then these selectors keep their meaning used in text mode but re-define
+their behavior in math mode according to the declaration. For example
+`\mathselector \it {\it} {\bi} {} {}` declares new behavior of `\it` in math mode
+but `\it` is unchanged in text mode.
+
+
 \sec Replacing all missing math characters from another font
 
 If we load an additional math font by \o`\addUmathfont`, for example:
@@ -1132,6 +1241,8 @@
 
 \endinput
 
+0.19  2025-02-14  \mathselector introduced.
+0.18  2025-01-15  \enablefic modifired.
 0.17  2024-12-04  \mathsetup instead \mathset, \.unionly modified
 0.16  2024-10-17  \mathclap, etc.  corrected.
 0.15  2024-04-28  \_ as interval prefix added.

Modified: trunk/Master/texmf-dist/tex/optex/pkg/minim.opm
===================================================================
--- trunk/Master/texmf-dist/tex/optex/pkg/minim.opm	2025-02-25 20:42:39 UTC (rev 74284)
+++ trunk/Master/texmf-dist/tex/optex/pkg/minim.opm	2025-02-25 20:43:08 UTC (rev 74285)
@@ -179,7 +179,7 @@
 
 \_let\shipout\_shipout
 
-\input minim-hooks
+\_isfile{minim-hooks}\_iftrue \_input minim-hooks \_fi
 
 \_catcode`\:=11
 \_let\_shipout\minim:shipout:new



More information about the tex-live-commits mailing list.