summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/context/sources/general/manuals/luatex/luatex-nodes.tex12
-rw-r--r--doc/context/sources/general/manuals/musings/musings-texlive.tex319
-rw-r--r--doc/context/sources/general/manuals/musings/musings-unicode.tex1584
-rw-r--r--doc/context/sources/general/manuals/ontarget/ontarget-fairphone.tex58
-rw-r--r--doc/context/sources/general/manuals/ontarget/ontarget.tex2
-rw-r--r--scripts/context/lua/mtxrun.lua10
-rw-r--r--scripts/context/stubs/mswin/mtxrun.lua10
-rw-r--r--scripts/context/stubs/unix/mtxrun10
-rw-r--r--scripts/context/stubs/win64/mtxrun.lua10
-rw-r--r--source/luametatex/build.sh15
-rw-r--r--source/luametatex/source/lua/lmtfontlib.c4
-rw-r--r--source/luametatex/source/lua/lmtinterface.h1
-rw-r--r--source/luametatex/source/lua/lmtnodelib.c22
-rw-r--r--source/luametatex/source/lua/lmttexlib.c37
-rw-r--r--source/luametatex/source/luacore/lua54/src/ldo.c14
-rw-r--r--source/luametatex/source/luacore/lua54/src/lopcodes.h2
-rw-r--r--source/luametatex/source/luacore/lua54/src/loslib.c21
-rw-r--r--source/luametatex/source/luacore/lua54/src/ltable.c2
-rw-r--r--source/luametatex/source/luacore/lua54/src/lvm.c4
-rw-r--r--source/luametatex/source/luametatex.h6
-rw-r--r--source/luametatex/source/tex/texexpand.c3
-rw-r--r--source/luametatex/source/tex/texfont.h34
-rw-r--r--source/luametatex/source/tex/texmath.c190
-rw-r--r--source/luametatex/source/tex/texmlist.c83
-rw-r--r--source/luametatex/source/tex/texnodes.h10
-rw-r--r--tex/context/base/mkii/cont-new.mkii2
-rw-r--r--tex/context/base/mkii/context.mkii2
-rw-r--r--tex/context/base/mkii/mult-it.mkii2
-rw-r--r--tex/context/base/mkiv/attr-mkr.mkiv3
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-rw-r--r--tex/context/base/mkiv/context.mkiv2
-rw-r--r--tex/context/base/mkiv/lpdf-mis.lua3
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin24650 -> 24657 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin266630 -> 267358 bytes
-rw-r--r--tex/context/base/mkiv/util-prs.lua9
-rw-r--r--tex/context/base/mkxl/attr-eff.lmt134
-rw-r--r--tex/context/base/mkxl/attr-eff.mkxl4
-rw-r--r--tex/context/base/mkxl/attr-mkr.lmt40
-rw-r--r--tex/context/base/mkxl/attr-mkr.mkxl5
-rw-r--r--tex/context/base/mkxl/attr-neg.lmt104
-rw-r--r--tex/context/base/mkxl/attr-neg.mkxl13
-rw-r--r--tex/context/base/mkxl/char-tex.lmt54
-rw-r--r--tex/context/base/mkxl/cont-new.mkxl2
-rw-r--r--tex/context/base/mkxl/context.mkxl12
-rw-r--r--tex/context/base/mkxl/enco-ini.mkxl11
-rw-r--r--tex/context/base/mkxl/font-ctx.lmt47
-rw-r--r--tex/context/base/mkxl/lang-def.mkxl12
-rw-r--r--tex/context/base/mkxl/lpdf-xmp.lmt3
-rw-r--r--tex/context/base/mkxl/math-acc.mklx37
-rw-r--r--tex/context/base/mkxl/math-act.lmt437
-rw-r--r--tex/context/base/mkxl/math-def.mkxl70
-rw-r--r--tex/context/base/mkxl/math-dld.mklx85
-rw-r--r--tex/context/base/mkxl/math-fen.mkxl56
-rw-r--r--tex/context/base/mkxl/math-ini.mkxl12
-rw-r--r--tex/context/base/mkxl/math-rad.mklx4
-rw-r--r--tex/context/base/mkxl/math-spa.lmt44
-rw-r--r--tex/context/base/mkxl/math-stc.mklx308
-rw-r--r--tex/context/base/mkxl/math-vfu.lmt205
-rw-r--r--tex/context/base/mkxl/mult-sys.mkxl2
-rw-r--r--tex/context/base/mkxl/node-ali.lmt6
-rw-r--r--tex/context/base/mkxl/page-brk.mkxl2
-rw-r--r--tex/context/base/mkxl/phys-dim.lmt1116
-rw-r--r--tex/context/base/mkxl/phys-dim.mkxl64
-rw-r--r--tex/context/base/mkxl/strc-flt.mklx4
-rw-r--r--tex/context/base/mkxl/strc-lst.mklx3
-rw-r--r--tex/context/base/mkxl/syst-aux.mkxl2
-rw-r--r--tex/context/base/mkxl/syst-ini.mkxl2
-rw-r--r--tex/context/base/mkxl/tabl-ntb.mkxl2
-rw-r--r--tex/context/base/mkxl/tabl-tab.mkxl2
-rw-r--r--tex/context/base/mkxl/tabl-tbl.mkxl2
-rw-r--r--tex/context/base/mkxl/typo-ada.lmt6
-rw-r--r--tex/context/base/mkxl/typo-ada.mkxl6
-rw-r--r--tex/context/base/mkxl/typo-adj.mkxl2
-rw-r--r--tex/context/base/mkxl/unic-ini.lmt26
-rw-r--r--tex/context/base/mkxl/unic-ini.mkxl5
-rw-r--r--tex/context/fonts/mkiv/antykwa-math.lfg22
-rw-r--r--tex/context/fonts/mkiv/common-math-jmn.lfg121
-rw-r--r--tex/context/fonts/mkiv/ebgaramond-math.lfg28
-rw-r--r--tex/context/fonts/mkiv/lucida-math.lfg60
-rw-r--r--tex/context/fonts/mkiv/type-imp-concrete.mkiv46
-rw-r--r--tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv24
-rw-r--r--tex/context/fonts/mkiv/type-imp-iwona.mkiv3
-rw-r--r--tex/context/fonts/mkiv/type-imp-kpfonts.mkiv6
-rw-r--r--tex/context/fonts/mkiv/type-imp-kurier.mkiv30
-rw-r--r--tex/context/fonts/mkiv/xcharter-math.lfg3
-rw-r--r--tex/context/interface/mkii/keys-it.xml2
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua2
-rw-r--r--web2c/contextcnf.lua34
-rw-r--r--web2c/texlivecnf.lua14
89 files changed, 4921 insertions, 913 deletions
diff --git a/doc/context/sources/general/manuals/luatex/luatex-nodes.tex b/doc/context/sources/general/manuals/luatex/luatex-nodes.tex
index 1883a0c46..6b9b0bd8c 100644
--- a/doc/context/sources/general/manuals/luatex/luatex-nodes.tex
+++ b/doc/context/sources/general/manuals/luatex/luatex-nodes.tex
@@ -1722,7 +1722,7 @@ The \type{traverse_char} iterator loops over the \nod {glyph} nodes in a list.
Only nodes with a subtype less than 256 are seen.
\startfunctioncall
-<node> n, font, char =
+<node> n, char, font =
node.traverse_char(<node> n)
\stopfunctioncall
@@ -1730,7 +1730,7 @@ The \type{traverse_glyph} iterator loops over a list and returns the list and
filters all glyphs:
\startfunctioncall
-<node> n, font, char =
+<node> n, char, font =
node.traverse_glyph(<node> n)
\stopfunctioncall
@@ -2195,8 +2195,8 @@ number often is reported when you print node related information. You go from
userdata nodes and there numeric references and back with:
\startfunctioncall
-<integer> d = node.todirect(<node> n))
-<node> n = node.tonode(<integer> d))
+<integer> d = node.direct.todirect(<node> n))
+<node> n = node.direct.tonode(<integer> d))
\stopfunctioncall
The userdata model is rather robust as it is a virtual interface with some
@@ -2437,8 +2437,8 @@ consistency. You can of course always define additional accessors using \type
\supported {subtypes} \yes \nop
\supported {subtype} \yes \nop
\supported {tail} \yes \yes
-\supported {todirect} \yes \yes
-\supported {tonode} \yes \yes
+\supported {todirect} \nop \yes
+\supported {tonode} \nop \yes
\supported {tostring} \yes \yes
\supported {traverse_char} \yes \yes
\supported {traverse_glyph} \yes \yes
diff --git a/doc/context/sources/general/manuals/musings/musings-texlive.tex b/doc/context/sources/general/manuals/musings/musings-texlive.tex
new file mode 100644
index 000000000..906b7e88d
--- /dev/null
+++ b/doc/context/sources/general/manuals/musings/musings-texlive.tex
@@ -0,0 +1,319 @@
+% language=us runpath=texruns:manuals/musings
+
+\startcomponent musings-assumptions
+
+\environment musings-style
+
+\setuptolerance[tolerant,stretch]
+
+\startchapter[title={\CONTEXT\ in \TEXLIVE\ 2023}]
+
+Starting with \TEXLIVE\ 2023 the default \CONTEXT\ distribution is \LMTX, a
+follow up on \MKIV, running on top of the \LUAMETATEX\ engine instead of \LUATEX.
+Already for a long time the \MKII\ version used with \PDFTEX, \XETEX\ and \ALEPH\
+has been frozen and most users moved on from \MKIV\ to \LMTX\ (a more distinctive
+tag for what internally is version \MKXL).
+
+In principle one can argue that we now have three versions of \CONTEXT\ and there
+can be the impression that they are very different. However, although \MKXL\ can
+do more than \MKIV\ which can do more than \MKII, the user interface hasn't
+changed that much and old functionality is available in newer versions. Of course
+some old features make no sense in newer variants, like eight|-|bit font
+encodings in an \OPENTYPE\ font realm and input encodings when one uses \UTF,
+although we still support input encodings a.k.a.\ regimes. When we started using
+the \type {Mk*} suffixes the main reason was that we had to distinguish files and
+the official \TEX\ distribution doesn't permit duplicate file names. Using a
+distinctive suffix also makes it possible to treat files differently.
+
+\starttabulate[|T|c|c|c|Tl|]
+\BC suffix \BC engine \BC template \BC arguments \BC main file \NC \NR
+\HL
+\NC MkII \NC \PDFTEX, \XETEX, \ALEPH \NC \NC \NC context.mkii \NC \NR
+\HL
+\NC MkIV \NC \LUATEX, \LUAJITTEX, \LUAMETATEX \NC \NC \NC context.mkiv \NC \NR
+\NC MkVI \NC idem \NC \NC yes \NC \NC \NR
+\NC MkIX \NC idem \NC yes \NC \NC \NC \NR
+\NC MkXI \NC idem \NC yes \NC yes \NC \NC \NR
+\HL
+\NC MkXL \NC \LUAMETATEX \NC \NC \NC context.mkxl \NC \NR
+\NC MkLX \NC idem \NC \NC yes \NC \NC \NR
+\stoptabulate
+
+In this table \quote {template} files are a mix of \TEX\ and \LUA\ and originate
+in the early days of \MKIV; basically, they are a wink to active server pages.
+With \quote {arguments} we refer to files that accept named macro arguments which
+means that they need to be preprocessed. That started as a proof of concept but
+some core files are defined that way. Users will normally just use a \type {.tex}
+file.
+
+The \LUA\ files in the code base have the suffix \type {lua}, or when meant for
+\LUAMETATEX\ that uses a newer \LUA\ engine they can have the suffix \type {lmt}.
+There can also be \type {lfg} (font goodies) and \type {llg} (language goodies)
+plus byte|-|compiled files with various suffixes but these are normally not seen
+by users. We leave it at that.
+
+So, while \TEXLIVE\ 2022 installed \MKII\ and \MKIV, \TEXLIVE\ 2023 installs
+\MKIV\ and \LMTX. Therefore the most significant upgrade is in the engine that is
+used by default: \LUAMETATEX\ instead of \LUATEX. The \MKII\ files are no longer
+installed so we don't need \PDFTEX.
+
+So how did we end up here? Initially the idea was that, because \LUATEX\ is
+basically frozen, \LUAMETATEX\ would be the engine that we conduct experiments
+with and from which occasionally we could backport code to \LUATEX. However it
+soon became clear that this would not work out well so backporting is off the
+table now. Just for the record: the project started years ago so we're not
+talking about something experimental here. There have been articles in \TUGBOAT\
+about what we've been doing over the years.
+
+One of the first decisions I made when starting with \LUAMETATEX\ was to remove
+the built|-|in backend, which then meant also removing the bitmap image inclusion
+code. That made us get rid of dependencies on external libraries. In fact, a
+proof|-|of|-|concept experimental variant didn't use the built|-|in backend at
+all. The font loading code could be removed as well because that was not used in
+\MKIV\ either. In \MKIV\ we also don't use the \KPSE\ library for managing files
+so that code could be dropped from the engine tool; it can be loaded as
+so|-|called optional library if needed but I'll not discuss that here. If you
+look at what happens with the \LUATEX\ code base, you'll notice that updating
+libraries happens frequently and that is not a burden that we want to impose on
+users, especially because it also can involve updating build|-|related files.
+Another advantage of not using them is that the code base remains small.
+
+A direct consequence of all this was that the build process became much more
+efficient and less complex. A fast compilation (seconds instead of minutes) meant
+that more drastic experiments became possible, like most recently an upgrade of
+the math subsystem. All this, combined with an overhaul of the code base, both
+the \TEX\ and \METAPOST\ part, meant that backporting was no longer reasonable.
+Being freed from the constraint that other macro packages might use \LUAMETATEX\
+in turn resulted in more drastic experiments and adding features that had been on
+our wish list for decades. Another side effect was that we could easily compile
+native \MSWINDOWS\ binaries and immediately support transitions to \ARM|-|based
+hardware.
+
+Instead of \quotation {backporting after experimenting}, a leading motive became
+\quotation {fundamentally move forward} while at the same time tightening the
+relation between \CONTEXT\ and the engine: the engine code became part of the
+distribution so that users can compile themselves, which fits perfectly in the
+paradigm (and demands) of distributing all the source code, even that of the
+engine. There is also less danger that patches on behalf of other usage
+interferes with stable support for \CONTEXT. A specific installation is now more
+or less long|-|term stable by design because it no longer depends on binaries
+and|/|or libraries being provided for a specific platform and operating system
+version. Of course installers and \TEXLIVE\ do provide the binaries, so users
+aren't forced to worry about it, but they can move along with a system update by
+recompiling an old, and for their purpose, frozen \CONTEXT\ code base.
+
+An unofficial objective (or challenge) became that the accumulated source stays
+around 12~\MB\ uncompressed, (compressed a bit over 2~\MB) and the binary around
+3~\MB\ so that we could use the engine as an efficient \LUA\ runner as well as a
+launcher stub, thereby removing yet another dependency. That way the official
+\CONTEXT\ distribution didn't grow much in size. A bonus is that we now use the
+same setup for all operating systems. It also opened up the possibility of a
+exceptionally small installation with all bells and whistles included. Another
+nice side effect, combined with automatic compilation on the compile farm, makes
+that we can provide installations that reflect the latest state of affairs: a
+recent binary combined with the latest \CONTEXT. As a result, most users quickly
+went for \LMTX\ instead of \MKIV.
+
+In the code base we avoid dependencies on specific platforms but there are a few
+cases where the code for \MSWINDOWS\ and \UNIX\ differs. However, the
+functionality should be the same. A good test is that for \MSWINDOWS\ we can
+compile with mingw (cross|-|compilation), \MSVC\ (native) and clang (native);
+that order is also the order of runtime performance. The native \MSVC\ binary is
+the smallest but users probably don't care. In any case, it is nice to have a
+fallback plan in place. The code is all in \CCODE; the \METAPOST\ code is
+converted from \CWEB\ into \CCODE\ using a \LUA\ script but we also ship the
+resulting \CCODE\ code. The code base provides a couple of \CMAKE\ files and
+comes with a trivial build script.
+
+When I say that there are no libraries used, I mean external libraries. We do use
+code from elsewhere: adapted \type {avl} as well as \type {decnumber} (for the
+\METAPOST\ library), adapted \type {hjn} (hyphenation), \type {miniz} (zip
+compression), \type {pplib} (for loading \PDF\ files), \type {libcerf} (to
+complement other math library support, but it might be dropped), and \type
+{mimalloc} for memory management. However all the code is in the \LUAMETATEX\
+code base and only updated after checking what changed. The most important
+library originating elsewhere is of course \LUA: we use the latest and greatest
+(currently) 5.4 release. We kept the \type {socket} library but it might be
+dropped or replaced at some point. In addition there is a subsystem for
+dynamically loading libraries; the main reason for that being that I needed \type
+{zint} for barcodes, interfaces to sql databases, a bunch of compression
+libraries, etc. But all that is tagged {\em optional} and \CONTEXT\ will never
+depend on it. There are no consequences for compilation either because we don't
+need the header files. The glue code is very minimalistic and most work gets
+delegated to \LUA.
+
+Initially, because the backend is written in \LUA, there was a drop in
+performance of some 15\percent\ but that was stepwise compensated by gains in
+performance in the engine and additional or improved functionality. The \CONTEXT\
+code base is rather optimized so there was little to gain there, apart from using
+new features. Existing primitive support could also be done a bit more
+efficiently; it helps if one knows where potential bottlenecks are. Therefore, in
+the meantime an \LMTX\ run can be quite a bit faster than a \MKIV\ run and it can
+even outperform a \LUAJITTEX\ run. In practice, the difference between an
+eight|-|bit \MKII\ run using the eight|-|bit \PDFTEX\ engine and a 32|-|bit
+\LUAMETATEX\ run with \LMTX\ can be neglected, definitely on more complex
+documents. I never get complaints about performance from \CONTEXT\ users, so it
+might be a minor concern.
+
+So what are the main differences in the installation? If you really want to
+experience it you should use the standard installation. Currently the small
+installer is the engine that synchronizes the installation over the net and,
+assuming a reasonable internet connection, that takes little time. The
+installation is relatively small, and many of the bytes used are for the
+documentation. Updates are done by transferring only the changed files. The
+\TEXLIVE\ installation is a bit larger because it shares for instance fonts with
+the main installation and these come with resources used by other macro packages.
+Both installations bring \MKIV\ as well as \LMTX\ and therefore provide \LUATEX\
+as well as \LUAMETATEX. However, a \MKIV\ run is now managed by \LUAMETATEX\
+because we use that engine for the runner. The \MKII\ code is no longer in
+\TEXLIVE\ but is in the repositories and used to test and compare with \PDFTEX.
+It just works.
+
+The number of binaries and stubs is reduced to a minimum:
+
+\starttabulate[|T|T||]
+\BC file \BC symlink \BC \NC \NR
+\NC tex/texmf-platform/luametatex \NC \NC combined \TEX, \METAPOST\ and \LUA\ engine \NC \NR
+\NC tex/texmf-platform/mtxrun \NC luametatex \NC script runner, binary \NC \NR
+\NC tex/texmf-platform/context \NC luametatex \NC CONTEXT\ runner, binary \NC \NR
+\NC tex/texmf-platform/mtxrun.lua \NC \NC script runner, lua code \NC \NR
+\NC tex/texmf-platform/context.lua \NC \NC loader for \CONTEXT\ runner \NC \NR
+\NC tex/texmf-platform/luatex \NC \NC the good old ancestor \NC \NR
+\stoptabulate
+
+All of these programs are in the \CONTEXT\ distribution directory \typ
+{tex/texmf-<platform>/}. In addition, \type {context} and \type {mtxrun} are
+symlinks to the \type {luametatex} binary, where possible.
+
+So, the \type {context} command runs \type {luametatex}, but loads the \LUA\ file
+with the same name which in turn will locate the \CONTEXT\ management script
+(\type {mtx-context}) in the \TEX\ tree and run it. The same is true for \type
+{mtxrun}: it is a binary (link) that loads the script in (this time) the same
+path and then can perform numerous tasks. For instance, identifying the installed
+fonts so that they can be accessed by name is done with:
+
+\starttyping
+mtxrun --script font --reload
+\stoptyping
+
+Where in \MKII\ we had stubs for various utility scripts, already in \MKIV\ we
+went for a generic runner and a bit more keying. It's not like these scripts are
+used a lot and by avoiding shortcuts there is also little danger for a mixup with
+the ever|-|growing list of other scripts in \TEXLIVE\ or commands that the
+operating system provides.
+
+The \LUATEX\ binary is optional and only needed if a user also wants to process
+\MKIV\ files. There are no shell scripts used for launching. The two main calls
+used by users are:
+
+\starttyping
+context foo.tex
+context --luatex foo.tex
+\stoptyping
+
+A user has only to make sure that the binaries are in the path specification.
+When you run from an editor, the next command does the work:
+
+\starttyping
+mtxrun --autogenerate --script context <filename>
+\stoptyping
+
+with \type {<filename>} being an editor|-|specific placeholder. Like other
+engines, \LUAMETATEX\ (and \CONTEXT) needs a file database and format file, and
+although it should generate these automatically you can make them with:
+
+\starttyping
+mtxrun --generate
+context --make
+\stoptyping
+
+The rest of the installation is similar to what we always had and is \TDS\
+compliant. The source code of \LUAMETATEX\ is included in the distribution itself
+(which nicely fulfills the requirements) but can also be found at:
+
+\starttyping
+https://github.com/contextgarden/luametatex
+\stoptyping
+
+There are also some optional libraries there but \CONTEXT\ works fine without
+them. The official latest distribution of \CONTEXT\ itself is:
+
+\starttyping
+https://github.com/contextgarden/context
+https://github.com/contextgarden/context-distribution-fonts
+\stoptyping
+
+We see users grab fonts from the Internet and play with them. They can install
+additional fonts in \typ {tex/texmf-fonts/data/<vendor>}. Project|-|specific
+files can be collected in \typ {tex/texmf-project/tex/context/user/<project>}.
+These directories are not touched by installations and can easily be copied or
+shared between different installations. After adding files to the tree \typ
+{mtxrun --generate} will update the file database.
+
+In the distribution there are plenty of documents that describe how \LUAMETATEX\
+with \LMTX\ differs from \MKIV\ with \LUATEX: new primitives, macro extensions,
+more granular math rendering, improved memory management, new (or extended)
+(rendering) concepts, more \METAPOST\ features; most is covered in one way or
+another, and much is already applied in the \CONTEXT\ source code. After all, it
+took a few years before we arrived here so you can expect substantial refactoring
+of the engine as well as the code base, and therefore eventually there is (and
+will be) more than in \MKIV.
+
+When you compare a \CONTEXT\ installation with what is needed for other macro
+packages you will notice a few differences. One concerns the way \TEX\ is
+launched. An engine starts with a blank slate but can be populated with a
+so|-|called format file that is basically a memory dump of a preloaded macro
+package. So, the original way to process a file is to pass a format filename to
+the engine. In order to avoid that a trick is used: when an engine (or
+symlink|/|stub to it) is launched by its format name, the loading happens
+automatically. So, for instance \type {pdflatex} is actually an equivalent for
+starting \PDFTEX\ with the format file \typ {pdflatex.fmt} while \type {latex} is
+\PDFTEX\ with another format file (\typ {latex.fmt}) starting up in \DVI\ mode.
+And, as there are many engines, a specific macro package can have many such
+combinations of its name and engine.
+
+In \CONTEXT\ we don't do it that way. One reason is that we never distinguished
+between backends: \MKII\ uses an abstract backend layer and load driver files at
+runtime (it was one of the reasons why we could support \ACROBAT\ as soon as it
+showed up, because we already supported the now obsolete but quite nice
+\DVIWINDO\ viewer). And that model hasn't changed much as we moved on. Because we
+use a runner, we also don't need to distinguish between engines: all formats have
+the same name but sit on an engine subpath in the \TEX\ tree. Anyway, this
+already removes quite some formats. On the other hand, \CONTEXT\ can be run with
+different language specific user interfaces which means that instead of just
+\type {context.fmt} we have \type {cont-en.fmt} and possibly more, like \type
+{cont-nl.fmt}. So that can increase the number again but by default only the
+English interface is installed. As a side note: where with \MKII\ we needed to
+generate \METAPOST\ mem files, with its descendants having \MPLIB\ we load the
+(actually quite a bit of) \METAPOST\ code at runtime. \footnote {Occasionally I
+do experiments with loading the \TEX\ format code at runtime, but at this moment
+the difference in startup time of about one second (assuming files are cached) is
+too large and running over networks will be less fun, so the format file will
+stay. The time involved in loading \METAPOST\ can be brought down but for now I
+leave it as it is.}
+
+In addition to a format file, for the \LUATEX\ and \LUAMETATEX\ engine we also
+have a (small) \LUA\ loader alongside the format file. All this is handled by the
+runner, also because we provide extensive command line features, and therefore of
+no concern to users and package maintainers. However, it does make integrating
+\CONTEXT\ in for instance \TEXLIVE\ different from other macro packages and
+thereby puts an extra burden on the \TEXLIVE\ team. Here I want to thank the team
+for making it possible to move forward this way, in spite of this rather
+different approach. Hopefully a \LUAMETATEX\ integration is a bit easier in the
+long run because we no longer have different stubs per platform and at least the
+binary part now has no dependencies and only has a handful of files.
+
+For those new to \CONTEXT\ or those who want to try it in \TEXLIVE\ 2023 there is
+not much difference between the versions. However, \MKIV\ is now frozen and new
+functionality only gets added to \LMTX. Of course we could backport some but with
+most users already having moved on, it makes no sense. Just as we keep \MKII\
+around for testing with \PDFTEX, we also keep \MKIV\ alive for testing with
+\LUATEX. Maybe in a couple of years \MKIV\ will go the same route as \MKII:
+ending up in the archives as an optional installation. \footnote {This text
+appeared in \TUGBOAT\ around the 2023 \TEXLIVE\ release. Thanks to Karl Berry for
+his careful reading and fixing of the text and of course for keeping \TEXLIVE\
+alive.}
+
+\stopchapter
+
+\stopcomponent
diff --git a/doc/context/sources/general/manuals/musings/musings-unicode.tex b/doc/context/sources/general/manuals/musings/musings-unicode.tex
new file mode 100644
index 000000000..06ec01985
--- /dev/null
+++ b/doc/context/sources/general/manuals/musings/musings-unicode.tex
@@ -0,0 +1,1584 @@
+% language=us runpath=texruns:manuals/math
+
+\def\unichar#1#2{#1 (U+#2: \char"#2)}
+
+\def\APL{\ss apl}
+
+% \useMPlibrary[dum]
+
+\startcomponent musings-unicode
+
+\environment musings-style
+
+% \usemodule[mathfun]
+
+\startchapter[title=Unicode]
+
+\startsection[title=Introduction]
+
+When working on a \TEX\ macro package for decades one can hardly avoid dealing
+with math; after all \TEX\ is pretty much about math. When this wonderful
+typesetting infrastructure was written it was all about quality and how to make
+your documents look nice. And for sure, Don Knuths documents looks nice, also
+because he pays a lot of attention to the \quotation {fine points of math
+typesetting}.
+
+The constraints of those time (like hardware, compilers, fonts, and for sure also
+time) made \TEX\ into what it is: eight bit character sets, eight bit fonts,
+eight bit hyphenation patterns, efficient memory usage and therefore carrying
+around as little as possible. It all makes sense. But one needs to pay attention.
+\footnote {And that is what Mikael Sundqvist and I have been doing a lot since we
+started upgrading math in \CONTEXT\ in combination with enhancing the math engine
+in \LUAMETATEX. The story here is a byproduct of our explorations and very much a
+combined effort.}
+
+Math typesetting is actually a sort of separated process in the engine:
+unprocessed lists go in and after some juggling a list of assembled boxes,
+glyphs, glues and penalties come out. I will not go into detail about that and
+only mention that in \LUAMETATEX\ we extended all this to be a bit more flexible
+and controllable, something that has been driven by the fact that we need to
+support \UNICODE\ fonts. This is all part of a related effort to move from eight
+bit \quote {everything} to \UNICODE\ \quote {everywhere}.
+
+Now, one can say a lot about \UNICODE\ but the main advantage is that it tries to
+cover \quote {all} characters ever encountered, including scripts (used in
+languages) that are long gone, as well as these little pictures that people like
+to see on the web: emojis. One can safely say that \UNICODE\ simplifies mixing
+languages and scripts, and thereby makes \TEX\ macro packages less complex. On
+the other hand, \UNICODE\ (or more precisely, related wide) fonts makes all kind
+of features possible and thereby add a complication.
+
+So, how about math? When Don Knuth gave us \TEX\ he also gave us fonts and there
+are plenty symbols in these fonts. But, as mathematicians seem to love variations
+on symbols soon more fonts arrived, most noticeably those from the \AMS\ that
+also added some more alphabets: mathematicians also love to render the shapes of
+letters differently. In order to access these glyphs names were invented that
+also sometimes suggested that there was some order in the matter. And, for some
+reason these names got aliases and soon we had a huge list of often obscure and
+inconsistent macro names. It didn't take long for a little mess and confusion to
+creep in.
+
+It has been said that the verbose \TEX\ math \ASCII\ input format is also a way
+for mathematicians to communicate, just because many use the same tool to render
+the formulas. Of course that gets obscured when one starts to add additional
+macros. It gets even more tricky once we start talking \quote {standard} as in
+\quotation {\LATEX\ is the standard}. That has for instance resulted in browsers
+interpreting \TEX\ like input without using \TEX\ (so how about expansion?). It
+has also sort of put \TEX\ into the range of possible word processing systems,
+which in turn leads to these \MSWORD\ versus Google docs versus \LATEX\ debates
+that can get rather nasty and unrealistic when it comes to discussing usage and
+quality. Interestingly, \MSWORD\ now has reasonable math, to some extent
+modelled after \TEX. It has some verbose \TEX\ like (but constrained) input and
+would do well for probably mostly people who occasionally have to inject some
+math. There were also attempts by the people at \MICROSOFT\ to normalize the
+input but we leave that aside now.
+
+However, because we now do have all these symbols and because source code editors
+make them accessible and show them there is a good chance that users will inject
+them, if only by cut and paste, so we do have to deal with that. This
+automatically puts us in the position that we need to deal with different
+meanings for the same symbol, which in turn might demand different spacing,
+penalties and such. In the end it is users that drive all this, not publishers;
+they don't really care and out|-|source typesetting anyway. We're not aware of
+any research and development being done and I suppose we would have noticed
+because after all we're involved in developing \LUATEX. It is one of the engines
+that does \OPENTYPE\ and \UNICODE\ math and no publisher or supplier ever took
+serious interest in it. From our perspective what users do is visible, everything
+else is hidden behind corporate curtains. And this is why nowadays we only need
+to care about users (mainly authors).
+
+Back to typesetting. For a long time all went well: one could typeset documents
+that looked good. Okay, not all looked good because not everyone paid attention to
+details, and the more the web evolved the more patching cut'n'paste of bad
+examples made its way into documents, but let's not start talking quality here.
+But then came \UNICODE\ and a while later people started talking about
+accessibility, cutting and pasting and more. In the meantime there had been
+developments like \MATHML\ and \OPENMATH\ that tried to structure and organize
+formulas in a more symbolic way. \footnote {It probably went unnoticed that
+\CONTEXT\ always supported rendering \MATHML, and as such had to deal with all
+the weird aspects (read: way it was used). Although one is not supposed to
+directly edit \MATHML\ we work with authors who are quite happy to do that simply
+because they code the documents in \XML\ because there is a need for high quality
+\PDF\ as well as \HTML\ output and a \CONTEXT\ based workflow can handle the
+\XML\ well. We're talking of large volumes here (mostly for basically free
+school math).}
+
+In the meantime the \TEX\ community had lost the edge on fonts, and \OPENTYPE\
+math was invented by \MICROSOFT\ and implemented in \MSWORD\ before a substantial
+number of \TEX\ users understood what was happening. They had it coming. To a
+large extend one can say the same about math in \UNICODE. Where a Greek capital
+\quote {A} is seen as different from a Latin capital \quote {A}, even when they
+often have the same shape, a math italic variable \quote {h} was made synonym to
+\quote {Planck constant}, as if the letters used in math had no meaning at all.
+We'll see that a wide hat is an extensible character of zero width combining hat
+accent, which makes for curious handling of the initial character. There is more
+granularity in some symbols, especially popular symbols like slashes and bars,
+than in letters. It is as if the math community didn't care much about how the
+letters (variables) were communicated and perceived but were picky about the
+slope of slashes. It seems more of a visual world, which might actually be the
+reason structured input never really took of. Maybe \TEX ies just love the mix of
+characters, commands, spacing directives. Maybe they just love to reposition and
+space these glyphs to suit all kind of curious non|-|standard math rendering.
+
+All this makes it pretty hard to communicate meaning, and it is just one of the
+examples where the \TEX\ community, for as far involved, failed to make a strong
+case. Our personal opinion is that no one really cared because in the \TEX\
+community it is all about rendering. The fact that we use math to communicate
+only gained attention when accessibility became hot and by then it was too late.
+Efforts like \OPENMATH\ started ambitious and in the end basically failed. Coding
+in \XML\ using \MATHML\ isn't much better and one always had to adapt to the
+latest fashion. Also, once plenty code shows up bugs become features. Browser
+support came and went and came back. Simplified input using for instance
+\ASCIIMATH\ started indeed simple but quickly became a (somewhat inconsistent)
+mess. What we see here is the same as everything web (and computer languages): we
+can do better, we start some project, then move on, and we end up with half|-|way
+abandoned results. The development cycles are short, results have to be achieved
+fast, there is no time (or interest) for iterating and refactoring. The word
+\quote {standard} and mantra \quote {everyone should use this} are quite popular.
+
+So where does that leave us with \TEX ? Well, with a mess. Decades of various
+efforts have not brought us a coherent system of organizing symbols and
+properties, made us end up with inconsistencies, made users revert to hacks,
+didn't make math easily transferable and complicates rendering. Personally we
+find it sort of strange that we spend time on for instance tagging and
+accessibility before we get these math alphabets and shared math specific symbols
+sorted out. If we cannot make good arguments for that (math being a script on its
+own with semantics and such) we waste energy and are pulling a dead horse. What
+puzzles us most is that one would expect mathematicians to be able to come up
+with strong arguments for a structured approach. But maybe it was simply the fact
+that \TEX\ math typesetting was pretty much driven by large commercial publishers
+and those providing services for them: the first category doesn't invest in these
+matters and even less today, and the second category makes money from sorting out
+the mess, so why get rid of it. Who knows. For us, it means that any complain
+about these matters deserves the same answer: the \TEX\ community created this
+mess, so it has to live with it. And the bad thing is: bugs and work|-|arounds
+eventually become features and then one is supposed to conform, even if deep down
+one knows better. It doesn't help that the community is proud of what it can
+render and has built itself a reputation that all is good.
+
+So why this criticism? Why not just abandon \TEX ? The answer is simple: \TEX\ is
+quite okay and cannot be blamed for where we are now. We need to think of
+solutions and in that respect the \CONTEXT\ users are lucky! They have always
+been told not to use this macro package for math because there are other
+standards and because publishers want \LATEX\ (even if they just let the
+manuscripts be recoded). That means that we don't really need to care much about
+the past. Those who use \CONTEXT\ can benefit from the compatibility we have
+anyway but also move forward to more structured and consistent math. It is in
+this perspective that we will discuss some more details next so that eventually
+we can draw some conclusions. The end goal is to have an additional layer of
+grouping math symbols that permits consistent high quality rendering in a mixed
+input environment.
+
+\stopsection
+
+\startsection[title=Molecules]
+
+Before we go into details about some characters, we spend some word on the
+rendering. The building blocks of a formula are atoms and internally the term
+nucleus is used for what we have without scripts. The simple sequence \type {1 +
+x} will result in a linked list of three atoms with three nuclei. In \type {x^2}
+the \type {x} is the nucleus. Atoms can have scripts: prescripts, postscripts and
+a prime. The majority of \UNICODE\ math characters become such atoms (nuclei and
+scripts) and they get a class property that determines their spacing, but that is
+not part of the \UNICODE\ specification. From the upcoming sections it will be
+clear that when we classify we don't get that much help from \MATHML\ or even the
+\TEX\ community either.
+
+In addition to these atoms the \LUAMETATEX\ engine (which builds upon \TEX) has
+what we can call molecules. There are several types: fractions, accents, fences,
+radicals. This distinction is to some extent present in \UNICODE: plenty of
+fraction related slashes, all kind of accents, vertical delimiters that can be
+made from snippets and act as fences, and a radical symbol. In \MATHML\ we see
+similar constructs but there in practice quite often operators need to be
+interpreted in a way that can distinguish between atoms and molecules. That is
+partly a side effect of applications that generate \MATHML. And as usual with
+standards pushed upon the world without years of exploration the confusion became
+part of the norm and will stay.
+
+In the \TEX\ engine over and under delimiters are implemented on top of radicals
+(using the same noad, the wrapper node for yet unprocessed math) but they have
+different code paths. Basically we have vertically fenced material and just like
+fractions have left and right fences as part of the concept (for binominals) the
+radical has a sort of left fence too. You can also wonder why we need accent
+noads while we support other delimiters with radicals. This organization mostly
+relates to subtypes and classes (and likely some limitations of the past) that
+have related spacing properties, but we can think if a generic structure noad and
+meaningful subtypes. However, that is not what we get so let's be more precise:
+
+{\bf Fractions:} these stack two atoms (or molecules) and separate them by a
+visible or phantom rule, or in \LUAMETATEX\ by a delimiter. They can have a left
+and right fence which originates in them also suitable for binominals. You may
+wonder why we don't use regular fences here. One reason we can think of is that
+when you fence something, you have an open and close class at the edges while
+with a fenced fraction the whole still is fraction. In \LUAMETATEX\ we can tweak
+classes at the edges but in regular \TEX\ there are fewer classes, so there
+constructs become ordinary or inner.
+
+{\bf Accents:} these put something on top of or below an atom (or molecule) and
+are driven by characters. The accent related commands take an integer
+(traditional) or three integers (extended) and it is this expected input that
+drives it. However, they are treated like delimiters. In traditional \TEX\ a
+delimiter is defined by two characters: the direct unscaled one, and when not
+found a second one drives the lookup from wider variants and eventually an
+extensible character. Accents just have the second one, which probably relates to
+the fact that the text ones that would be the starting point make no sense. It is
+this \quote {looking} for a single code point that makes that accents are not
+merged with the more general radical command space. Another reason is that
+accents deal a bit different with spacing and italic correction so even if we
+could merge, it would be more confusing in the end.
+
+{\bf Fences:} these come in pairs with optional middle ones. The reason for
+pairing is that they need to get the same size. That means that before we
+construct them the atom or molecule that they fence has to be analyzed. It also
+makes the result a construct of its own, although in \LUAMETATEX\ we can unpack
+that result so that it can be broken across lines. In practice that was never an
+issue because in a running text unscaled fences are used (just atoms with open
+and close classes assigned) but as soon as one goes to multi|-|line displays
+formulas things become more hairy. The related commands expect delimiters (the
+two part character definitions) but in the meantime are also happy with a single
+one because in the end \OPENTYPE\ math has all in one font.
+
+{\bf Radicals:} originally this only concerned roots but because they are
+basically wrappers we also use them for content that gets a delimiter above,
+below or both. In that sense the term radical can also be interpreted as \quote
+{extreme}, more than a carrot looking symbol. The related commands take one or
+more delimiters (or character) because we support left as well as right
+delimiters connected by a rule, so in the end radicals evolved into a construct
+with delimiters of all kind. So, the unique property of radicals is that the
+fences assume a cooperation between one or more glyphs and a rule. In \CONTEXT\
+we support actuarian hooks as radicals that are used for annuity expressions,
+otherwise the \UNICODE\ symbols is useless and the \MATHML\ construct complex.
+
+So, where accents take numbers as delimiter specification, fences, fractions and
+radicals take specific math quantities or just letters. This makes that we will
+not merge these into one scanner and handler even if they all use the same
+(large) noad to store and carry around their properties. Also, it has some charm
+to keep the original \TEX\ distinctions. After all, it's not like \UNICODE,
+\MATHML\ or \OPENTYPE\ math fonts have brought some new insights: in the end they
+all draw from \TEX\ and they way it's done there.
+
+\stopsection
+
+\startsection[title=Symbols]
+
+There are plenty of symbols in \UNICODE. When we try to get an idea how we ended
+up with that set we're surprised that not much seems to be known about it. There
+are references to \ISO\ standards, usage by specific organizations (like those
+dealing with patents), there are references to lists of publishers. In personal
+communications with people involved it becomes clear that the criterion that some
+symbols really has to be used somewhere doesn't apply to these math symbols.
+There are bizarre specimens that we cannot locate anywhere. They are often
+assigned the \quote {relation} property which for \TEX\ is a safe bet because
+binary and relations get similar spacing, but binary makes an exception when it
+sits at the front. The fact that relation spacing is used can even obscure the
+fact that some characters have zero width properties; the results just look
+somewhat bad and one can always blame the font or renderer and adding some thin
+spacing is accepted behavior. So one can make the argument that because \TEX\ was
+the main renderer of math, a safe bet was better than a confusing and
+unproven|-|by|-|usage assignment to some category.
+
+In \TEX\ some symbols have multiple names, even when they have the same class.
+This indicates the wish for meaning at one end but shape at the other, and once a
+name has been assigned it sticks. It would be interesting to know how
+mathematicians see formulas: if one puts \type {\bar}s around a variable does one
+see \quotation {bar x bar} or \quotation {the modulus of x}, and how is translation
+to audio to be performed?
+
+One important aspect of using any symbol in \TEX, or basically any typesetting
+system that deals with math, is that the spacing depends on the meaning. Now, in
+the perspective of \UNICODE\ meaning is somewhat diffuse. A Latin capital \quote
+{A} related to \quote {a} is not the same as a Greek capital \quote {A} that
+relates to \quote {\alpha}. So, from the shape one cannot beforehand deduce what is
+meant, but when copying it the \UNICODE\ will expose the meaning. This is not the
+case in math: although many symbols have one meaning only, there are also plenty
+that can mean different things and the (\TEX) math community has not been able to
+make a strong case for providing different slots. Maybe the reason was that there
+already was a tradition of using commands that then relate a shape to a class
+that then results in appropriate spacing. Maybe it is also assumed that an
+article or book starts by explaining what a specific symbol means in that
+particular context. But that doesn't help much for copying. It also doesn't help
+with direct \UNICODE\ input. The way out for this last problem is that in
+\CONTEXT\ we will add additional properties to characters that then can
+communicate the class and thereby control the spacing. Although we initially did
+that at the \LUA\ end we now use the lightweight dictionary feature of the
+engine: a property, group, slot model. The main reason is that we foresee that at
+some point we might have to add property based rendering to the engine, and this
+opens up that possibility. Ever since we started with \LUATEX\ and \MKIV\ we have
+used the character database (in \LUA\ format) to store most properties so that we
+have all in one place.
+
+For figuring out the properties we can look at how traditionally symbols got
+multiple commands associated, how \MATHML\ looks at it, what \UNICODE\ reveals and
+what we find in fonts. It is a bit of jungle out there so for sure we have to
+make decisions ourselves. We next turn to that exploration.
+
+\stopsection
+
+\startsection[title=Slashes]
+
+The definition on the \WIKIPEDIA\ page [1] of slashes is as follows:
+
+\startquotation
+ The slash is an oblique slanting line punctuation mark /. Once used to mark
+ periods and commas, the slash is now used to represent exclusive or inclusive
+ or, division and fractions, and as a date separator. It is called a solidus
+ in \UNICODE, is also known as an oblique stroke, and has several other
+ historical or technical names including oblique and virgule.
+\stopquotation
+
+The page then has a very detailed description on how slashes are used in text,
+mathematics, computing, currency, dates, numbering, linguistic transcriptions,
+line breaks, abbreviations, proofreading, fiction, libraries, addresses, poetry,
+music, sports, and text messages. It is a pretty good and detailed page which also
+gives a nice summary of usage in math.
+
+In mathematics, we use the slash (a forward leaning bar) for fractions, division,
+and quotient of set. Examples of fractions are $\vfrac {1} {2}$ but also
+$\percent$ sits in this category.
+
+\starttabulate[|T|l|l|]
+\NC U+0002F \NC \switchtobodyfont[stixtwo]$\utfchar{"0002F}$ \NC this is the official solidus \NC \NR % /
+\NC U+02044 \NC \switchtobodyfont[stixtwo]$\utfchar{"02044}$ \NC the mathematical fraction slash \NC \NR % ⁄
+\NC U+02215 \NC \switchtobodyfont[stixtwo]$\utfchar{"02215}$ \NC the mathematical division slash \NC \NR % ∕
+\NC U+02571 \NC \switchtobodyfont[stixtwo]$\utfchar{"02571}$ \NC a diagonal box drawing line \NC \NR % ╱
+\NC U+029F8 \NC \switchtobodyfont[stixtwo]$\utfchar{"029F8}$ \NC the mathematical big solidus \NC \NR % ⧸
+\NC U+0FF0F \NC \switchtobodyfont[stixtwo]$\utfchar{"0FF0F}$ \NC a full width solidus \NC \NR % /
+\NC U+1F67C \NC \switchtobodyfont[stixtwo]$\utfchar{"1F67C}$ \NC the very heavy solidus \NC \NR % 🙼
+\stoptabulate
+
+The \STIX\ fonts have the first five, the rest is not there, so we can safely
+assume that they are not used in math. That brings us to the question that, say
+that the other ones are used, how does the user access them? In the editor they
+often look pretty much the same. For \TEX ies the answer is easy: you use a
+command. But as we already mentioned, there we enter a real fuzzy area: these
+commands either describe a shape or they communicate a meaning, at least, in an
+ideal world. Sometimes wrapping in a macro helps, like \typ {$\vfrac {1} {2}$}.
+
+In the document that explains \UNICODE\ math there is a section \quotation
+{Fraction Slash and Other Diagonals}. Even if we limit ourselves to the forward
+leaning slashes it looks like we need to include
+exotic symbols, as the empty set symbol with an left arrow on top: \type
+{U+29B4} a circle with left pointing arrow on top, that doesn't show up in most
+math fonts but \STIX\ has it {\switchtobodyfont[stixtwo]{$⦴$}}. We quote:
+
+\startquotation
+ \type {U+2044 ⁄} \typ {FRACTION SLASH} is typically used to build up simple
+ skewed fractions in running text. It applies to immediately adjacent
+ sequences of decimal digits, that is, to spans of characters with the General
+ Category property value \type {Nd}. For example, \type {1⁄2} should be
+ displayed as \type {½}. In ordinary plain text, any character other than a
+ digit delimits the numerator or denominator. So \type {5 1⁄2} should be
+ displayed as \type {5½} since a space follows the \type {5}. In general
+ mathematical use, a more versatile method for layout of fractions is needed
+ (see, for example, Section 2.1 of [UnicodeMath]), however parsers of
+ mathematical texts should be prepared to handle \typ {FRACTION SLASH} when it
+ is received from other sources. \type {U+27CB}
+ \typ {MATHEMATICAL RISING DIAGONAL} and \type {U+27CD}
+ \typ {MATHEMATICAL FALLING DIAGONAL} are
+ mathematical symbols for specific uses, to be distinguished from the more
+ widely used solidi and reverse solidi operators as well as from
+ nonmathematical diagonals.
+\stopquotation
+
+In \TEX\ there is no parsing going on: we just get sequences of atoms and the
+inter atom spacing applies. Curly braced arguments are used to communicate units
+that needs to be treated a while. As side note: where for some scripts there are
+special characters that tell where something (state) starts and ends this is not
+available for math, which makes it impossible to mark a sequence of characters as
+being something math. The whole repertoire of pre|-|composed fractions and super-
+and subscripted \UNICODE\ symbols are not to be used in math.
+
+Most documents that somehow relate to or (partially) originate in \TEX\ can
+be rather fuzzy, so we can read here:
+
+\startquotation
+ \type {U+27CB} corresponds to the \LATEX\ entity \type {\diagup} and \type
+ {U+27CD} to \type {\diagdown}. Their glyphs are invariably drawn with 45° and
+ 135° slopes, respectively, instead of the more upright slants typical for the
+ solidi operators. The diagonals are also to be distinguished from the two box
+ drawing characters \type {U+2571} and \type {U+2572}. While in some fonts
+ those characters may be drawn with 45° and 135° slopes, respectively, they
+ are not intended to be used as mathematical symbols. One usage recorded for
+ \type {U+27CB} and \type {U+27CD} is in the notation for spaces of double
+ cosets.
+\stopquotation
+
+So, it is the angles that math users should translate into meaning which I guess
+is natural for them. From the above we cannot deduce if we should take them into
+account in a macro package.
+
+The \MATHML\ specification [3] keeps it abstract and talks about division without
+mentioning the rendering. In content \MATHML\ we have:
+
+\starttyping
+divide = element divide { CommonAtt, DefEncAtt, empty}
+\stoptyping
+
+and the suggested rendering (from an example) is a slash.
+
+In the chapter \quotation {Characters, Entities and Fonts} there is mentioning of:
+
+\startquotation
+ There is one more case where combining characters turn up naturally in
+ mathematical markup. Some relations have associated negations, such as \type
+ {U+226F} [\typ {NOT GREATER-THAN}] for the negation of U+003E [\typ
+ {GREATER-THAN SIGN}]. The glyph for U+226F [NOT GREATER-THAN] is usually just
+ that for U+003E [\typ {GREATER-THAN SIGN}] with a slash through it. Thus it
+ could also be expressed by \type {U+003E}|-|\type {U+0338} making use of the
+ combining slash \type {U+0338} [COMBINING LONG SOLIDUS OVERLAY]. That is true
+ of 25 other characters in common enough mathematical use to merit their own
+ \UNICODE\ code points. In the other direction there are 31 character entity
+ names listed in [\typ {Entities}] which are to be expressed using \type
+ {U+0338} [\typ {COMBINING LONG SOLIDUS OVERLAY}].
+\stopquotation
+
+A curious note is this:
+
+\startquotation
+ For special purposes, one may need a symbol which does not have a \UNICODE\
+ representation. In these cases one may use the \type {mglyph} element for
+ direct access to a glyph as an image, or (in some systems) from a font that
+ uses a non|-|\UNICODE\ encoding. All \MATHML\ token elements accept
+ characters in their content and also accept an \type {mglyph} there. Beware,
+ however, that use of \type {mglyph} to access a font is deprecated and the
+ mechanism may not work in all systems. The \type {mglyph} element should
+ always supply a useful alternative representation in its alt attribute.
+\stopquotation
+
+At some point we experimented with very precise positioned \HTML\ from \TEX\
+(read: \CONTEXT) and that worked very well: the rendering was exactly the same as
+\PDF\ but then suddenly it was no longer possible to access glyphs from fonts. The
+assumption had become that one should feed text into the font rendering machinery
+and use \OPENTYPE\ features to access specific shapes, which of course is a
+fragile approach (the libraries and logic keep evolving, and the most robust
+access is simply by index, or by glyph name if present, assuming that one uses
+the font that was meant to be used). So, how the \MATHML\ glyph element is
+supposed to work out well is not clear. Anyway, as we want nicely typeset math we
+don't care that much if features present in \LUAMETATEX\ and \CONTEXT\ are unique
+and cannot be reproduced otherwise.
+
+In \type {mathclass.txt} [4] which is \quotation {{\em not} formally part of the
+\UNICODE\ Character Database at this time} we see a classification:
+
+\starttabulate[|T|l|]
+\NC U+0002F \NC binary \NC \NR
+\NC U+02044 \NC binary \NC \NR
+\NC U+02215 \NC binary \NC \NR
+\NC U+02571 \NC not mentioned \NC \NR
+\NC U+029F8 \NC n-ary or large operator, often takes limits \NC \NR
+\NC U+0FF0F \NC not mentioned \NC \NR
+\NC U+1F67C \NC not mentioned \NC \NR
+\stoptabulate
+
+So, in the end we can focus on the four that are mentioned, and we will do that
+with the above in mind as well as what is common in the \TEX\ world. We will look
+at usage, classification (groups) and classes.
+
+% modern % ok, both the same
+% cambria % different, no extensible /
+% bonum % ok, both the same
+% pagella % ok, both the same
+% stixtwo % only / extensible, 2044 useless
+% lucida % both extensible, 2044 looks bad and more slope
+
+Unfortunately this sort of mess also results in a mess in fonts. For instance
+when we checked out the difference between \type {U+002F} and \type {U+2044} we
+found that in the fonts produced by the \TEX Gyre project both have proper
+dimensions (and look the same), so they can be used stand alone, but also as
+delimiters. In Cambria the dimensions are okay but only \type {U+2044} has
+extensible characters. In \CONTEXT\ we have defined \type {\slash} to use that slot but
+when you test Lucida and \STIX2 the results are disappointing: In Lucida the
+width of \type {U+2044} makes it unusable (it looks bad anyway), and in \STIX2 it
+is a bit wider so in the end it even becomes fuzzy what to recommend as fix:
+quarter width, half width or full width. Defining \type {\slash} as any of them
+gives at some point an issue so in the end we just patch the font in the goodie
+file: we make them the same and make sure they have extensible characters. After all,
+chances are slim that this will ever be fixed. In that respect a newer engine
+doesn't change the problem: we need to handle it in the macro package, but at
+least that can be done a bit more natural. \footnote {In principle, we can support
+the goodies in the generic font handler, but we think it makes no sense because it
+also relates to the way math is handled in general and supporting a wide range of
+different applications can only cripple the code, let along that agreeing on
+matters can be hard.}
+
+% \ctxlua{table.tocontext(characters.data[0x002F],"[0x002F]")}
+% \ctxlua{table.tocontext(characters.data[0x2044],"[0x2044]")}
+% \ctxlua{table.tocontext(characters.data[0x2215],"[0x2215]")}
+% \ctxlua{table.tocontext(characters.data[0x2571],"[0x2571]")}
+% \ctxlua{table.tocontext(characters.data[0x29F8],"[0x29F8]")}
+
+\stopsection
+
+\startsection[title=Bars]
+
+Again we start with the \WIKIPEDIA\ page, this time the one dedicated to bars
+[5]. The page starts with mathematics so that suggests that the (initial) author
+is familiar with usage in that field: if we cut and paste the itemized list we
+even get \TEX\ math (sort of). Examples of usage are: absolute value,
+cardinality, conditional probability, determinant, distance, divisibility,
+function evaluation, length, norm, order, restriction, set|-|builder notation,
+the Sheffer stroke in logic, subtraction, but also \quotation {A vertical bar can
+be used to separate variables from fixed parameters in a function, or in the
+notation for elliptic integrals}.
+
+Among the objectives of our exploration are grouping symbols in sets that
+represent related meanings and usage. Within these groups we can fine tune with
+classes but that is more geared at rendering. Although currently users enter
+specific usage of symbols with the same shape (or even \UNICODE) with commands we
+can imagine them entering the \quote {real} characters and in that case we need
+some automatic class assignment based on a group (or set of groups). The
+\WIKIPEDIA\ page mentions that in physics \quotation {The vertical bar is used in
+bra|–|ket notation in quantum physics}. It then goes on about usage in computing,
+phonetics and literature. This ordering is different from the slashes, but okay.
+
+The page then makes a distinction between solid and broken bars and there is some
+interesting history behind that, which relates to typewriters, terminals and
+printers in the perspective of distinction and indeed we noticed that on our
+keyboard the broken bar is still used, even if the rendering is solid. The
+page ends with the \UNICODE\ bars and entities. We mention most:
+
+\starttabulate[|T|l|l|]
+\NC U+007C \NC \switchtobodyfont[stixtwo]$\utfchar{"007C}$ \NC a single vertical line \NC \NR % |
+\NC U+00A6 \NC \switchtobodyfont[stixtwo]$\utfchar{"00A6}$ \NC a single broken line \NC \NR % ¦
+\NC U+2016 \NC \switchtobodyfont[stixtwo]$\utfchar{"2016}$ \NC a double vertical line (norms) \NC \NR % ‖
+\NC U+2223 \NC \switchtobodyfont[stixtwo]$\utfchar{"2223}$ \NC divides \NC \NR % ∣
+\NC U+2225 \NC \switchtobodyfont[stixtwo]$\utfchar{"2225}$ \NC parallel lines \NC \NR % ∥
+\NC U+2502 \NC \switchtobodyfont[stixtwo]$\utfchar{"2502}$ \NC a vertical box drawing line \NC \NR % │
+\NC U+FF5C \NC \switchtobodyfont[stixtwo]$\utfchar{"FF5C}$ \NC a fullwidth vertical line \NC \NR % |
+\stoptabulate
+
+Given the mentioned wide range of usage it will be clear bars that can be confusing
+and are pretty overloaded. We're not aware of broken bars being used in math, so
+we ignore these.
+
+The \UNICODE\ math draft talks of \quote {vertical lines} and distinguishes two
+series, delimiters:
+
+\starttabulate[|T|l|l|]
+\NC U+007C \NC \switchtobodyfont[stixtwo]$\utfchar{"007C}$ \NC single vertical lines \NC \NR
+\NC U+2016 \NC \switchtobodyfont[stixtwo]$\utfchar{"2016}$ \NC double vertical lines \NC \NR
+\NC U+2980 \NC \switchtobodyfont[stixtwo]$\utfchar{"2980}$ \NC triple vertical lines \NC \NR
+\stoptabulate
+
+and operators:
+
+\starttabulate[|T|l|l|]
+\NC U+2223 \NC \switchtobodyfont[stixtwo]$\utfchar{"2223}$ \NC divides (single line) \NC \NR
+\NC U+2225 \NC \switchtobodyfont[stixtwo]$\utfchar{"2225}$ \NC parallel (double lines) \NC \NR
+\NC U+2AF4 \NC \switchtobodyfont[stixtwo]$\utfchar{"2AF4}$ \NC binary relation (tripple lines) \NC \NR
+\NC U+2AFC \NC \switchtobodyfont[stixtwo]$\utfchar{"2AFC}$ \NC s large triplle operator \NC \NR
+\stoptabulate
+
+Watch the triples: these are not (yet) in the \WIKIPEDIA\ summary. Rightfully
+there is a remark that the official \UNICODE\ descriptions use \typ {BAR} and
+\typ {LINE} but \TEX ies can't complain about that, can they? After all, they
+also use these terms mixed.
+
+The delimiters sit at the edges but sometimes also in the middle. The operators
+are between other elements and the document states that they also should grow.
+And is it mentioned that spacing depends on usage. The large triple is an n-ary
+operator but as usual with math symbols the user (reader) has to guess what that
+actually means.
+
+It is actually unfortunate that the fences have no left, middle and right
+variant. Even if these render the same it would make life easier and consistency
+with other fences is also worth something. One wonders how it would have looked
+if accessibility demands had kicked in earlier. The \UNICODE\ \type
+{mathclass.txt} [4] provides:
+
+\starttabulate[|T|l|]
+\NC U+007C \NC fence (unpaired delimiter) \NC \NR
+\NC U+2016 \NC fence (unpaired delimiter) \NC \NR
+\NC U+2980 \NC fence (unpaired delimiter) \NC \NR
+\stoptabulate
+
+We assume that the unpaired qualification is actually an indication that usage as
+what in \TEX\ is called \quote {middle} is okay. The operators are classified as:
+
+\starttabulate[|T|l|]
+\NC U+2223 \NC relation \NC \NR
+\NC U+2225 \NC relation \NC \NR
+\NC U+2AF4 \NC binary \NC \NR
+\NC U+2AFC \NC large n-ary \NC \NR
+\stoptabulate
+
+% \ctxlua{table.tocontext(characters.data[0x007C],"[0x007C]")}
+% \ctxlua{table.tocontext(characters.data[0x00A6],"[0x00A6]")}
+% \ctxlua{table.tocontext(characters.data[0x2016],"[0x2016]")}
+% \ctxlua{table.tocontext(characters.data[0x2980],"[0x2980]")}
+% \ctxlua{table.tocontext(characters.data[0x2223],"[0x2223]")}
+% \ctxlua{table.tocontext(characters.data[0x2225],"[0x2225]")}
+% \ctxlua{table.tocontext(characters.data[0x2AF4],"[0x2AF4]")}
+% \ctxlua{table.tocontext(characters.data[0x2AFC],"[0x2AFC]")}
+
+The main problem with bars in \TEX\ is that there is no distinction between a
+left and right bar which makes it impossible to use them directly as fences. On
+can consider this to be an omission to \UNICODE\ math because shape rules over
+meaning. So anyway, this is something that a macro package has to deal with. If
+needed these can get a class on their own in which case we can define atom
+spacing rules that deal with them ending up left or right. In \UNICODE\ there are
+signals that deal with bidirectional text, so we see no reason why there shouldn't
+be similar provisions for math.
+
+\stopsection
+
+\startsection[title=Hyphens and Dashes]
+
+This section applies to text and math as both are riddled with horizontal lines:
+easy to scratch in wood, chisel in stone or draw on paper symbols. We limit
+ourselves to the straight ones, but similar observations can be made for curved
+ones.
+
+\WIKIPEDIA\ distinguishes hyphens, minus, and dashes so there are multiple pages
+dedicated to this. The page about minus mentions that there are three usages
+(somewhat rephrased):
+
+\startitemize[packed]
+ \startitem
+ It is used as subtraction operator and therefore a binary operator
+ that indicates the operation of subtraction.
+ \stopitem
+ \startitem
+ It can be function whose value for any real or complex argument is the
+ additive inverse of that argument.
+ \stopitem
+ \startitem
+ It can serve as a prefix of a numeric constant. When it is placed
+ immediately before an unsigned numeral, the combination names a negative
+ number, the additive inverse of the positive number that the numeral
+ would otherwise name.
+ \stopitem
+\stopitemize
+
+The functional variant is how content \MATHML\ sees it: you apply a minus
+operator to something, singular of multiple. We were surprised to see that there
+is a distinctive rendering suggested, something we have argued for at several
+occasions (mostly \TEX\ meetings):
+
+\startquotation
+ In many contexts, it does not matter whether the second or the third of these
+ usages is intended: \type {−5} is the same number. When it is important to
+ distinguish them, a raised minus sign \type {¯} is sometimes used for negative
+ constants, as in elementary education, the programming language \APL, and some
+ early graphing calculators.
+\stopquotation
+
+Unfortunately that distinction was not recognized by the \TEX\ community at large
+which (we guess) is why we don't see it in \UNICODE, which on the other hand has
+plenty dashes as we will see soon.
+
+The page mentions usage in indicating blood types and music, which is a nice
+detail. It also mentions usage in computing, including regular expressions and in
+physics and chemistry indicating charge. It lists these codes for minus symbols:
+
+\starttabulate[|Tl|l|]
+\NC U+002D \NC hyphen minus \NC \NR
+\NC U+2212 \NC minus \NC \NR
+\NC U+FE63 \NC small hyphen minus \NC \NR
+\NC U+FF0D \NC full width hyphen minus \NC \NR
+\stoptabulate
+
+The page also mentions the commercial minus \type {⁒} (see also [7]) and division
+sign \type {÷} (see also [8]) and we think these should be supported in math mode
+simply because they can be part of (even simple text style) formulas.
+
+The fact that we use the hyphen as minus and expect it to render as a wider dash
+like shape is something that related to math mode in \TEX\ speak. In text mode we
+expect it to be seen as hyphenation related indicator. We won't go into details
+about automated hyphenation and explicit hyphens in text mode but here are the
+hyphens as mentioned on the hyphen specific \WIKIPEDIA\ page:
+
+\starttabulate[|Tl|l|]
+\NC U+002D \NC hyphen minus \NC \NR
+\NC U+00AD \NC soft hyphen \NC \NR
+\NC U+2010 \NC hyphen \NC \NR
+\NC U+2011 \NC non breaking hyphen \NC \NR
+\stoptabulate
+
+You might wonder why we mention text variants here and one reason is that we
+actually might need to provide a catch for the last two: maybe when a user copies
+these from a document (when rendered at all) we need to treat them as the simple
+hyphen minus and just remap them to the math minus when in math mode. Below, we
+will discuss dashes, and although these are also meant for text, a reason for
+exploring these can be found in the fact that \TEX\ users like to decorate the
+content in unexpected ways and lines (or rules) fit into that. The \WIKIPEDIA\
+pages go into some details about the hyphens being used in compounds and there
+can be some confusion about whether to use endashes or hyphens for that. We're
+pretty sure that typesetting wars have been fought over that. Usage as pre- and
+suffixes definitely is worth noting (and we use them as such in this sentence).
+
+We leave out all the other usages and see what there is to tell about related
+symbols. The \WIKIPEDIA\ page about dashes is an extensive one. It starts out with
+the distinction between \unichar {figure dash} {2012}, \unichar {endash} {2013},
+\unichar {emdash} {2014} and \unichar {horizontal bar} {2015}. Of these a \TEX ie
+will for sure recognize the endash and emdash. The hyphen is not a dash but if
+you look at \TEX\ input that double or triple hyphens get ligatured into en- and
+emdashes! The only certainty one has is that the endash is often half the width
+of an emdash. Also, the width of the emdash is often the same as the font size.
+
+One reason why a language subsystem of a \TEX\ macro package is complex is that
+it has to deal with cultural aspects and the usage as well as spacing around all
+these dashes can differ. When trying to support that a macro writer soon finds
+out that one user of language~X can tell you the rules are done this way, and a
+while later you get a mail from another user who claims that in language~X the
+rules are done that way. Word processing and dominance of English probably adds
+to the confusion. The same is true for quotes, but math doesn't need these, so we
+skip them. Now wait, you will say: does math use these dashes? Users probably
+will mix them in but more important is that the width of these dashes also has
+associated skips: \type {\enspace} and \type {\emspace} or \type {\quad} and
+these one definitely see users mix into math.
+
+The figure dash has the same width as digits which makes them useful in tables. In
+the fonts that come with \TEX\ it is the reverse: the digits have the same width
+and that width matches the endash. There is no habit of using the figuredash, but
+we might need to change that. After all, we now have the fonts! We do need to
+deal with the figure dash because users might mix math and text in tables, and
+although you can find plenty of badly typeset by \TEX\ tables, this is no excuse
+for using a mix of minus and figure dash in inconsistent ways.
+
+The \WIKIPEDIA\ page mentions the usage of the endash: as connector, as compound
+hyphen, and as sentence interrupter. Now the one that needs some attention is the
+second one. In Dutch, we can combine words in many ways and for educational
+purposes adding a compound dash makes sense. However, because the weight of the
+hyphen and endash in \TEX\ fonts is rather incompatible, in \CONTEXT\ we use(d)
+fakes: two overlapping hyphens. Another complication is that one has to wrap that
+in a discretionary node in order to make the hyphenator happy, but that is now
+delegated to the engine that can be configured to see certain characters as valid
+hyphenation points. Although we support discretionaries in math this doesn't
+relate to dashes but to pluses and minuses and such. The engine supports explicit
+discretionaries but can also automatically repeat symbols that are set up as
+repeatable across lines. We're not sure if users actually use en- and emdashes in
+math mode, but one can occasionally run into examples (on the web) where special
+effects are achieved in curious ways. \footnote {The math stream doesn't go
+through the font handler although embedded \type {\hbox}es get that treatment.
+This means that two hyphens in a row are just two atoms and not get collapsed to
+an endash.}
+
+It is worth pointing out that \WIKIPEDIA\ discusses \quotation {Ranges of values}
+and this is something we need to investigate in the perspective of math! Strictly
+spoken that is a text thing, but \unknown\ Among the many observed and suggested
+patterns we note that among \TEX ies using the endash as itemize symbols is
+also popular.
+
+Usage of the emdash is related to the use of parenthesis or colons, so it is more
+a kind of punctuation. It can also be used as an interrupt and again it is a
+candidate for an itemize symbol. There is of course a \TEX\ thing there: lack of
+text symbols made for a rather mixed usage of math and text symbols in
+itemizations. For instance a dotted one uses the well visible math dot instead of
+the often hardly visible text dot that simply was not present in \TEX\ fonts, so
+our eyes got accustomed to the bolder ones. It is one of the reasons why a \TEX\
+macro package load a math font even when no math is used. Over the years in \TEX\
+math and text symbols have been mixed in various ways, also a side effect if the
+limited amount of characters in text fonts and the abundance of them in math
+mode, even if most are only accessible by name. We need to deal with that
+historic mix.
+
+The page rightfully mentions that \TEX\ has no horizontal bar, also known as
+\quote {quotation dash}, used for dialogues in some languages. We should make a
+note then that it might be good to see if we have to reconfigure the
+sub|-|sentence presets to match that expectation. The proposed hack {\red MPS:
+where?} for a missing symbol is somewhat curious:
+
+\starttyping
+x \hbox{---}\kern-.5em--- x
+\stoptyping
+
+\startbuffer[dash-example]
+\uleaders \hbox to 1.5em {---\hskip 0pt minus .5em---} \hskip.125em minus .125em \relax
+\stopbuffer
+
+Why not \type {\hbox {---\kern-.5em---}} or just \type {---\kern-.5em---} to get
+the same effect? This also assumes that the font collapses these three hyphens
+into a dash, then it backtracks the symbol width and does a second one.
+\footnote {Here is some food for thought: for this kind of usage one can argue
+that such a dash should have some stretch. In \LUAMETATEX\ and therefore
+\CONTEXT\ we can do this: \typeinlinebuffer [dash-example] and get: \dorecurse
+{30} {x \getbuffer [dash-example] x}. Boxed material can be stretched and be
+taken into account when creating paragraphs. It is no big deal to wrap that in a
+macro, say \type {\figuredashed}.} Anyway, where figure dashes are related to
+minuses we can probably ignore this super minus resembling horizontal bar.
+\footnote {We can actually issue a warning when it is used in math mode.}
+
+The \WIKIPEDIA\ page ends with a summary of all kind of dashes, including
+underscores, script specific symbols, accents (like macron), modifiers and curly
+ones. Here we only mention the ones that can end up in some source when one cuts
+and pastes. Doing that can result in missing characters (because not all fonts
+provides them) or a change in meaning (for as far as the symbols relates to an
+intention). We show some that fit into this discussion and also mention the
+\UNICODE\ description:
+
+\starttabulate[|T|lb{\ttx}|p|]
+\NC U+002D \NC HYPHEN-MINUS \NC the usual hyphen but also used as minus \NC \NR
+\NC U+005F \NC LOW LINE \NC aka underscore \NC \NR
+\NC U+00AD \NC SOFT HYPHEN \NC valid hyphenation point (invisible) \NC \NR
+\NC U+2010 \NC HYPHEN \NC the real hyphen but more work on a keyboard \NC \NR
+\NC U+2011 \NC NON-BREAKING HYPHEN \NC a hard hyphen, disables following hyphenation \NC \NR
+\NC U+2012 \NC FIGURE DASH \NC see discussion above \NC \NR
+\NC U+2013 \NC EN DASH \NC see discussion above \NC \NR
+\NC U+2014 \NC EM DASH \NC see discussion above \NC \NR
+\NC U+2015 \NC HORIZONTAL BAR \NC see discussion above \NC \NR
+\NC U+2043 \NC HYPHEN BULLET \NC used in itemized lists \NC \NR
+\NC U+207B \NC SUPERSCRIPT MINUS \NC combined with pre-superscripted characters \NC \NR
+\NC U+208B \NC SUBSCRIPT MINUS \NC combined with pre-subscripted characters \NC \NR
+\NC U+2212 \NC MINUS SIGN \NC the math minus (rendering of hyphen) \NC \NR
+\NC U+23AF \NC HORIZONTAL LINE EXTENSION \NC build long connected horizontal lines \NC \NR
+\NC U+23E4 \NC STRAIGHTNESS \NC represents line straightness in technical context \NC \NR
+\NC U+2500 \NC BOX DRAWINGS LIGHT HORIZONTAL \NC part of the box-drawing repertoire \NC \NR
+\NC U+2796 \NC HEAVY MINUS SIGN \NC a visual variant with no meaning \NC \NR
+\NC U+2E3A \NC TWO-EM DASH \NC a visual variant with no meaning \NC \NR
+\NC U+2E3B \NC THREE-EM DASH \NC a visual variant with no meaning \NC \NR
+\NC U+FE58 \NC SMALL EM DASH \NC a visual variant with no meaning \NC \NR
+\NC U+FE63 \NC SMALL HYPHEN-MINUS \NC a visual variant with no meaning \NC \NR
+\NC U+FF0D \NC FULLWIDTH HYPHEN-MINUS \NC a visual variant with no meaning \NC \NR
+\stoptabulate
+
+The \UNICODE\ math draft only mentions the hyphen: \footnote {When I copy this
+snippet into the document source there are \typ {START OF TEXT} symbols at the
+places where a hyphenation occurs, which is probably a side effect of a bad \type
+{TOUNICODE} entry in the \PDF\ file, but it is kind of interesting in this
+perspective as definitely a hyphen is rendered.}
+
+\startquotation
+ Minus sign. \type {U+2212} [or] \type{−} [known as] \typ {MINUS SIGN} is the
+ preferred representation of the unary and binary minus sign rather than the
+ \ASCII|-|derived \type {U+002D} [or] \type {-} [known as] \typ
+ {HYPHEN-MINUS}, because minus sign is unambiguous and because it is rendered
+ with a more desirable length, usually longer than a hyphen.
+\stopquotation
+
+and elsewhere we can read:
+
+\startquotation
+ The \ASCII\ hyphen minus \type {U+002D} [or] \type {-} is a weakly
+ mathematical character that may be used for the subtraction operator, but
+ \type {U+2212} [or] \type {−} [known as] \typ {MINUS SIGN} is preferred for
+ this purpose and looks better.
+\stopquotation
+
+We are not aware of the concept of weak mathematical characters, so we will not
+take that property too serious when we try to improve the rendering.
+
+This is basically it. There is no mentioning of classes (after all, traditional
+\TEX\ has no unary class) so it is assumed that the renderer does the right
+thing: interpreting the sequence of characters and apply spacing accordingly.
+There are users who like to see a unary minus being rendered differently, just as
+the minus that a student is supposed to key in a calculator and while the
+\WIKIPEDIA\ page mentions this explicitly, it is ignored here. Yes, having two
+distinctive slots for this would have been great. Maybe it is not seen as
+relevant enough by the community that would benefit most, but who knows what had
+happened it the \WIKIPEDIA\ page had been there before!
+
+The minus is mentioned in the somewhat curious section about how shapes should be
+positioned relative to the baseline, where the position of the minus relates to
+what in \TEX\ speak is the math axis. There is also some mentioning of non-mathematical use, like:
+
+\startquotation
+ The concept of mathematical use is deliberately kept broad; therefore the
+ Math property is also given to characters that are used as operators, but are
+ not part of standard mathematical notation, such as \type {U+2052} \typ
+ {COMMERCIAL MINUS}.
+\stopquotation
+
+There should be no confusion with the \typ {SET MINUS} which renders as a
+backslash, a \typ {(NEG\-ATED) MINUS TILDE} or \typ {(NEG\-ATED) SIMILAR MINUS
+SIMILAR} that look more like relations. {\red MPS: overfull hbox, and do you
+intend to hyphenate?}
+
+The \MATHML\ document recognizes the minus as being unary or binary. In content
+\MATHML\ it is easy: when applied to a single atom it is a unary. In presentation
+\MATHML\ minus is an operator that sits at the front of a row (unary) or in the
+middle (binary). Keep in mind that we are limited to \type {mn} for numbers,
+\type {mi} for alphabetic symbols and \type {mo} for operators, not to be
+confused with \TEX's math operators, because in \MATHML\ relations are also
+operators. One can wonder about a minus in \type {mn} elements.
+
+So to summarize: we definitely need to make sure that (whatever renders as)
+hyphens is dealt with in math as minus. We can wonder what to do with
+(especially) en- and emdashes and the other horizontal lines that actually might
+show up as (what we call) middle delimiters in mathematical constructs: if it's
+there, \TEX ies will use it! The lack of specific symbols for unary minus has to
+be compensated at the macro package level.
+
+% \ctxlua{table.tocontext(characters.data[0x002D],"[0x002D]")}
+% \ctxlua{table.tocontext(characters.data[0x2010],"[0x2010]")}
+% \ctxlua{table.tocontext(characters.data[0x2011],"[0x2011]")}
+% \ctxlua{table.tocontext(characters.data[0x2212],"[0x2212]")}
+% \ctxlua{table.tocontext(characters.data[0x2212],"[0x2213]")}
+% \ctxlua{table.tocontext(characters.data[0x2212],"[0x2214]")}
+% \ctxlua{table.tocontext(characters.data[0x2212],"[0x2215]")}
+% \ctxlua{table.tocontext(characters.data[0xFE63],"[0xFE63]")}
+% \ctxlua{table.tocontext(characters.data[0xFF0D],"[0xFF0D]")}
+
+% U+2043 HYPHEN BULLET
+% U+207B SUPERSCRIPT MINUS
+% U+208B SUBSCRIPT MINUS
+
+\stopsection
+
+\startsection[title=Pieces]
+
+In \UNICODE\ one can find all kind of constructors, for instance characters that
+find their origin in those character sets that had lines and corners for drawing
+on a terminal. It is therefore no surprise that there are also some constructors
+that relate to math. An example demonstrates this:
+
+\startbuffer[definition]
+\def\makeweird#1#2#3#4%
+ {\vcenter\bgroup
+ \offinterlineskip
+ \hbox{$\scriptscriptstyle\char"#1$}\par
+ \hbox{$\scriptscriptstyle\char"#2$}\par
+ \hbox{$\scriptscriptstyle\char"#3$}\par
+ \hbox{$\scriptscriptstyle\char"#4$}%
+ \egroup}
+
+\def\lwA{\mathopen {\makeweird{23A7}{23A8}{23A8}{23A9}}}
+\def\rwA{\mathclose{\makeweird{23AB}{23AC}{23AC}{23AD}}}
+\def\lwB{\mathopen {\makeweird{23A7}{23AC}{23AC}{23A9}}}
+\def\rwB{\mathclose{\makeweird{23AB}{23A8}{23A8}{23AD}}}
+\def\lwC{\mathopen {\makeweird{23A7}{23AC}{23A8}{23A9}}}
+\def\rwC{\mathclose{\makeweird{23AB}{23A8}{23AC}{23AD}}}
+\stopbuffer
+
+\startbuffer[demo]
+$\lwA x + 4 + \lwB x^2 + 4^2 + \lwC x^3 + 4^3 \rwC \rwB \rwA$
+\stopbuffer
+
+\typebuffer[definition,demo]
+
+This renders as:
+
+\startlinecorrection
+\getbuffer[definition]
+\scale[width=\textwidth]{\getbuffer[demo]}
+\stoplinecorrection
+
+So, we have official \UNICODE\ characters for constructing large fences. In the
+\UNICODE\ math documents there is some mentioning of this and interesting is that
+there are suggested compositions expressed in 2, 3, 5 etc. stacked \quote {lines}
+which makes one wonder how math is perceived (or supposed to be rendered). But
+what is really weird is that there are plenty of arrows but no snippets defined that
+can be used to create extended ones. Why vertical snippets and no horizontal
+ones? This is clearly an omission and the \TEX\ community did take care of this
+need. So, for horizontal arrows and alike one expects the font to handle it and
+for fences not?
+
+It is not only fences that have snippets, we also find them for integrals. But
+for vertical arrows they are lacking: that is completely up to the font. Now, for
+us that is fine, but again, for consistency they could have been there. It would
+make it possible to filter bits and pieces from fonts using official slots
+instead of private ones. So, to some extent we can best assume there is nothing
+like that and ignore whatever pieces are in \UNICODE\ anyway (like the braces in
+the example). One can even argue that because of this inconsistency a font
+designed can as well only use private slots and not provide snippets at all.
+
+So, how do we get out of this situation? Because no one cared getting it in
+\UNICODE, we can do as we like. Of course, we can define arrow fillers as has
+always been done in \TEX, but because in \LUAMETATEX\ we have a bit more in our
+toolkit, and because we want to support stretch fractions (where the rule is
+replaced by a horizontal delimiter) it was decided to define a tweak that deals
+with this: when the basic arrows have no horizontal parts defined, we just
+assemble them. For those arrows that have a hook or so at the other end, we use
+the space as extender. \footnote {Actually we no longer do that because the
+engine will center the arrow anyway when it's too short.} If we ever end up with
+proper snippets un \UNICODE\ then we also need adapted fonts, and then we can get
+rid of these hacks. That said: because all decent math fonts do have the three
+pairs or fences (brace, parenthesis, bracket) the vertical snippets are rather
+useless, unless one wants to construct assembled weird ones. This would be
+different for horizontal assemblies, because there is more variety in them.
+
+The official name for all related to characters that can stretch is \quote
+{delimiter}. In traditional \TEX\ one can define a command that becomes a
+character. In that case a family, class and slot is assigned. You can also
+directly access a character in which case one will assign these properties
+otherwise (no command is defined). The same is true for these delimiters.
+However, in traditional \TEX\ the larger character usually comes from a so called
+extension font and uses family~3). In \OPENTYPE\ fonts we have all in one font so
+there the large family, class, and slot are not used.
+
+An interesting side effect of the updated math machinery in \LUAMETATEX\ is that
+we no longer really need delimiter specifications when we use \OPENTYPE\ fonts.
+This is because in practice the only two classes that really matter are the open
+and close ones. There are basically two kinds of delimiters: fences and
+singulars. Fences need open and close and only bars have a dual character. So,
+when we don't define it as delimiter, the engine can still use that character and
+take its assigned class when used stand|-|alone, while in the case of fences
+these themselves are of class open and close. And, for instance a left brace can
+get class open because when used stand alone it is an unscaled left fence. In the
+rare case that one really need a different class we are using commands: some
+characters can be binary, ordinary or whatever so then commands relate a name to
+a class|-|character combination. Actually, in \CONTEXT\ we will switch to using
+dictionaries and field specific rendering instead, but that is a different story.
+We can illustrate the arrows with an example:
+
+\startbuffer
+$ x +
+ \left\downarrow a \uparrow \frac{1}{b} \downarrow c \right\uparrow
+= y $
+\stopbuffer
+
+\typebuffer
+
+The stand alone arrows are defines with class relation but when used as fences
+their spacing is driven by the fences themselves.
+
+\startlinecorrection
+\scale[width=\textwidth]{\showmakeup[mathglue]\mathspacingmode1\showglyphs\getbuffer}
+\stoplinecorrection
+
+This means that in \CONTEXT\ \LMTX\ we no longer have delimiter code definitions.
+Of course the engine has to be able to use math characters of any kind (by
+commands, direct or as \UTF) as delimiters, but that was not that hard to
+provide. It also simplifies the code we use for fencing as it can be less
+selective.
+
+Another interesting side effect of once again looking into these stretched
+characters is that the fraction mechanism that already was extended with skewed
+fractions, now supports any stretchable character as alternative for a fraction
+rule.
+
+\startbuffer
+$
+ p \leftarrowtext {a + b + c + d}{x + y} q
+ \quad
+ p \frac {a + b + c + d}{x + y} q
+$
+\stopbuffer
+
+\typebuffer
+
+Watch the difference in spacing: here the class of the used delimiter determines the
+spacing around the (pseudo) fraction:
+
+\startlinecorrection
+\scale[width=\textwidth]{\showmakeup[mathglue]\mathspacingmode1\showglyphs\getbuffer}
+\stoplinecorrection
+
+Again this simplifies some code because normally one ends up with stacking stuff
+using leaders in between.
+
+\stopsection
+
+\startsection[title=Accents]
+
+When we talk about accents, we refer to tiny symbols that anchor themselves onto
+base characters. We limit ourselves to the ones common in Latin scripts because
+they are the ones used in math. Accents in \UNICODE\ are somewhat special. In
+the past, when encoding vectors were limited, accents were entered as part of an
+input sequence and then anchored by the renderer. Nowadays often pre|-|composed
+characters are used. A very cheap way of anchoring is to have accents that just
+overlay, and in practice centering an accent over a base character works sort of
+okay. As an example of an accent we will use the hat:
+
+\starttabulate[|T|c|l|c|]
+\NC U+005E \NC x\char"005E x m\char"005E m\NC \tex {Hat} \NC \im{x \char"005E x + m\char"005E m} \NC \NR % 94
+\NC U+02C6 \NC x\char"02C6 x m\char"02C6 m\NC \tex {hat} \NC \im{x \char"02C6 x + m\char"02C6 m} \NC \NR % 710
+\NC U+0302 \NC x\char"0302 x m\char"0302 m\NC \tex {widehat} \NC \im{x \char"0302 x + m\char"0302 m} \NC \NR % 770
+\stoptabulate
+
+Normally the font handler will take care of anchoring \type {U+0302}, but it can
+only be done properly when there are anchors defined for what are called \quote
+{marks}: the official feature description is mark|-|to|-|base (or simply \type
+{mark}). The last column in the above table shows math and as we input a raw
+character we don't get proper anchoring: the zero width makes it overlap.
+
+% till here
+
+Now wait, you will say, but why does it actually overlap? The reason is that zero
+width is not actually zero width here! The glyph has a bounding box that goes
+into the negative horizontal direction and therefore, when such a shape gets
+injected into the output, the rendering in the viewer will move the left edge to
+the left. But because the \TEX\ engine only handles positive widths and because
+the width is explicitly part of a character specification anyway\footnote {The
+height and depth are not: these we derive from the bounding box.} we don't
+progress (advance) which is why the overlapping sort of works for the $x$ but
+less so for the $m$: in math mode we need to use these \type {\hat} and \type
+{\widehat} commands.
+
+The hat and widehat assignments were those of August 2022. In plain \TEX\ we see
+these definitions:
+
+\starttyping
+\def\hat {\mathaccent"705E }
+\def\widehat{\mathaccent"0362 }
+\stoptyping
+
+The \type {\mathaccent} primitive takes an integer that encodes the class, family,
+and slot in the 8 bit font encoding. Here we see that the hat comes from family
+0, the upright math font. The widehat comes from extensible family 3. These two
+are independently defined. When you want a hat that spans the nucleus, you need to
+use the widehat. In the math engine spanning actually means that we have a
+delimiter and normally that means: start with a basic shape, when that is too
+narrow, go to the extensible font and follow the chain with increasing sizes and
+when you run out of those apply an extensible recipe. The sequence and extensible
+are both optional and the important part is that we first look at what is called
+the small character and then to the large one(s).
+
+However, the \type {\mathaccent} primitives doesn't take a delimiter! It directly
+starts following a chain if the given character has it (and then the character
+itself is of course the first in that chain). And this is where the problems
+start when we move to \OPENTYPE\ and \UNICODE\ math.
+
+\starttabulate[|T|l|l|]
+\NC U+005E \NC Hat \NC some useless, often ugly large glyph \NC \NR % 94
+\NC U+02C6 \NC hat \NC it has width but no extensibles \NC \NR % 710
+\NC U+0302 \NC widehat \NC it has zero width and extensibles \NC \NR % 770
+\stoptabulate
+
+Now, if we define \type {\hat} as \type {U+02C6} we don't get the extensibles,
+and it basically is what was always done in \TEX\ macro packages following the
+plain suggestions. If we define \type {\widehat} we start out with a glyph that
+has likely zero width\footnote {Over the many years that \LUATEX\ evolved this
+was not guaranteed, for instance when wide (\UNICODE) fonts were constructed from
+traditional eight bit (\TEX\ encoded) fonts.} And, because \OPENTYPE\ starts with
+the base glyph and {\em then} uses a set of variants of eventually a recipe of
+parts, we suddenly have a different situation with \type {\mathaccent} than we
+normally have, where these are decoupled. Therefore, the definition of \type {\hat}
+and \type {\widehat} determines what an \OPENTYPE\ math engine will do, just as
+in regular \TEX, but we might need them to be defined differently.
+
+A solution would be to let \type {\mathaccent} (or \type {\Umathaccent}) directly
+go to the variants, but that is sort of weird. Because a zero width glyph doesn't
+match the criteria to span a nucleus it is likely to be skipped anyway, although
+there can be a case where the next in size overruns the width of the nucleus in
+which case the zero width one is used which itself is not that nice. We could
+actually derive the width from the boundingbox, but that would be a bit abnormal,
+and it makes no sense to burden the font machinery with that exception. Another
+approach we can follow is to just copy the extensibles from \type {U+0302} to
+\type {02C6} and use that one for \type {\hat} as well as \type {\widehat} and
+then make \type {\widehat} an alias to \type {\hat}. After, all, the main reason
+why we have two commands comes from the fact that \type {\mathaccent} doesn't
+take a delimiter but single character reference (encoded in an integer).
+
+Here is the whole list of accents:
+
+\starttabulate[||T||T|]
+\NC \tex{grave} \NC U+0060 \NC \tex{widegrave} \NC U+0300 \NC \NR
+\NC \tex{ddot} \NC U+00A8 \NC \tex{wideddot} \NC U+0308 \NC \NR
+\NC \tex{bar} \NC U+00AF \NC \tex{widebar} \NC U+0304 \NC \NR
+\NC \tex{acute} \NC U+00B4 \NC \tex{wideacute} \NC U+0301 \NC \NR
+\NC \tex{hat} \NC U+02C6 \NC \tex{widehat} \NC U+0302 \NC \NR
+\NC \tex{check} \NC U+02C7 \NC \tex{widecheck} \NC U+030C \NC \NR
+\NC \tex{breve} \NC U+02D8 \NC \tex{widebreve} \NC U+0306 \NC \NR
+\NC \tex{dot} \NC U+02D9 \NC \tex{widedot} \NC U+0307 \NC \NR
+\NC \tex{ring} \NC U+02DA \NC \tex{widering} \NC U+030A \NC \NR
+\NC \tex{tilde} \NC U+02DC \NC \tex{widetilde} \NC U+0303 \NC \NR
+\NC \tex{dddot} \NC U+20DB \NC \tex{widedddot} \NC U+20DB \NC \NR
+\stoptabulate
+
+The only accent that is an exception is the last one but is it really used? It
+anyway makes no real sense to assume that users will ever directly input the
+\UTF\ characters conforming the last column, so we can just go for the first one
+and use the extensibles from the second and see where we end up. Neither \MATHML\
+nor \TEX\ related specifications seem to cover this well, so we can just do what
+suits us best.
+
+\startbuffer
+\showglyphs
+\im {\widehat{a} + \widehat {aa}} =
+\im {\hat {a} + \hat {aa}} =
+\im {\hat {a} + \hat[stretch=yes]{aa}} =
+\setupmathaccent[top][stretch=yes]
+\im {\hat {a} + \hat {aa}}
+\stopbuffer
+
+Because all has to fit into the \CONTEXT\ user interface and because we also want
+to be backward compatible (command wise), we end up with something:
+
+\typebuffer
+
+that gives us:
+
+\startpacked \glyphscale = \numexpr2*\glyphscale\relax \getbuffer \stoppacked
+
+Now, one problem, is of course that users can enter these modifiers as \UTF\
+sequence in the input, just like they do with delimiters. Therefore we do support
+the following feature (which is under class control so disabled by default):
+
+\startbuffer
+\Umathcode "02C6 \mathaccentcode 0 "02C6
+\edef \HiHatA {\Uchar"02C6}
+\Umathchardef \HiHatB \mathaccentcode 0 "02C6
+
+$ \Uchar"02C6{x} + \HiHatA{xx} + \HiHatB{xx} = \widehat {xxxx} $
+\stopbuffer
+
+\typebuffer
+
+You get this:
+
+\start
+ \pushoverloadmode \getbuffer \popoverloadmode
+\stop
+
+The only cheat here is that normally accents come after the accentee, but we can
+live with that. After all, it's all about convenience.
+
+There is another aspect of accents that we need to mention here. The hat, tilde,
+and check are often used over not only single letters but also small expressions.
+So how come that fonts have only very few variants defined? We can imagine that
+in eight bit fonts the number of available slots plays a role but in \OPENTYPE\
+fonts that is not the case. It therefore can be considered an
+oversight that usage of these wide accents has not be communicated well to the
+font designers.
+
+\def\CrappyHack#1{\im{
+ #1{a} + #1{a+b} + #1{a+b+c} +
+ #1{a+b+c+d} + #1{a+b+c+d+e} + #1{a+b+c+d+e+f}
+}\par}
+
+\startpacked
+\CrappyHack\widehat
+\CrappyHack\widetilde
+\CrappyHack\widecheck
+\stoppacked
+
+The previous lines demonstrate that we can actually cheat a little for these
+three top accents: we can just scale the last variant horizontally. It was a few
+lines patch to \LUAMETATEX\ to make this automatic and triggered by setting the
+\type {extensible} field in a character table to \type {true} instead of a
+recipe. The ingredients to get this working were already there, and it works out
+quite well. The only complication was that the \type {flac} feature (that
+provides flat accents for cases where the nucleus is rather high) could interfere,
+but that was trivial to deal with in the code that does the goodies. \footnote
+{When we were testing fonts this got us by surprise when we tested Cambria that
+has these flat overloads for the tilde and check. Because supports this automatic
+(hidden from the user) one doesn't look into that direction when testing
+something.}
+
+When it comes to these delimiters that have no real solution in the font, we can
+consider delegating coming up with a glyph to the macro package at the time it is
+needed, and we can actually do that. However, this is mostly interesting for
+educational usage, where the amount of delimiters is predictable and limited.
+About a decade ago some mechanism was added to the \MKIV\ math machinery that
+support plugins so that we could use \METAFUN\ to generate (most noticeably)
+square root symbols the way we liked. \footnote {This was a fun project of Alan
+and Hans.} The main drawback is that mixing this in means matching to a font, and
+that is not always trivial. But it is this kind of trickery that makes working
+with \TEX\ fun. That said: what we are discussing here is more fundamental in the
+sense that we try to come up with generic engine solutions that just rely on the
+fonts. That way complex math with all reasonable symbols is also served.
+\footnote {These \METAFUN\ plugins are still possible, but we need to adapt some
+to \LMTX\ which will happen as we go.}
+
+Interestingly there are some arrows that act like accents. There are over- and
+under ones as well as combining (often zero width) accents. Fonts are not always
+consistent in how these extends (the wide ones). Often the combining accents are
+smaller and closer to the running text. Traditionally in \TEX\ fonts there are no
+extensible arrows: they are constructed from arrow heads, minus and equal signs
+with some negative spacing in between. One can therefore wonder is the smaller
+combining ones are appreciated by those who want stable math. It definitely means
+that we have to make choices. Even more interesting is that while \UNICODE\ has
+some means to construct braces from predictable \UNICODE\ slots. there is no way
+to do the same with arrows and (indeed) there are fonts out there with shaped
+arrows that demand different middle and end pieces. In fact, the same is true for
+rules that are not simple rectangles and radical extensions that are not flat
+rules either. In all these cases the usage patterns of accents and similar
+constructs has not really been fed back into the way \UNICODE\ and \OPENTYPE\
+fonts support math. \footnote {One can argue that this is not what \UNICODE\ is
+for but if so, then some other bits and pieces also make little sense.}
+
+\stopsection
+
+\startsection[title=Bullets]
+
+In \TEX\ usage bullets are a it special. Because fonts had a limited number of slots
+available, bullets in for instance itemized lists traditionally were taken from
+a math font. The bullet in Computer Modern has a comfortable size and is quite
+useful for that. Bullets in text fonts often were (are) relatively small so even when
+they were available they were not really used. The official \UNICODE\ slot for
+bullet is \type {U+2022} and in this font it shows up as \quote {•}. The \WIKIPEDIA\ page
+on bullets (typography) mentions:
+
+\startquotation
+ A variant, the bullet operator (\type {U+2219} ∙ \typ {BULLET OPERATOR}) is
+ used as a math symbol, akin to the dot operator. Specifically, in logic, $x •
+ y$ means logical conjunction. It is the same as saying \quotation {x and y}
+\stopquotation
+
+The page also mentions that \quotation {glyphs such as {\switchtobodyfont
+[stixtwo]$•$} and {\switchtobodyfont [stixtwo]$◦$}} have \quotation {reversed
+variants {\switchtobodyfont [stixtwo]$◘$} and {\switchtobodyfont [stixtwo]$◙$}}
+although we haven't see the reverse once in \TEX\ documents (yet), like these (we
+use \STIX2\ to show them):
+
+\starttabulate[|Tl|l|l|]
+\NC U+2022 \NC \switchtobodyfont[stixtwo]$•$ \NC BULLET \NC \NR
+\NC U+2023 \NC \switchtobodyfont[stixtwo]$‣$ \NC TRIANGULAR BULLET \NC \NR
+\NC U+2043 \NC \switchtobodyfont[stixtwo]$⁃$\NC HYPHEN BULLET \NC \NR
+\NC U+204C \NC \switchtobodyfont[stixtwo]$⁌$\NC LACK LEFTWARDS BULLET \NC \NR
+\NC U+204D \NC \switchtobodyfont[stixtwo]$⁍$\NC LACK RIGHTWARDS BULLET \NC \NR
+\NC U+2219 \NC \switchtobodyfont[stixtwo]$∙$ \NC BULLET OPERATOR (math) \NC \NR
+\NC U+25CB \NC \switchtobodyfont[stixtwo]$○$ \NC WHITE CIRCLE \NC \NR
+\NC U+25CF \NC \switchtobodyfont[stixtwo]$●$ \NC BLACK CIRCLE \NC \NR
+\NC U+25D8 \NC \switchtobodyfont[stixtwo]$◘$ \NC INVERSE BULLET \NC \NR
+\NC U+25E6 \NC \switchtobodyfont[stixtwo]$◦$ \NC WHITE BULLET \NC \NR
+\NC U+29BE \NC \switchtobodyfont[stixtwo]$⦾$ \NC CIRCLED WHITE BULLET \NC \NR
+\NC U+29BF \NC \switchtobodyfont[stixtwo]$⦿$ \NC CIRCLED BULLET \NC \NR
+\stoptabulate
+
+The reverse ones are not really reverse in \STIX2\ as they have bigger circles.
+There are a few more bullets mentioned but probably only because they have the
+word bullet in their description and they don't really look like bullets. Given
+the already discussed lack of granularity in some math symbols with multiple
+usage it is somewhat surprising that we have a math bullet. The weird looking
+left- and rightward bullets are kind of hard to distinguish. Let's hope that
+mathematicians don't discover these!
+
+This brings us to the more general way of looking at these bullets because among
+the popular math symbols used in text are also the triangles and (\TEX) math
+fonts came with. When we have a few commands for circular shapes like \typ
+{$\bullet \bigcirc \circ$} giving $\bullet \bigcirc \circ$ we have plenty of
+(black) triangles.
+
+For instance, we have \type {\triangledown} and \type {\bigtriangledown} and these
+have corresponding \UNICODE\ slots \type {U+25BD} and \type {U+25BF} but when
+you try these in for instance \STIX2, Pagella and Cambria you got:
+▽ + ▿, ▽ + ? and ? + ?, where the question mark indicates a missing character.
+
+It is for that reason that \type {\triangledown} and \type {\bigtriangledown} are
+both defined as using the large one. This test also demonstrated us that we
+didn't have to waste time looking up what \MATHML\ had to tell about it. A
+typeset version of that specification was never a visual highlight and missing
+glyphs only makes that worse. And, when fonts lack shapes no one uses them
+anyway.
+
+However, it makes sense to think a bit about how to deal with this properly, and
+we will likely add some checking to the goodie files for it, so that when we do
+have them, we use them. \footnote {Most practical is to add this information to
+the character database which is a bit of work}. But even then, most troublesome
+is that the size (and even positioning) of these symbols is rather inconsistent
+across math fonts, but because they are seldom used it doesn't make much sense to
+compensate for that (read: we just wait till users ask for it).
+
+% {\switchtobodyfont[stixtwo]$\char"25BD+\char"25BF$}% +\triangledown+\bigtriangledown$
+% {\switchtobodyfont[pagella]$\char"25BD+\char"25BF$}% +\triangledown+\bigtriangledown$
+% {\switchtobodyfont[cambria]$\char"25BD+\char"25BF$}% +\triangledown+\bigtriangledown$
+
+\stopsection
+
+\startsection[title=Punctuation]
+
+There are quite some punctuation symbols in \UNICODE\ but not for math where the
+main troublemakers are the period, comma, colon and semicolon. The first two can
+be used as separator in numbers, in which case we don't want any spacing, or they
+can be part of a (pseudo) sentence in a formula, or they can separate entries in
+a list (take coordinates).
+
+\starttyping
+1.1 + 1.2
+(1.1, 1.2)
+x + 1.1, x + 1.2
+\stoptyping
+
+When used as separator in a sentence, which is more likely in display math than
+in inline math, the spacing after it can be either regular (as in text) or wide.
+And the symbol can come from the math font or text (and these can actually look
+different). In \CONTEXT\ (also pre \LMTX) we have some special trickery at work
+for spacing comma's and periods but we leave that aside now. What should be noted
+is that out|-|of|-|the|-|box spaces are ignored when math is scanned so we cannot
+take that surrounding into account when dealing with spacing in the engine.
+
+Although the \UNICODE\ specification provides a classification of characters that
+includes punctuation in practice we need to deal with it ourselves. For instance,
+by default a period is not considered punctuation but a command and semi colon
+are, while a colon is a relation!
+
+Take for instance $f.$ (math italic f followed by a period). Italic correction
+and math glyphs have this special relationship and it also shows up in
+punctuation. Imagine that we have a sequence of characters, say $fx$. These are
+actually two ordinary atoms but in $f,$ we have an ordinary atom followed by a
+punctuation atom so here spacing is determined by how these classes are set up.
+But, given the shape if the $f$ we actually don't want italic correction here.
+
+\startbuffer
+$fx + f. +f, + f: + f; + a. +a, + a: + a; + x, +x, + x: + x;$%
+\stopbuffer
+
+\startlinecorrection
+\scale[width=\textwidth]{%
+ \getbuffer
+}
+\blank[halfline]
+\scale[width=\textwidth]{%
+ \showmakeup[mathglue]%
+ \mathspacingmode\plusone
+ \showfontitalics
+ \showfontkerns
+ \showglyphs
+ \getbuffer
+}
+\stoplinecorrection
+
+When you zoom in you can see the subtle spacing differences. We can compensate
+for the semi colon being a bit higher than the period by applying some kern,
+something that we can set up in the goodie file.
+
+Actually, if we assume that periods only occur in numbers we can make it
+punctuation and set it up for digit spacing but then commas etc also get done
+that way. A variant is to have two punctuation classes (or cheat and put the
+period in the digit class). No matter what we do, no help can be expected from
+documents mentioned: it's mostly a visual thing anyway.
+
+Let's end with the visual aspect: in most fonts the two colons \type {0x003A} and
+\type {0x2236} are different: one has more distance between the periods. Which
+one? Well, that depends on the font! Latin Modern has a cramped \type {0x2236}
+while \STIX2 has a cramped \type {0x003A}. Cambria has square dots for the
+{0x003A} and round ones slightly more cramped for \type {0x2236}. Lucida goes
+extreme: it has smaller dots far apart for \type {0x2236}. If the idea is that a
+reader should get from the shape what it's about one can wonder if texts get read
+the way the author intended. Of maybe shapes don't matter. Of course a macro
+package can obscure these inconsistencies by setting the math character code of
+\type {0x003A} to \type {0x2236} but that only obscures the fact that little
+attention has been paid: what one can consider bugs became features.
+
+\stopsection
+
+\startsection[title=Special ones]
+
+There are quite some characters that really depend on a math renderer. Examples
+are wide accents, fences, and arrows. Some constructs, like fractions use rules
+and these don't come from \UNICODE\ nor fonts. A mixed case is radicals: there
+is a \UNICODE\ point and fonts can provide larger variants. Normally one steps up
+a slightly slanted version but when things get large the radical becomes an
+extensible and therefore gets an upright shape. The engine is supposed to add a
+horizontal rule at the right location. Interesting is that there is no provision
+for a right end cap. The reason probably is that \TEX, being the major renderer,
+has no combined horizontal and vertical extenders and \OPENTYPE\ doesn't have
+that either. Some properties are driven by the fonts' math parameters which sort
+of makes the radical rendering a very restricted adventure: it is supposed to be
+used for roots only, either of not with a degree anchored in the right top area.
+It looks like that degree is not really to extend much beyond the left edge of
+the symbol.
+
+In \UNICODE\ there is an actuarian character \type {U+20E7} and support in fonts
+is not that good. We do support it because we ran into in \MATHML. However, it is
+a hack. The symbol as provided by fonts is rather useless.
+
+\startbuffer
+$ \sqrt {x + 1} + \annuity{x + 1} $
+\stopbuffer
+
+\typebuffer
+
+Let's see how it renders:
+
+\startlinecorrection
+\scale[width=.5\textwidth]{\getbuffer}
+\stoplinecorrection
+
+We take the dimensions of a radical as template and when we look at the bare
+glyphs we see this:
+
+\startlinecorrection
+\scale[height=2\lineheight]{$\char"221A \enspace \char"20E7$}
+\stoplinecorrection
+
+Basically we have a right actuarian character like we have a left radical. But In
+this case the rule will go left instead of right. This is implemented on top of
+radicals so and driven by \type {\Udelimited} that takes two delimiters and
+doesn't scan for a degree. For two-sided roots (with degree) we have \type
+{\Urooted}. And like normal radicals the delimited one adapts itself to the
+content:
+
+\startbuffer
+$ \sqrt {x + \frac{1}{x}} + \annuity {x + \frac{1}{x}} $
+\stopbuffer
+
+\typebuffer
+
+So we get:
+
+\startlinecorrection
+\scale[width=.5\textwidth]{\showstruts \getbuffer}
+\stoplinecorrection
+
+For the record: in \CONTEXT\ spacing is also driven by the struts and because we
+use the radicals renderer the gap and distance parameters also apply. It might
+look spacy, but keep in mind that we want radicals to look similar when we have
+more of them in line, and we can configure all. We have also enabled the feature
+that radicals at the same level are normalized in height and depth. Here are some
+variants:
+
+\startbuffer
+$ \lannuity {x + \frac{1}{x}} +
+ \rannuity {x + \frac{1}{x}} +
+ \lrannuity {x + \frac{1}{x}} $
+\stopbuffer
+
+\typebuffer
+
+This gives:
+
+\startlinecorrection
+\scale[width=.75\textwidth]{\getbuffer}
+\stoplinecorrection
+
+So we can have a mix of left, right and both end radical like symbols that
+encompass the nucleus. We're not aware of more such characters in \UNICODE\ but
+when they show up we are prepared. Only real usage can result in some parameters
+being fine|-|tuned.
+
+\stopsection
+
+% \startsection[title=Summary]
+%
+% Here we give a summary of some of the things that added on top of \UNICODE\ and
+% \OPENTYPE\ math in order to be able to properly render these more complex atoms
+% and molecules.
+%
+% \stopsection
+
+\startsection[title=Final words]
+
+This text was written in 2022 when we were working on math, extending the goodie
+files with new tweaks, checking support in fonts and updating manuals. But, as we
+moved forward, for instance with adapting \TYPEONE\ support of Antykwa and Iwona
+to the new possibilities again we had to go back in time and figure out why
+actually things were done in certain ways. And I have to admit that we had some
+good laughs and quite some fun on seeing how strange and inconsistent the assumed
+structured and logical \TEX\ ecosystem deals with math. A wrapup like is is never
+complete and we can keep adding to it so just consider it to be a momentary
+impression.
+
+Personally I have to admit that I've always overestimated what happened outside
+the \CONTEXT\ bubble, especially given the claims made. Consistency in \UNICODE\
+math is probably not as good as is could have been and the same is true for
+\OPENTYPE\ math support, but maybe I'm naive in expecting consistency and logic
+in math related work. The mere fact that Donald Knuth pays a lot of attention to
+the math in his writing doesn't automatically translate in all \TEX ies doing the
+same. I don't claim that \CONTEXT\ is doing better but I do hope that its users
+keep going for the best outcome.
+
+\stopsection
+
+\startsection[title=Resources]
+
+\starttyping
+[1] https://en.wikipedia.org/wiki/Slash_(punctuation)
+[2] http://www.unicode.org/reports/tr25
+[3] https://www.w3.org/TR/MathML3
+[4] https://www.unicode.org/Public/math/revision-15/MathClass-15.txt
+[5] https://en.wikipedia.org/wiki/Vertical_bar
+[6] https://en.wikipedia.org/wiki/Dash
+[7] https://en.wikipedia.org/wiki/Commercial_minus_sign
+[8] https://en.wikipedia.org/wiki/Division_sign
+[9] https://en.wikipedia.org/wiki/Bullet_(typography)
+\stoptyping
+
+\stopsection
+
+% After reading the \UNICODE\ report about math I don't feel too guilty when people
+% complain about the \CONTEXT\ manuals. It is a curious mix of discussing
+% organization of symbols, rendering, usage, structure, exchange, parsing,
+% confusion, etc. and it is clearly a mix of experiences with the web, word
+% processing and \TEX\ and as such not that useable because it is just not how
+% \TEX\ works with input and fonts and how users perceive matters. But it
+% definitely helps to get an idea why we ended up with the current situation: the
+% unification of math was more a combination of what was there and not a fresh
+% start. Maybe that is not really possible anyway. If we flash forward a couple of
+% pages it will all look the same to us as stone age chiseling in stone.
+
+\stopchapter
+
+\stopcomponent
diff --git a/doc/context/sources/general/manuals/ontarget/ontarget-fairphone.tex b/doc/context/sources/general/manuals/ontarget/ontarget-fairphone.tex
new file mode 100644
index 000000000..9d29e5b7b
--- /dev/null
+++ b/doc/context/sources/general/manuals/ontarget/ontarget-fairphone.tex
@@ -0,0 +1,58 @@
+% language=us runpath=texruns:manuals/ontarget
+
+\startcomponent ontarget-fairphone
+
+\environment ontarget-style
+
+\startchapter[title={\LMTX\ on a phone}]
+
+When my FairPhone~2 started to get issues (running hot and then rebooting) and
+some spare parts became hard to get, I moved on to a FairPhone~4. We're talking
+early 2022. The specifications of that little computer, which comes with a 5 year
+warrantee and long term support are quite okay: a 1080x2340 pixel display, a
+Qualcomm SM7225 Snapdragon 750G (Octa|-|core (2x2.2 GHz Kryo 570 & 6x1.8 GHz Kryo
+570), an Adreno 619 GPU, 8GB memory. an 256GB solid state disk, the usual
+phone gadgets like audio, camera, wireless, bluetooth and gps, and an
+USB Type-C 3.0 connector with support for OTG and DisplayPort.
+
+Why do these specification matter? One reason is that in the compile farm we
+generate binaries for ARM processors and this phone has a decent one. The fast
+cores are in the same league as an over|-|clocked RaspberryPi~4 that we use in
+the compile farm for generating 32~bit binaries; the 64~bit binaries are generated
+in a virtual machine on a Mac Mini. So, in 2023, when looking at that phone, I
+wondered if we could run \LMTX\ on it. I installed the UserLand \LINUX\ stub from
+the Android Playstore and got myself an Ubuntu headless installation. After
+downloading the \LMTX\ installer indeed I could install the distribution on the
+little machine.
+
+A next step was trying to connect the phone to the display on my desk and after
+getting the right USB|-|C cable from the local computer shop I managed to get a
+bit larger terminal although Android~12 seems not able to use the whole 4K
+screen. Putting it in developers mode made it possible to enable the Android
+desktop interface in an external monitor. A bluetooth keyboard and mouse
+completed the setup. Later I tried a \LINUX\ desktop but that was quite a
+disappointment so more research is needed there.
+
+A predictable next step was to see if I could compile the \LUAMETATEX\ source
+that is part of the installation. Installing \GCC\ and \CMAKE\ was easy and indeed
+compilation went pretty well after that.
+
+A quick performance test showed that making a format, which includes generating
+the file database, initially takes 10~seconds but less that 4~seconds once files
+are cached. Processing 1000 paragraphs from the \type {tufte} sample file is done
+with a reasonable 55~pages per second. I didn't test more complex documents but
+that might happen later, when the dock that I ordered has arrived, and when I
+have a decent display setup.
+
+Given the fact that I only use a handful of applications on the laptop one can
+wonder when the moment is there that a properly dockable phone can do the job. Of
+course a disadvantage is that batteries are too small so one needs to provide
+power, but one needs a monitor, keyboard and mouse anyway. Wear and tear of the
+\SSD\ can also be an issue but when storage is plenty that should work out all
+right. Of course it also assumes a stable operating system with one's favourite
+editing platform and viewer available.
+
+\stopchapter
+
+\stopcomponent
+
diff --git a/doc/context/sources/general/manuals/ontarget/ontarget.tex b/doc/context/sources/general/manuals/ontarget/ontarget.tex
index ba79a09bd..635ca5fb8 100644
--- a/doc/context/sources/general/manuals/ontarget/ontarget.tex
+++ b/doc/context/sources/general/manuals/ontarget/ontarget.tex
@@ -25,6 +25,8 @@
\component ontarget-alsomath
\component ontarget-ridofjit
\component ontarget-gettingridof
+ \component ontarget-registers
+ \component ontarget-fairphone
\stopbodymatter
\stopdocument
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index 306f84a1c..49ae4a1bb 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -9338,7 +9338,7 @@ do -- create closure to overcome 200 locals limit
package.loaded["util-prs"] = package.loaded["util-prs"] or true
--- original size: 25542, stripped down to: 16783
+-- original size: 25716, stripped down to: 16805
if not modules then modules={} end modules ['util-prs']={
version=1.001,
@@ -9546,7 +9546,9 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols=S(symbol)
local separator=space^0*symbols*space^0
- local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
+ local value=lbrace*C((nobrace+nestedbraces)^0)
+*(rbrace*(#symbols+P(-1)))
++C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
if withaction then
local withvalue=Carg(1)*value/function(f,s) return f(s) end
pattern=spaces*withvalue*(separator*withvalue)^0
@@ -26093,8 +26095,8 @@ end -- of closure
-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
-- skipped libraries : -
--- original bytes : 1035743
--- stripped bytes : 408144
+-- original bytes : 1035917
+-- stripped bytes : 408296
-- end library merge
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
index 306f84a1c..49ae4a1bb 100644
--- a/scripts/context/stubs/mswin/mtxrun.lua
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -9338,7 +9338,7 @@ do -- create closure to overcome 200 locals limit
package.loaded["util-prs"] = package.loaded["util-prs"] or true
--- original size: 25542, stripped down to: 16783
+-- original size: 25716, stripped down to: 16805
if not modules then modules={} end modules ['util-prs']={
version=1.001,
@@ -9546,7 +9546,9 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols=S(symbol)
local separator=space^0*symbols*space^0
- local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
+ local value=lbrace*C((nobrace+nestedbraces)^0)
+*(rbrace*(#symbols+P(-1)))
++C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
if withaction then
local withvalue=Carg(1)*value/function(f,s) return f(s) end
pattern=spaces*withvalue*(separator*withvalue)^0
@@ -26093,8 +26095,8 @@ end -- of closure
-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
-- skipped libraries : -
--- original bytes : 1035743
--- stripped bytes : 408144
+-- original bytes : 1035917
+-- stripped bytes : 408296
-- end library merge
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
index 306f84a1c..49ae4a1bb 100644
--- a/scripts/context/stubs/unix/mtxrun
+++ b/scripts/context/stubs/unix/mtxrun
@@ -9338,7 +9338,7 @@ do -- create closure to overcome 200 locals limit
package.loaded["util-prs"] = package.loaded["util-prs"] or true
--- original size: 25542, stripped down to: 16783
+-- original size: 25716, stripped down to: 16805
if not modules then modules={} end modules ['util-prs']={
version=1.001,
@@ -9546,7 +9546,9 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols=S(symbol)
local separator=space^0*symbols*space^0
- local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
+ local value=lbrace*C((nobrace+nestedbraces)^0)
+*(rbrace*(#symbols+P(-1)))
++C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
if withaction then
local withvalue=Carg(1)*value/function(f,s) return f(s) end
pattern=spaces*withvalue*(separator*withvalue)^0
@@ -26093,8 +26095,8 @@ end -- of closure
-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
-- skipped libraries : -
--- original bytes : 1035743
--- stripped bytes : 408144
+-- original bytes : 1035917
+-- stripped bytes : 408296
-- end library merge
diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua
index 306f84a1c..49ae4a1bb 100644
--- a/scripts/context/stubs/win64/mtxrun.lua
+++ b/scripts/context/stubs/win64/mtxrun.lua
@@ -9338,7 +9338,7 @@ do -- create closure to overcome 200 locals limit
package.loaded["util-prs"] = package.loaded["util-prs"] or true
--- original size: 25542, stripped down to: 16783
+-- original size: 25716, stripped down to: 16805
if not modules then modules={} end modules ['util-prs']={
version=1.001,
@@ -9546,7 +9546,9 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols=S(symbol)
local separator=space^0*symbols*space^0
- local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
+ local value=lbrace*C((nobrace+nestedbraces)^0)
+*(rbrace*(#symbols+P(-1)))
++C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0)
if withaction then
local withvalue=Carg(1)*value/function(f,s) return f(s) end
pattern=spaces*withvalue*(separator*withvalue)^0
@@ -26093,8 +26095,8 @@ end -- of closure
-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
-- skipped libraries : -
--- original bytes : 1035743
--- stripped bytes : 408144
+-- original bytes : 1035917
+-- stripped bytes : 408296
-- end library merge
diff --git a/source/luametatex/build.sh b/source/luametatex/build.sh
index 56ed63497..2f5514316 100644
--- a/source/luametatex/build.sh
+++ b/source/luametatex/build.sh
@@ -15,6 +15,13 @@
# mtxrun.lua (latest version)
# context.lua (latest version)
+#NINJA=$(which ninja);
+#if (NINJA) then
+# NINJA="-G Ninja"
+#else
+ NINJA=""
+#fi
+
if [ "$1" = "mingw-64" ] || [ "$1" = "mingw64" ] || [ "$1" = "mingw" ] || [ "$1" == "--mingw64" ]
then
@@ -22,7 +29,7 @@ then
SUFFIX=".exe"
mkdir -p build/mingw-64
cd build/mingw-64
- cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64.cmake ../..
+ cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64.cmake ../..
elif [ "$1" = "mingw-32" ] || [ "$1" = "mingw32" ] || [ "$1" == "--mingw32" ]
then
@@ -31,7 +38,7 @@ then
SUFFIX=".exe"
mkdir -p build/mingw-32
cd build/mingw-32
- cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-32.cmake ../..
+ cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-32.cmake ../..
elif [ "$1" = "mingw-64-ucrt" ] || [ "$1" = "mingw64ucrt" ] || [ "$1" = "--mingw64ucrt" ] || [ "$1" = "ucrt" ] || [ "$1" = "--ucrt" ]
then
@@ -40,7 +47,7 @@ then
SUFFIX=".exe"
mkdir -p build/mingw-64-ucrt
cd build/mingw-64-ucrt
- cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64-ucrt.cmake ../..
+ cmake $NINJA -DCMAKE_TOOLCHAIN_FILE=./cmake/mingw-64-ucrt.cmake ../..
else
@@ -48,7 +55,7 @@ else
SUFFIX=" "
mkdir -p build/native
cd build/native
- cmake -G Ninja ../..
+ cmake $NINJA ../..
fi
diff --git a/source/luametatex/source/lua/lmtfontlib.c b/source/luametatex/source/lua/lmtfontlib.c
index b2982cc49..9850d59e7 100644
--- a/source/luametatex/source/lua/lmtfontlib.c
+++ b/source/luametatex/source/lua/lmtfontlib.c
@@ -313,6 +313,10 @@ static void fontlib_aux_font_char_from_lua(lua_State *L, halfword f, int i, int
set_charinfo_tag(co, inner_left_tag);
} else if (lua_key_eq(starget, right)) {
set_charinfo_tag(co, inner_right_tag);
+ } else if (lua_key_eq(starget, top)) {
+ set_charinfo_tag(co, inner_top_tag);
+ } else if (lua_key_eq(starget, bottom)) {
+ set_charinfo_tag(co, inner_bottom_tag);
}
set_numeric_field_by_index(target, innerxoffset, INT_MIN);
set_charinfo_inner_x_offset(co, target);
diff --git a/source/luametatex/source/lua/lmtinterface.h b/source/luametatex/source/lua/lmtinterface.h
index 26481d075..d98b55294 100644
--- a/source/luametatex/source/lua/lmtinterface.h
+++ b/source/luametatex/source/lua/lmtinterface.h
@@ -517,6 +517,7 @@ make_lua_key(L, catalog);\
make_lua_key(L, catcode_table);\
make_lua_key(L, category);\
make_lua_key(L, cell);\
+make_lua_key(L, center);\
make_lua_key(L, char);\
make_lua_key(L, char_given);\
make_lua_key(L, char_number);\
diff --git a/source/luametatex/source/lua/lmtnodelib.c b/source/luametatex/source/lua/lmtnodelib.c
index 997115267..d4a325c21 100644
--- a/source/luametatex/source/lua/lmtnodelib.c
+++ b/source/luametatex/source/lua/lmtnodelib.c
@@ -8243,7 +8243,7 @@ static int nodelib_direct_currentattributes(lua_State* L)
/* node.direct.todirect */
-static int nodelib_direct_todirect(lua_State* L)
+static int nodelib_shared_todirect(lua_State* L)
{
if (lua_type(L, 1) != LUA_TNUMBER) {
/* assume node, no further testing, used in known situations */
@@ -8271,7 +8271,7 @@ static int nodelib_direct_tovaliddirect(lua_State* L)
/* node.direct.tonode */
-static int nodelib_direct_tonode(lua_State* L)
+static int nodelib_shared_tonode(lua_State* L)
{
halfword n = nodelib_valid_direct_from_index(L, 1);
if (n) {
@@ -9882,8 +9882,6 @@ static const struct luaL_Reg nodelib_direct_function_list[] = {
{ "slide", nodelib_direct_slide },
{ "startofpar", nodelib_direct_startofpar },
{ "tail", nodelib_direct_tail },
- { "todirect", nodelib_direct_todirect },
- { "tonode", nodelib_direct_tonode },
{ "tostring", nodelib_direct_tostring },
{ "tovaliddirect", nodelib_direct_tovaliddirect },
{ "traverse", nodelib_direct_traverse },
@@ -9911,6 +9909,8 @@ static const struct luaL_Reg nodelib_direct_function_list[] = {
{ "setspeciallist", nodelib_direct_setspeciallist },
{ "isspeciallist", nodelib_direct_isspeciallist },
{ "getusedattributes", nodelib_direct_getusedattributes },
+ { "show", nodelib_direct_show },
+ { "serialized", nodelib_direct_serialized },
/* dual node and direct */
{ "type", nodelib_hybrid_type },
{ "types", nodelib_shared_types },
@@ -9918,10 +9918,10 @@ static const struct luaL_Reg nodelib_direct_function_list[] = {
{ "subtypes", nodelib_shared_subtypes },
{ "values", nodelib_shared_values },
{ "id", nodelib_shared_id },
- { "show", nodelib_direct_show },
- { "gluetostring", nodelib_hybrid_gluetostring },
- { "serialized", nodelib_direct_serialized },
{ "getcachestate", nodelib_shared_getcachestate },
+ { "todirect", nodelib_shared_todirect },
+ { "tonode", nodelib_shared_tonode },
+ { "gluetostring", nodelib_hybrid_gluetostring },
{ NULL, NULL },
};
@@ -9959,6 +9959,8 @@ static const struct luaL_Reg nodelib_function_list[] = {
{ "insertafter", nodelib_userdata_insertafter },
{ "insertbefore", nodelib_userdata_insertbefore },
{ "remove", nodelib_userdata_remove },
+ { "show", nodelib_userdata_show },
+ { "serialized", nodelib_userdata_serialized },
/* shared between userdata and direct */
{ "type", nodelib_hybrid_type },
{ "types", nodelib_shared_types },
@@ -9966,10 +9968,10 @@ static const struct luaL_Reg nodelib_function_list[] = {
{ "subtypes", nodelib_shared_subtypes },
{ "values", nodelib_shared_values },
{ "id", nodelib_shared_id },
- { "show", nodelib_userdata_show },
- { "gluetostring", nodelib_hybrid_gluetostring },
- { "serialized", nodelib_userdata_serialized },
{ "getcachestate", nodelib_shared_getcachestate },
+ { "todirect", nodelib_shared_todirect },
+ { "tonode", nodelib_shared_tonode },
+ { "gluetostring", nodelib_hybrid_gluetostring },
{ NULL, NULL },
};
diff --git a/source/luametatex/source/lua/lmttexlib.c b/source/luametatex/source/lua/lmttexlib.c
index 38c8e3fa8..0ce5bfd08 100644
--- a/source/luametatex/source/lua/lmttexlib.c
+++ b/source/luametatex/source/lua/lmttexlib.c
@@ -4829,7 +4829,7 @@ static int texlib_getglyphoptionvalues(lua_State *L)
static int texlib_getnoadoptionvalues(lua_State *L)
{
- lua_createtable(L, 2, 34);
+ lua_createtable(L, 2, 36);
lua_push_key_at_index(L, axis, noad_option_axis);
lua_push_key_at_index(L, noaxis, noad_option_no_axis);
lua_push_key_at_index(L, exact, noad_option_exact);
@@ -4866,6 +4866,9 @@ static int texlib_getnoadoptionvalues(lua_State *L)
lua_push_key_at_index(L, fixedsuperorsubscript, noad_option_fixed_super_or_sub_script);
lua_push_key_at_index(L, fixedsuperandsubscript, noad_option_fixed_super_and_sub_script);
lua_push_key_at_index(L, autobase, noad_option_auto_base);
+ lua_push_key_at_index(L, shrink, noad_option_shrink);
+ lua_push_key_at_index(L, stretch, noad_option_stretch);
+ lua_push_key_at_index(L, center, noad_option_center);
return 1;
}
@@ -5090,21 +5093,23 @@ static int texlib_getkerneloptionvalues(lua_State *L)
static int texlib_getcharactertagvalues(lua_State *L)
{
lua_createtable(L, 2, 12);
- lua_set_string_by_index(L, no_tag, "normal");
- lua_set_string_by_index(L, ligatures_tag, "ligatures");
- lua_set_string_by_index(L, kerns_tag, "kerns");
- lua_set_string_by_index(L, list_tag, "list");
- lua_set_string_by_index(L, callback_tag, "callback");
- lua_set_string_by_index(L, extensible_tag, "extensible");
- lua_set_string_by_index(L, horizontal_tag, "horizontal");
- lua_set_string_by_index(L, vertical_tag, "vertical");
- lua_set_string_by_index(L, extend_last_tag, "extendlast");
- lua_set_string_by_index(L, inner_left_tag, "innerleft");
- lua_set_string_by_index(L, inner_right_tag, "innerright");
- lua_set_string_by_index(L, italic_tag, "italic");
- lua_set_string_by_index(L, n_ary_tag, "nary");
- lua_set_string_by_index(L, radical_tag, "radical");
- lua_set_string_by_index(L, punctuation_tag, "punctuation");
+ lua_set_string_by_index(L, no_tag, "normal");
+ lua_set_string_by_index(L, ligatures_tag, "ligatures");
+ lua_set_string_by_index(L, kerns_tag, "kerns");
+ lua_set_string_by_index(L, list_tag, "list");
+ lua_set_string_by_index(L, callback_tag, "callback");
+ lua_set_string_by_index(L, extensible_tag, "extensible");
+ lua_set_string_by_index(L, horizontal_tag, "horizontal");
+ lua_set_string_by_index(L, vertical_tag, "vertical");
+ lua_set_string_by_index(L, inner_left_tag, "innerleft");
+ lua_set_string_by_index(L, inner_right_tag, "innerright");
+ lua_set_string_by_index(L, inner_top_tag, "innertop");
+ lua_set_string_by_index(L, inner_bottom_tag, "innerbottom");
+ lua_set_string_by_index(L, extend_last_tag, "extendlast");
+ lua_set_string_by_index(L, italic_tag, "italic");
+ lua_set_string_by_index(L, n_ary_tag, "nary");
+ lua_set_string_by_index(L, radical_tag, "radical");
+ lua_set_string_by_index(L, punctuation_tag, "punctuation");
return 1;
}
diff --git a/source/luametatex/source/luacore/lua54/src/ldo.c b/source/luametatex/source/luacore/lua54/src/ldo.c
index c30cde76f..2a0017ca6 100644
--- a/source/luametatex/source/luacore/lua54/src/ldo.c
+++ b/source/luametatex/source/luacore/lua54/src/ldo.c
@@ -299,17 +299,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int nsize = inuse * 2; /* proposed new size */
- int max = inuse * 3; /* maximum "reasonable" size */
- if (max > LUAI_MAXSTACK) {
- max = LUAI_MAXSTACK; /* respect stack limit */
- if (nsize > LUAI_MAXSTACK)
- nsize = LUAI_MAXSTACK;
- }
+ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
- if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+ if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+ int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
+ }
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@@ -629,7 +625,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/
-l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
diff --git a/source/luametatex/source/luacore/lua54/src/lopcodes.h b/source/luametatex/source/luacore/lua54/src/lopcodes.h
index 7c2745159..4c5514539 100644
--- a/source/luametatex/source/luacore/lua54/src/lopcodes.h
+++ b/source/luametatex/source/luacore/lua54/src/lopcodes.h
@@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
-isJ sJ(25) | Op(7) |
+isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
diff --git a/source/luametatex/source/luacore/lua54/src/loslib.c b/source/luametatex/source/luacore/lua54/src/loslib.c
index 89ac06bc4..ad5a92768 100644
--- a/source/luametatex/source/luacore/lua54/src/loslib.c
+++ b/source/luametatex/source/luacore/lua54/src/loslib.c
@@ -30,23 +30,14 @@
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
- "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
- "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-
#if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
+#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
diff --git a/source/luametatex/source/luacore/lua54/src/ltable.c b/source/luametatex/source/luacore/lua54/src/ltable.c
index cc7993e08..3c690c5f1 100644
--- a/source/luametatex/source/luacore/lua54/src/ltable.c
+++ b/source/luametatex/source/luacore/lua54/src/ltable.c
@@ -257,10 +257,12 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
+#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
return size;
diff --git a/source/luametatex/source/luacore/lua54/src/lvm.c b/source/luametatex/source/luacore/lua54/src/lvm.c
index 2e84dc63c..8493a770c 100644
--- a/source/luametatex/source/luacore/lua54/src/lvm.c
+++ b/source/luametatex/source/luacore/lua54/src/lvm.c
@@ -1410,6 +1410,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MODK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -1422,6 +1423,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIVK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -1470,6 +1472,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_MOD) {
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -1482,6 +1485,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
diff --git a/source/luametatex/source/luametatex.h b/source/luametatex/source/luametatex.h
index 4d79c6cf2..05c40321d 100644
--- a/source/luametatex/source/luametatex.h
+++ b/source/luametatex/source/luametatex.h
@@ -90,9 +90,9 @@
# include "tex/textypes.h"
# define luametatex_version 210
-# define luametatex_revision 07
-# define luametatex_version_string "2.10.07"
-# define luametatex_development_id 20230306
+# define luametatex_revision 8
+# define luametatex_version_string "2.10.08"
+# define luametatex_development_id 20230320
# define luametatex_name_camelcase "LuaMetaTeX"
# define luametatex_name_lowercase "luametatex"
diff --git a/source/luametatex/source/tex/texexpand.c b/source/luametatex/source/tex/texexpand.c
index 6cf887bea..706972bfe 100644
--- a/source/luametatex/source/tex/texexpand.c
+++ b/source/luametatex/source/tex/texexpand.c
@@ -550,7 +550,8 @@ void tex_expand_current_token(void)
/*tex Complain about an undefined macro */
tex_handle_error(
normal_error_type,
- "Undefined control sequence %m", cur_cs,
+ // "Undefined control sequence %m", cur_cs,
+ "Undefined control sequence",
"The control sequence at the end of the top line of your error message was never\n"
"\\def'ed. You can just continue as I'll forget about whatever was undefined."
);
diff --git a/source/luametatex/source/tex/texfont.h b/source/luametatex/source/tex/texfont.h
index 947cdf446..0d3fa9fb3 100644
--- a/source/luametatex/source/tex/texfont.h
+++ b/source/luametatex/source/tex/texfont.h
@@ -465,21 +465,23 @@ extern int tex_get_math_char (halfword f, int c, int size, scaled *scal
*/
typedef enum char_tag_codes {
- no_tag = 0x0000, /*tex vanilla character */
- ligatures_tag = 0x0001, /*tex character has a ligature program, not used */
- kerns_tag = 0x0002, /*tex character has a kerning program, not used */
- list_tag = 0x0004, /*tex character has a successor in a charlist */
- callback_tag = 0x0010,
- extensible_tag = 0x0020, /*tex character is extensible, we can unset it in order to block */
- horizontal_tag = 0x0040, /*tex horizontal extensible */
- vertical_tag = 0x0080, /*tex vertical extensible */
- extend_last_tag = 0x0100, /*tex auto scale last variant */
- inner_left_tag = 0x0200, /*tex anchoring */
- inner_right_tag = 0x0400, /*tex anchoring */
- italic_tag = 0x0800,
- n_ary_tag = 0x1000,
- radical_tag = 0x2000,
- punctuation_tag = 0x4000,
+ no_tag = 0x00000, /*tex vanilla character */
+ ligatures_tag = 0x00001, /*tex character has a ligature program, not used */
+ kerns_tag = 0x00002, /*tex character has a kerning program, not used */
+ list_tag = 0x00004, /*tex character has a successor in a charlist */
+ callback_tag = 0x00010,
+ extensible_tag = 0x00020, /*tex character is extensible, we can unset it in order to block */
+ horizontal_tag = 0x00040, /*tex horizontal extensible */
+ vertical_tag = 0x00080, /*tex vertical extensible */
+ inner_left_tag = 0x00100, /*tex anchoring */
+ inner_right_tag = 0x00200, /*tex anchoring */
+ inner_top_tag = 0x00400, /*tex anchoring */
+ inner_bottom_tag = 0x00800, /*tex anchoring */
+ extend_last_tag = 0x01000, /*tex auto scale last variant */
+ italic_tag = 0x02000,
+ n_ary_tag = 0x04000,
+ radical_tag = 0x08000,
+ punctuation_tag = 0x10000,
} char_tag_codes;
/*tex
@@ -597,8 +599,6 @@ extern scaled tex_char_top_margin_from_font (halfword f, halfword c)
extern scaled tex_char_bottom_margin_from_font (halfword f, halfword c);
extern scaled tex_char_top_overshoot_from_font (halfword f, halfword c);
extern scaled tex_char_bottom_overshoot_from_font (halfword f, halfword c);
-extern scaled tex_char_inner_x_offset_from_font (halfword f, halfword c);
-extern scaled tex_char_inner_y_offset_from_font (halfword f, halfword c);
extern extinfo *tex_char_extensible_recipe_from_font (halfword f, halfword c);
extern halfword tex_char_unchecked_top_anchor_from_font (halfword f, halfword c);
diff --git a/source/luametatex/source/tex/texmath.c b/source/luametatex/source/tex/texmath.c
index 01db082b2..0e52f7c70 100644
--- a/source/luametatex/source/tex/texmath.c
+++ b/source/luametatex/source/tex/texmath.c
@@ -2672,37 +2672,49 @@ void tex_run_math_radical(void)
attrlist = tex_scan_attribute(attrlist);
}
break;
- case 'e': case 'E':
- if (tex_scan_mandate_keyword("exact", 1)) {
- options = options | noad_option_exact;
- }
- break;
case 'b': case 'B':
if (tex_scan_mandate_keyword("bottom", 1)) {
bottom = 1;
}
break;
+ case 'e': case 'E':
+ if (tex_scan_mandate_keyword("exact", 1)) {
+ options = options | noad_option_exact;
+ }
+ break;
case 't': case 'T':
if (tex_scan_mandate_keyword("top", 1)) {
top = 1;
}
break;
case 's': case 'S':
- switch (tex_scan_character("itoITO", 0, 0, 0)) {
+ switch (tex_scan_character("hitoHITO", 0, 0, 0)) {
case 't': case 'T':
- if (tex_scan_mandate_keyword("style", 2)) {
- switch (code) {
- case normal_radical_subtype:
- case radical_radical_subtype:
- case root_radical_subtype:
- case rooted_radical_subtype:
- case delimited_radical_subtype:
- style = tex_scan_math_style_identifier(1, 0);
- break;
- default:
- /* ignore */
- break;
- }
+ switch (tex_scan_character("ryRY", 0, 0, 0)) {
+ case 'y': case 'Y':
+ if (tex_scan_mandate_keyword("style", 3)) {
+ switch (code) {
+ case normal_radical_subtype:
+ case radical_radical_subtype:
+ case root_radical_subtype:
+ case rooted_radical_subtype:
+ case delimited_radical_subtype:
+ style = tex_scan_math_style_identifier(1, 0);
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ }
+ break;
+ case 'r': case 'R':
+ if (tex_scan_mandate_keyword("stretch", 3)) {
+ options = options | noad_option_stretch;
+ }
+ break;
+ default:
+ tex_aux_show_keyword_error("style|stretch");
+ goto DONE;
}
break;
case 'o': case 'O':
@@ -2715,8 +2727,13 @@ void tex_run_math_radical(void)
radical_size(radical) = tex_scan_int(0, NULL);
}
break;
+ case 'h': case 'H':
+ if (tex_scan_mandate_keyword("shrink", 2)) {
+ options = options | noad_option_shrink;
+ }
+ break;
default:
- tex_aux_show_keyword_error("style|source");
+ tex_aux_show_keyword_error("style|source|stretch|shrink");
goto DONE;
}
break;
@@ -2898,132 +2915,6 @@ void tex_finish_math_radical(void)
}
}
-// void tex_run_math_accent(void)
-// {
-// mathcodeval t = tex_no_math_code();
-// mathcodeval b = tex_no_math_code();
-// mathcodeval o = tex_no_math_code();
-// halfword code = cur_chr;
-// halfword accent = tex_new_node(accent_noad, bothflexible_accent_subtype);
-// quarterword subtype = ordinary_noad_subtype;
-// halfword attrlist = null;
-// if (cur_cmd == accent_cmd) {
-// tex_handle_error(
-// normal_error_type,
-// "Please use \\mathaccent for accents in math mode",
-// "I'm changing \\accent to \\mathaccent here; wish me luck. (Accents are not the\n"
-// "same in formulas as they are in text.)" );
-// }
-// tex_tail_append(accent);
-// switch (code) {
-// case math_accent_code:
-// /*tex |\mathaccent| */
-// t = tex_scan_mathchar(tex_mathcode);
-// break;
-// case math_uaccent_code:
-// /*tex |\Umathaccent| */
-// while (1) {
-// switch (tex_scan_character("abnsfABNSF", 0, 1, 0)) {
-// case 'a': case 'A':
-// if (tex_scan_mandate_keyword("attr", 1)) {
-// attrlist = tex_scan_attribute(attrlist);
-// }
-// break;
-// case 's': case 'S':
-// if (tex_scan_mandate_keyword("source", 1)) {
-// noad_source(accent) = tex_scan_int(0, NULL);
-// }
-// break;
-// case 'f': case 'F':
-// if (tex_scan_mandate_keyword("fraction", 1)) {
-// accent_fraction(accent) = tex_scan_int(0, NULL);
-// }
-// break;
-// case 'n': case 'N':
-// if (tex_scan_mandate_keyword("nooverflow", 1)) {
-// /*tex
-// Actually there never is an overflow but for consistency we do
-// accept this key. Mayebe in the future it will be used.
-// */
-// noad_options(accent) |= noad_option_no_overflow;
-// }
-// break;
-// case 'b': case 'B':
-// if (tex_scan_mandate_keyword("base", 1)) {
-// noad_options(accent) |= noad_option_auto_base;
-// }
-// break;
-// default:
-// goto DONE;
-// }
-// }
-// DONE:
-// /* todo: integrate in the above */
-// if (tex_scan_keyword("fixed")) {
-// /*tex top */
-// node_subtype(accent) = fixedtop_accent_subtype;
-// t = tex_scan_mathchar(umath_mathcode);
-// } else if (tex_scan_keyword("both")) {
-// /*tex top bottom */
-// if (tex_scan_keyword("fixed")) {
-// node_subtype(accent) = fixedtop_accent_subtype;
-// }
-// t = tex_scan_mathchar(umath_mathcode);
-// if (tex_scan_keyword("fixed")) {
-// node_subtype(accent) = fixedboth_accent_subtype;
-// }
-// b = tex_scan_mathchar(umath_mathcode);
-// } else if (tex_scan_keyword("bottom")) {
-// /*tex bottom */
-// if (tex_scan_keyword("fixed")) {
-// node_subtype(accent) = fixedbottom_accent_subtype;
-// }
-// b = tex_scan_mathchar(umath_mathcode);
-// } else if (tex_scan_keyword("top")) {
-// /*tex top */
-// if (tex_scan_keyword("fixed")) {
-// node_subtype(accent) = fixedtop_accent_subtype;
-// }
-// t = tex_scan_mathchar(umath_mathcode);
-// } else if (tex_scan_keyword("overlay")) {
-// /* overlay */
-// if (tex_scan_keyword("fixed")) {
-// node_subtype(accent) = fixedtop_accent_subtype;
-// }
-// o = tex_scan_mathchar(umath_mathcode);
-// } else {
-// /*tex top */
-// t = tex_scan_mathchar(umath_mathcode);
-// }
-// break;
-// default:
-// tex_confusion("scan math accent");
-// }
-// if (attrlist) {
-// tex_attach_attribute_list_attribute(accent, attrlist);
-// }
-// if (! (t.character_value == 0 && t.family_value == 0)) {
-// halfword n = tex_new_node(math_char_node, 0);
-// subtype = tex_aux_set_math_char(n, &t, NULL);
-// accent_top_character(accent) = n;
-// }
-// if (! (b.character_value == 0 && b.family_value == 0)) {
-// halfword n = tex_new_node(math_char_node, 0);
-// subtype = tex_aux_set_math_char(n, &b, NULL);
-// accent_bottom_character(accent) = n;
-// }
-// if (! (o.character_value == 0 && o.family_value == 0)) {
-// halfword n = tex_new_node(math_char_node, 0);
-// subtype = tex_aux_set_math_char(n, &o, NULL);
-// accent_middle_character(accent) = n;
-// }
-// {
-// halfword n = tex_new_node(math_char_node, subtype);
-// noad_nucleus(accent) = n;
-// tex_aux_scan_math(n, tex_math_style_variant(cur_list.math_style, math_parameter_accent_variant), 0, 0, 0, 0, unset_noad_class, unset_noad_class);
-// }
-// }
-
void tex_run_math_accent(void)
{
mathcodeval t = tex_no_math_code();
@@ -3049,12 +2940,17 @@ void tex_run_math_accent(void)
case math_uaccent_code:
/*tex |\Umathaccent| */
while (1) {
- switch (tex_scan_character("abnsftoABNSFTO", 0, 1, 0)) {
+ switch (tex_scan_character("abcnsftoABCNSFTO", 0, 1, 0)) {
case 'a': case 'A':
if (tex_scan_mandate_keyword("attr", 1)) {
attrlist = tex_scan_attribute(attrlist);
}
break;
+ case 'c': case 'C':
+ if (tex_scan_mandate_keyword("center", 1)) {
+ noad_options(accent) |= noad_option_center;
+ }
+ break;
case 's': case 'S':
if (tex_scan_mandate_keyword("source", 1)) {
noad_source(accent) = tex_scan_int(0, NULL);
diff --git a/source/luametatex/source/tex/texmlist.c b/source/luametatex/source/tex/texmlist.c
index 56b780506..3b7734ccf 100644
--- a/source/luametatex/source/tex/texmlist.c
+++ b/source/luametatex/source/tex/texmlist.c
@@ -861,7 +861,7 @@ static halfword tex_aux_underbar(halfword box, scaled gap, scaled height, scaled
*/
-static halfword tex_aux_char_box(halfword fnt, int chr, halfword att, scaled *ic, quarterword subtype, scaled target, int style)
+static halfword tex_aux_char_box(halfword fnt, int chr, halfword att, scaled *ic, quarterword subtype, scaled target, int style, int shrink, int stretch)
{
/*tex The new box and its character node. */
halfword glyph = tex_aux_new_math_glyph(fnt, chr, subtype);
@@ -876,7 +876,7 @@ static halfword tex_aux_char_box(halfword fnt, int chr, halfword att, scaled *ic
if (tex_has_glyph_option(glyph, glyph_option_no_italic_correction)) {
whd.ic = 0;
}
- if (whd.ic) {
+ if (! (stretch || shrink) && whd.ic) {
if (ic) {
*ic = whd.ic; /* also in open type? needs checking */
}
@@ -889,12 +889,19 @@ static halfword tex_aux_char_box(halfword fnt, int chr, halfword att, scaled *ic
} else if (ic) {
*ic = 0;
}
- if (target && whd.wd > 0 && whd.wd < target && tex_aux_math_engine_control(fnt, math_control_extend_accents) && tex_char_has_tag_from_font(fnt, chr, extend_last_tag)) {
- scaled margin = tex_get_math_x_parameter_default(style, math_parameter_accent_extend_margin, 0);
- scaled amount = target - 2 * margin;
- if (amount > 0) {
- glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * amount/whd.wd);
- glyph_x_offset(glyph) = (whd.wd - amount)/2;
+ if (target && whd.wd > 0) {
+ if (whd.wd < target && tex_aux_math_engine_control(fnt, math_control_extend_accents) && tex_char_has_tag_from_font(fnt, chr, extend_last_tag)) {
+ scaled margin = tex_get_math_x_parameter_default(style, math_parameter_accent_extend_margin, 0);
+ scaled amount = target - 2 * margin;
+ if (amount > 0) {
+ glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * amount/whd.wd);
+ glyph_x_offset(glyph) = (whd.wd - amount)/2;
+ }
+ return box;
+ }
+ if ((shrink && (whd.wd > target)) || (stretch && (whd.wd < target))) {
+ glyph_x_scale(glyph) = lround((double) glyph_x_scale(glyph) * target/whd.wd);
+ glyph_x_offset(glyph) = (whd.wd - target)/2;
}
}
return box;
@@ -1384,6 +1391,8 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
/*tex are we trying the large variant? */
int large_attempt = 0;
int do_parts = 0;
+ int shrink = flat && tex_has_noad_option(target, noad_option_shrink);
+ int stretch = flat && tex_has_noad_option(target, noad_option_stretch);
/*tex to save the current attribute list */
halfword att = null;
if (extremes) {
@@ -1448,7 +1457,7 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
if (total >= (targetsize - tolerance)) {
goto FOUND;
}
- }
+ }
if (tex_char_has_tag_from_font(curfnt, curchr, extensible_tag)) {
if (tex_char_has_tag_from_font(curfnt, curchr, horizontal_tag) || tex_char_has_tag_from_font(curfnt, curchr, vertical_tag)) {
/*tex We only check when we are explicit. */
@@ -1498,8 +1507,13 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
*/
extinfo *ext = do_parts ? tex_char_extensible_recipe_from_font(fnt, chr) : NULL;
if (ext) {
- scaled minoverlap = flat ? tex_get_math_x_parameter_default(style, math_parameter_connector_overlap_min, 0) : tex_get_math_y_parameter_default(style, math_parameter_connector_overlap_min, 0);;
+ scaled minoverlap = flat ? tex_get_math_x_parameter_default(style, math_parameter_connector_overlap_min, 0) : tex_get_math_y_parameter_default(style, math_parameter_connector_overlap_min, 0);
result = tex_aux_get_delimiter_box(fnt, chr, targetsize, minoverlap, flat, att);
+ if (stretch && flat && (box_width(result) > targetsize)) { // threshold nooverflow
+ tex_flush_node_list(result);
+ do_parts = 0;
+ goto HERE;
+ }
if (delta) {
/*tex Not yet done: horizontal italics. */
if (tex_aux_math_engine_control(fnt, math_control_apply_vertical_italic_kern)) {
@@ -1529,7 +1543,8 @@ static halfword tex_aux_make_delimiter(halfword target, halfword delimiter, int
the traditional width (which is fake width + italic) becomes less and the delta is
added. See (**).
*/
- result = tex_aux_char_box(fnt, chr, att, delta, glyph_math_delimiter_subtype, flat ? targetsize : 0, style);
+ HERE:
+ result = tex_aux_char_box(fnt, chr, att, delta, glyph_math_delimiter_subtype, flat ? targetsize : 0, style, shrink, stretch);
if (flat) {
/* This will be done when we have a reasonable example. */
} else {
@@ -2395,12 +2410,20 @@ static void tex_aux_make_root_radical(halfword target, int style, int size, kern
}
delimiter = tex_aux_make_delimiter(target, delimiter, size, box_total(nucleus) + clearance + theta, 0, style, 1, NULL, NULL, 0, has_noad_option_nooverflow(target), &extremes, 0);
if (radical_degree(target)) {
+ halfword innerf = 0;
+ halfword innerc = 0;
if (tex_char_has_tag_from_font(extremes.bfont, extremes.bchar, inner_left_tag)) {
- innerx = tex_char_inner_x_offset_from_font(extremes.bfont, extremes.bchar);
- innery = tex_char_inner_y_offset_from_font(extremes.bfont, extremes.bchar);
+ innerf = extremes.bfont;
+ innerc = extremes.bchar;
} else if (tex_char_has_tag_from_font(extremes.tfont, extremes.tchar, inner_left_tag)) {
- innerx = tex_char_inner_x_offset_from_font(extremes.tfont, extremes.tchar);
- innery = tex_char_inner_y_offset_from_font(extremes.tfont, extremes.tchar);
+ innerf = extremes.tfont;
+ innerc = extremes.tchar;
+ }
+ if (innerc) {
+ innerx = tex_char_inner_x_offset_from_font(innerf, innerc);
+ innery = tex_char_inner_y_offset_from_font(innerf, innerc);
+ innerx = innerx == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innerx, size);
+ innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(innerf, innery, size);
}
}
if (companion) {
@@ -2790,7 +2813,7 @@ static void tex_aux_preroll_radical(halfword target, int style, int size)
typedef enum math_accent_location_codes {
top_accent_code = 1,
- bot_accent_code = 2,
+ bot_accent_code = 2, // todo : bottom_accent_code
overlay_accent_code = 4,
stretch_accent_code = 8, /* reserved, not yet set */
} math_accent_location_codes;
@@ -2896,6 +2919,7 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
scaled fraction = accent_fraction(target) > 0 ? accent_fraction(target) : 1000;
scaled skew = 0;
scaled offset = 0;
+ scaled innery = 0;
halfword accent = null;
halfword base = null;
halfword result = null;
@@ -3008,7 +3032,7 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
}
if (! accent) {
/*tex Italic gets added to width for traditional fonts (no italic anyway): */
- accent = tex_aux_char_box(accentfnt, accentchr, attrlist, NULL, glyph_math_accent_subtype, basewidth, style); // usedwidth
+ accent = tex_aux_char_box(accentfnt, accentchr, attrlist, NULL, glyph_math_accent_subtype, basewidth, style, 0, 0); // usedwidth
}
if (flags & top_accent_code) {
scaled b = tex_get_math_y_parameter(style, math_parameter_accent_base_height);
@@ -3019,7 +3043,7 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
halfword flatchr = tex_char_flat_accent_from_font(accentfnt, accentchr);
if (flatchr != INT_MIN && flatchr != accentchr) {
tex_flush_node(accent);
- accent = tex_aux_char_box(accentfnt, flatchr, attrlist, NULL, glyph_math_accent_subtype, usedwidth, style);
+ accent = tex_aux_char_box(accentfnt, flatchr, attrlist, NULL, glyph_math_accent_subtype, usedwidth, style, 0, 0);
if (tracing_math_par >= 2) {
tex_begin_diagnostic();
tex_print_format("[math: flattening accent, old %x, new %x]", accentchr, flatchr);
@@ -3039,6 +3063,10 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
if (u != undefined_math_parameter) {
delta -= u;
}
+ if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_top_tag)) {
+ innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
+ innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
+ }
} else if (flags & bot_accent_code) {
// scaled b = tex_get_math_y_parameter(style, math_parameter_accent_base_depth, 0);
// scaled f = tex_get_math_y_parameter(style, math_parameter_flattened_accent_base_depth, 0);
@@ -3050,6 +3078,10 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
if (l != undefined_math_parameter) {
delta += l;
}
+ if (tex_char_has_tag_from_font(accentfnt, accentchr, inner_bottom_tag)) {
+ innery = tex_char_inner_y_offset_from_font(accentfnt, accentchr);
+ innery = innery == INT_MIN ? 0 : tex_aux_math_y_size_scaled(accentfnt, innery, size);
+ }
} else { /* if (flags & overlay_accent_code) { */
/*tex Center the accent vertically around base: */
delta = tex_half_scaled(box_total(accent) + box_total(base));
@@ -3082,11 +3114,11 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
anchor = tex_half_scaled(accentwidth);
} else {
anchor = tex_char_unchecked_top_anchor_from_font(accentfnt, accentchr); /* no bot accent key */
- if (anchor != INT_MIN) {
- anchor = tex_aux_math_y_size_scaled(accentfnt, anchor, size); /* why y and not x */
- } else {
+ if (anchor == INT_MIN || has_noad_option_center(target)) {
/*tex just take the center */
anchor = tex_half_scaled(accentwidth);
+ } else {
+ anchor = tex_aux_math_x_size_scaled(accentfnt, anchor, size);
}
}
if (math_direction_par == dir_righttoleft) {
@@ -3117,6 +3149,7 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
accent_bot_overshoot(target) = overshoot;
}
if (flags & (top_accent_code | overlay_accent_code)) {
+ delta += innery;
if (delta) {
halfword kern = tex_new_kern_node(-delta, vertical_math_kern_subtype);
tex_attach_attribute_list_copy(kern, target);
@@ -3126,6 +3159,12 @@ static void tex_aux_do_make_math_accent(halfword target, halfword accentfnt, hal
tex_couple_nodes(accent, base);
}
result = accent;
+ } else if ((flags & bot_accent_code) && innery) {
+ halfword kern = tex_new_kern_node(innery, vertical_math_kern_subtype);
+ tex_attach_attribute_list_copy(kern, target);
+ tex_couple_nodes(base, kern);
+ tex_couple_nodes(kern, accent);
+ result = base;
} else {
tex_couple_nodes(base, accent);
result = base;
@@ -7107,7 +7146,7 @@ static void tex_mlist_to_hlist_finalize_list(mliststate *state)
tex_couple_nodes(p, box_list(l));
box_list(l) = null;
tex_flush_node(l);
- } else if (current_type == simple_noad && current_subtype == math_end_class) {
+ } else if (current_type == simple_noad && (current_subtype == math_end_class) || (current_subtype == math_begin_class)) {
if (noad_new_hlist(current)) {
tex_flush_node(noad_new_hlist(current));
noad_new_hlist(current) = null;
diff --git a/source/luametatex/source/tex/texnodes.h b/source/luametatex/source/tex/texnodes.h
index f3f9276a6..cb666f874 100644
--- a/source/luametatex/source/tex/texnodes.h
+++ b/source/luametatex/source/tex/texnodes.h
@@ -1788,13 +1788,16 @@ typedef enum noad_options {
# define noad_option_fixed_super_or_sub_script 0x0200000000
# define noad_option_fixed_super_and_sub_script 0x0400000000
# define noad_option_auto_base 0x0800000000
+# define noad_option_stretch 0x1000000000
+# define noad_option_shrink 0x2000000000
+# define noad_option_center 0x4000000000
# define has_option(a,b) (((a) & (b)) == (b))
# define unset_option(a,b) ((a) & ~(b))
-inline static void tex_add_noad_option (halfword a, halfword r) { noad_options(a) |= r; }
-inline static void tex_remove_noad_option (halfword a, halfword r) { noad_options(a) &= ~(r | noad_options(a)); }
-inline static int tex_has_noad_option (halfword a, halfword r) { return (noad_options(a) & r) == r; }
+inline static void tex_add_noad_option (halfword a, long long r) { noad_options(a) |= r; }
+inline static void tex_remove_noad_option (halfword a, long long r) { noad_options(a) &= ~(r | noad_options(a)); }
+inline static int tex_has_noad_option (halfword a, long long r) { return (noad_options(a) & r) == r; }
inline static int has_noad_no_script_option(halfword n, halfword option)
{
@@ -1842,6 +1845,7 @@ inline static int has_noad_no_script_option(halfword n, halfword option)
# define has_noad_option_unrolllist(a) (has_option(noad_options(a), noad_option_unroll_list))
# define has_noad_option_followedbyspace(a) (has_option(noad_options(a), noad_option_followed_by_space))
# define has_noad_option_proportional(a) (has_option(noad_options(a), noad_option_proportional))
+# define has_noad_option_center(a) (has_option(noad_options(a), noad_option_center))
# define has_noad_option_source_on_nucleus(a) (has_option(noad_options(a), noad_option_source_on_nucleus))
# define has_noad_option_fixed_super_or_sub_script(a) (has_option(noad_options(a), noad_option_fixed_super_or_sub_script))
# define has_noad_option_fixed_super_and_sub_script(a) (has_option(noad_options(a), noad_option_fixed_super_and_sub_script))
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index adf47a428..ec168c472 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2023.03.10 12:15}
+\newcontextversion{2023.03.20 15:42}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index cbe8cf4ff..9e6c53624 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2023.03.10 12:15}
+\edef\contextversion{2023.03.20 15:42}
%D For those who want to use this:
diff --git a/tex/context/base/mkii/mult-it.mkii b/tex/context/base/mkii/mult-it.mkii
index d9a553cea..b700c4172 100644
--- a/tex/context/base/mkii/mult-it.mkii
+++ b/tex/context/base/mkii/mult-it.mkii
@@ -832,6 +832,7 @@
\setinterfaceconstant{exitoffset}{exitoffset}
\setinterfaceconstant{expansion}{espansione}
\setinterfaceconstant{export}{export}
+\setinterfaceconstant{extradata}{extradata}
\setinterfaceconstant{extras}{extras}
\setinterfaceconstant{factor}{fattore}
\setinterfaceconstant{fallback}{fallback}
@@ -955,6 +956,7 @@
\setinterfaceconstant{lastpage}{ultimapagina}
\setinterfaceconstant{lastpagesep}{lastpagesep}
\setinterfaceconstant{lastpubsep}{lastpubsep}
+\setinterfaceconstant{lasttextseparator}{lasttextseparator}
\setinterfaceconstant{layout}{layout}
\setinterfaceconstant{left}{sinistra}
\setinterfaceconstant{leftclass}{leftclass}
diff --git a/tex/context/base/mkiv/attr-mkr.mkiv b/tex/context/base/mkiv/attr-mkr.mkiv
index 544558dcf..a784dd9d8 100644
--- a/tex/context/base/mkiv/attr-mkr.mkiv
+++ b/tex/context/base/mkiv/attr-mkr.mkiv
@@ -20,6 +20,7 @@
\unexpanded\def\definemarker [#1]{\defineattribute[\s!marker:#1]}
\unexpanded\def\setmarker [#1]#2[#3]{\dosetattribute{\s!marker:#1}{#3}}
\unexpanded\def\resetmarker [#1]{\dogetattribute{\s!marker:#1}}
- \def\boxmarker #1#2{attr \numexpr\dogetattributeid{\s!marker:#1}\numexpr \numexpr#2\relax}
+ \def\boxmarker #1#2{attr \numexpr\dogetattributeid{\s!marker:#1}\relax \numexpr\numexpr#2\relax}
+\unexpanded\def\marker #1{\numexpr\dogetattributeid{\s!marker:#1}\relax}
\protect \endinput
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index 22e4d4bae..684cf24c8 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2023.03.10 12:15}
+\newcontextversion{2023.03.20 15:42}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 1c9effa6a..9b89b9bdf 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -49,7 +49,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2023.03.10 12:15}
+\edef\contextversion{2023.03.20 15:42}
%D Kind of special:
diff --git a/tex/context/base/mkiv/lpdf-mis.lua b/tex/context/base/mkiv/lpdf-mis.lua
index 94e9fc271..803a8860e 100644
--- a/tex/context/base/mkiv/lpdf-mis.lua
+++ b/tex/context/base/mkiv/lpdf-mis.lua
@@ -246,7 +246,8 @@ local function setupidentity()
addtoinfo("ConTeXt.Version",version)
addtoinfo("ConTeXt.Time",os.date("%Y-%m-%d %H:%M"))
addtoinfo("ConTeXt.Jobname",jobname)
- addtoinfo("ConTeXt.Url","www.pragma-ade.com")
+ -- addtoinfo("ConTeXt.Url","www.pragma-ade.com")
+ addtoinfo("ConTeXt.Url","github.com/contextgarden/context")
addtoinfo("ConTeXt.Support","contextgarden.net")
addtoinfo("TeX.Support","tug.org")
--
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index c073662c5..de994239b 100644
--- a/tex/context/base/mkiv/status-files.pdf
+++ b/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 5bced88ec..e6773acf4 100644
--- a/tex/context/base/mkiv/status-lua.pdf
+++ b/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/util-prs.lua b/tex/context/base/mkiv/util-prs.lua
index 635b610e0..d7b7087a5 100644
--- a/tex/context/base/mkiv/util-prs.lua
+++ b/tex/context/base/mkiv/util-prs.lua
@@ -264,8 +264,13 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols = S(symbol)
local separator = space^0 * symbols * space^0
- local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace
- + C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0)
+ local value =
+ lbrace
+ * C((nobrace + nestedbraces)^0)
+ -- * rbrace
+ * (rbrace * (#symbols + P(-1))) -- new per 2023-03-11
+ +
+ C((nestedbraces + (1-(space^0*(symbols+P(-1)))))^0)
if withaction then
local withvalue = Carg(1) * value / function(f,s) return f(s) end
pattern = spaces * withvalue * (separator*withvalue)^0
diff --git a/tex/context/base/mkxl/attr-eff.lmt b/tex/context/base/mkxl/attr-eff.lmt
new file mode 100644
index 000000000..d04408fb9
--- /dev/null
+++ b/tex/context/base/mkxl/attr-eff.lmt
@@ -0,0 +1,134 @@
+if not modules then modules = { } end modules ['attr-eff'] = {
+ version = 1.001,
+ comment = "companion to attr-eff.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local attributes, nodes, backends, utilities = attributes, nodes, backends, utilities
+local tex = tex
+
+local states = attributes.states
+local enableaction = nodes.tasks.enableaction
+local nodeinjections = backends.nodeinjections
+local texsetattribute = tex.setattribute
+local allocate = utilities.storage.allocate
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+
+local interfaces = interfaces
+local implement = interfaces.implement
+
+local variables = interfaces.variables
+local v_normal = variables.normal
+
+attributes.effects = attributes.effects or { }
+local effects = attributes.effects
+
+local a_effect = attributes.private('effect')
+
+effects.data = allocate()
+effects.values = effects.values or { }
+effects.registered = effects.registered or { }
+effects.attribute = a_effect
+
+local data = effects.data
+local registered = effects.registered
+local values = effects.values
+
+local f_stamp = formatters["%s:%s:%s"]
+
+storage.register("attributes/effects/registered", registered, "attributes.effects.registered")
+storage.register("attributes/effects/values", values, "attributes.effects.values")
+
+-- valid effects: normal inner outer both hidden (stretch,rulethickness,effect)
+
+local function effect(...) effect = nodeinjections.effect return effect(...) end
+
+local function extender(effects,key)
+ if key == "none" then
+ local d = effect(0,0,0)
+ effects.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ local e = values[n] -- we could nil values[n] now but hardly needed
+ local d = effect(e[1],e[2],e[3])
+ data[n] = d
+ return d
+end
+
+setmetatableindex(effects, extender)
+setmetatableindex(effects.data, reviver)
+
+effects.handler = nodes.installattributehandler {
+ name = "effect",
+ namespace = effects,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+local function register(specification)
+ local alternative, stretch, rulethickness
+ if specification then
+ alternative = specification.alternative or v_normal
+ stretch = specification.stretch or 0
+ rulethickness = specification.rulethickness or 0
+ else
+ alternative = v_normal
+ stretch = 0
+ rulethickness = 0
+ end
+ local stamp = f_stamp(alternative,stretch,rulethickness)
+ local n = registered[stamp]
+ if not n then
+ n = #values + 1
+ values[n] = { alternative, stretch, rulethickness }
+ registered[stamp] = n
+ end
+ return n
+end
+
+local enabled = false
+
+local function enable()
+ if not enabled then
+ enableaction("shipouts","attributes.effects.handler")
+ enabled = true
+ end
+end
+
+effects.register = register
+effects.enable = enable
+
+-- interface
+
+implement {
+ name = "seteffect",
+ actions = function(specification)
+ if not enabled then
+ enable()
+ end
+ texsetattribute(a_effect,register(specification))
+ end,
+ arguments = {
+ {
+ { "alternative", "string" },
+ { "stretch", "integer" },
+ { "rulethickness", "dimen" }
+ }
+ }
+}
+
+implement {
+ name = "reseteffect",
+ actions = function()
+ if enabled then
+ texsetattribute(a_effect,register())
+ end
+ end
+}
diff --git a/tex/context/base/mkxl/attr-eff.mkxl b/tex/context/base/mkxl/attr-eff.mkxl
index 42aadf9a2..5a50ab60c 100644
--- a/tex/context/base/mkxl/attr-eff.mkxl
+++ b/tex/context/base/mkxl/attr-eff.mkxl
@@ -13,7 +13,7 @@
\writestatus{loading}{ConTeXt Attribute Macros / Effects}
-\registerctxluafile{attr-eff}{}
+\registerctxluafile{attr-eff}{autosuffix}
\unprotect
@@ -22,7 +22,7 @@
\installcommandhandler \??effect {effect} \??effect
\setupeffect
- [\c!method=\v!none,
+ [\c!method=\v!none, % should become command or define or so
\c!stretch=\zerocount,
\c!rulethickness=\zeropoint,
\c!alternative=\v!normal]
diff --git a/tex/context/base/mkxl/attr-mkr.lmt b/tex/context/base/mkxl/attr-mkr.lmt
new file mode 100644
index 000000000..10550d935
--- /dev/null
+++ b/tex/context/base/mkxl/attr-mkr.lmt
@@ -0,0 +1,40 @@
+if not modules then modules = { } end modules ['attr-mkr'] = {
+ version = 1.001,
+ comment = "companion to attr-mkr.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local markers = nodes.markers or { }
+nodes.markers = markers
+
+local cache = { }
+local numbers = attributes.numbers
+local a_unknown = attributes.private("marker:unknown")
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+local setattr = nuts.setattr
+local getattr = nuts.getattr
+
+table.setmetatableindex(cache,function(t,k)
+ local k = "marker:" .. k
+ local v = numbers[k] or a_unknown
+ t[k] = v
+ return v
+end)
+
+function markers.get(n,name)
+ local a = cache[name]
+ if a then
+ getattr(tonut(n),a)
+ end
+end
+
+function markers.set(n,name,v)
+ local a = cache[name]
+ if a then
+ setattr(tonut(n),a,v)
+ end
+end
diff --git a/tex/context/base/mkxl/attr-mkr.mkxl b/tex/context/base/mkxl/attr-mkr.mkxl
index 2209af241..24e0a2319 100644
--- a/tex/context/base/mkxl/attr-mkr.mkxl
+++ b/tex/context/base/mkxl/attr-mkr.mkxl
@@ -15,11 +15,12 @@
\unprotect
-\registerctxluafile{attr-mkr}{}
+\registerctxluafile{attr-mkr}{autosuffix}
\permanent \protected\def\definemarker [#1]{\defineattribute[\s!marker:#1]}
\permanent\tolerant\protected\def\setmarker [#1]#*[#2]{\dosetattribute{\s!marker:#1}{#2}}
\permanent \protected\def\resetmarker [#1]{\dogetattribute{\s!marker:#1}}
-\permanent \def\boxmarker #1#2{attr \numexpr\dogetattributeid{\s!marker:#1}\numexpr \numexpr#2\relax}
+\permanent \def\boxmarker #1#2{attr \numexpr\dogetattributeid{\s!marker:#1}\relax \numexpr#2\relax}
+\permanent \protected\def\marker #1{\numexpr\dogetattributeid{\s!marker:#1}\relax}
\protect \endinput
diff --git a/tex/context/base/mkxl/attr-neg.lmt b/tex/context/base/mkxl/attr-neg.lmt
new file mode 100644
index 000000000..4739b736d
--- /dev/null
+++ b/tex/context/base/mkxl/attr-neg.lmt
@@ -0,0 +1,104 @@
+if not modules then modules = { } end modules ['attr-neg'] = {
+ version = 1.001,
+ comment = "companion to attr-neg.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this module is being reconstructed and code will move to other places
+-- we can also do the nsnone via a metatable and then also se index 0
+
+local format = string.format
+
+local attributes, nodes, utilities, logs, backends = attributes, nodes, utilities, logs, backends
+local commands, context, interfaces = commands, context, interfaces
+local tex = tex
+
+local states = attributes.states
+local enableaction = nodes.tasks.enableaction
+local nodeinjections = backends.nodeinjections
+local texsetattribute = tex.setattribute
+local variables = interfaces.variables
+local allocate = utilities.storage.allocate
+local setmetatableindex = table.setmetatableindex
+
+--- negative / positive
+
+attributes.negatives = attributes.negatives or { }
+local negatives = attributes.negatives
+
+local a_negative = attributes.private("negative")
+
+local v_none = interfaces.variables.none
+
+negatives.data = allocate()
+negatives.attribute = a_negative
+
+negatives.registered = allocate {
+ [variables.positive] = 1,
+ [variables.negative] = 2,
+}
+
+local data = negatives.data
+local registered = negatives.registered
+
+local function extender(negatives,key)
+ if key == "none" then -- v_none then
+ local d = data[1]
+ negatives.none = d
+ return d
+ end
+end
+
+local function reviver(data,n)
+ if n == 1 then
+ local d = nodeinjections.positive() -- called once
+ data[1] = d
+ return d
+ elseif n == 2 then
+ local d = nodeinjections.negative() -- called once
+ data[2] = d
+ return d
+ end
+end
+
+setmetatableindex(negatives, extender)
+setmetatableindex(negatives.data, reviver)
+
+negatives.handler = nodes.installattributehandler {
+ name = "negative",
+ namespace = negatives,
+ initializer = states.initialize,
+ finalizer = states.finalize,
+ processor = states.process,
+}
+
+local function register(stamp)
+ return registered[stamp] or registered.positive
+end
+
+local function enable()
+ enableaction("shipouts","attributes.negatives.handler")
+end
+
+negatives.register = register
+negatives.enable = enable
+
+-- interface
+
+local enabled = false
+
+function negatives.set(stamp)
+ if not enabled then
+ enable()
+ enabled = true
+ end
+ texsetattribute(a_negative,register(stamp))
+end
+
+interfaces.implement {
+ name = "setnegative",
+ actions = negatives.set,
+ arguments = "argument",
+}
diff --git a/tex/context/base/mkxl/attr-neg.mkxl b/tex/context/base/mkxl/attr-neg.mkxl
index c849e6bf6..869ac0b2e 100644
--- a/tex/context/base/mkxl/attr-neg.mkxl
+++ b/tex/context/base/mkxl/attr-neg.mkxl
@@ -13,16 +13,19 @@
\writestatus{loading}{ConTeXt Attribute Macros / Negation}
-\registerctxluafile{attr-neg}{}
+\registerctxluafile{attr-neg}{autosuffix}
\unprotect
+%D This feature is kind of useless because only \ACROBAT\ seems to support it and
+%D even rather complete mupdf based viewers seem to ignore it.
+
% positive and negative are preregistered
-\permanent\protected\def\startnegative{\clf_setnegative{\v!negative}}
-\permanent\protected\def\stopnegative {\clf_setnegative{\v!positive}}
+\permanent\protected\def\startnegative{\clf_setnegative\v!negative}
+\permanent\protected\def\stopnegative {\clf_setnegative\v!positive}
-\permanent\protected\def\startpositive{\clf_setnegative{\v!positive}}
-\permanent\protected\def\stoppositive {\clf_setnegative{\v!negative}}
+\permanent\protected\def\startpositive{\clf_setnegative\v!positive}
+\permanent\protected\def\stoppositive {\clf_setnegative\v!negative}
\protect \endinput
diff --git a/tex/context/base/mkxl/char-tex.lmt b/tex/context/base/mkxl/char-tex.lmt
index 0e0297381..31023136d 100644
--- a/tex/context/base/mkxl/char-tex.lmt
+++ b/tex/context/base/mkxl/char-tex.lmt
@@ -23,6 +23,8 @@ local mark = utilities.storage.mark
local context = context
local commands = commands
+if not characters then require("char-ini") require("char-utf") end
+
local characters = characters
local texcharacters = { }
characters.tex = texcharacters
@@ -401,7 +403,7 @@ if not interfaces then return end
local implement = interfaces.implement
-local pattern
+local pattern1, pattern2
local verbosemarks = characters.verbosemarks
@@ -418,6 +420,7 @@ else
["grave"] = utfchar(0x300),
["acute"] = utfchar(0x301),
["circumflex"] = utfchar(0x302),
+ ["circumflex"] = utfchar(0x302),
["tilde"] = utfchar(0x303),
["macron"] = utfchar(0x304), ["line"] = utfchar(0x304),
["overline"] = utfchar(0x305),
@@ -442,6 +445,7 @@ else
["macron below"] = utfchar(0x331), ["line below"] = utfchar(0x331),
["hook below"] = utfchar(0x1FA9D),
+
}
characters.verbosemarks = verbosemarks
@@ -452,48 +456,68 @@ else
end
-local function prepare()
- pattern = Cs((utfchartabletopattern(verbosemarks) / verbosemarks + lpegpatterns.space/"" + lpegpatterns.utf8character)^0)
- return pattern
+local function prepare1()
+ pattern1 = Cs(
+ (
+P("\\")/"" * (utfchartabletopattern(commandmapping) / commandmapping) * (P(" ")/"")
++ utfchartabletopattern(verbosemarks) / verbosemarks
+ + lpegpatterns.space/""
+ + lpegpatterns.utf8character
+ )^0
+ )
+ return pattern1
+end
+
+local function prepare2()
+ local back = {
+ ["ı"] = "i",
+ ["ȷ"] = "j",
+ }
+ pattern2 = Cs(
+ (
+ utfchartabletopattern(back) / back
+ + lpegpatterns.utf8character
+ )^0
+ )
+ return pattern2
end
local hash = table.setmetatableindex(function(t,k)
- local f = ""
- k = lpegmatch(pattern or prepare(),k) or k
+ local f = k
+ k = lpegmatch(pattern1 or prepare1(),k) or k
+ k = lpegmatch(pattern2 or prepare2(),k) or k
local v = collapse(k) or k -- char specials
--- print("collapse",k,v)
if k ~= v then
goto DONE
end
v = combine(k) or k -- with specials
--- print("combine",k,v)
if k ~= v then
goto DONE
end
v = commandmapping[k] or k
--- print("command",k,v)
if k ~= v then
- f = "\\"
+ f = "\\" .. f
goto DONE
end
v = textoutf(k) or k
--- print("utf",k,v)
if k ~= v then
- f = "\\"
+ f = "\\" .. f
goto DONE
end
::DONE::
- report_defining("instead of old school '%s%s' you can input the utf sequence %s",f,k,v)
+ report_defining("instead of old school '%s' you can input the utf sequence %s",f,v)
t[k] = v
return v
end)
implement {
name = "chr",
- arguments = "argument",
+ -- arguments = "argument", -- not here
+ arguments = "string",
public = true,
actions = function(str)
- context(hash[str]) -- expandable
+ local hsh = hash[str]
+ context(hsh) -- expandable
end
}
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index ef7c40717..9a6fc93da 100644
--- a/tex/context/base/mkxl/cont-new.mkxl
+++ b/tex/context/base/mkxl/cont-new.mkxl
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2023.03.10 12:15}
+\newcontextversion{2023.03.20 15:42}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl
index 8f9513510..1a07772eb 100644
--- a/tex/context/base/mkxl/context.mkxl
+++ b/tex/context/base/mkxl/context.mkxl
@@ -29,7 +29,7 @@
%D {YYYY.MM.DD HH:MM} format.
\immutable\edef\contextformat {\jobname}
-\immutable\edef\contextversion{2023.03.10 12:15}
+\immutable\edef\contextversion{2023.03.20 15:42}
%overloadmode 1 % check frozen / warning
%overloadmode 2 % check frozen / error
@@ -651,11 +651,7 @@
% take a while before we dealt with all of them because I'll also clean them
% up a bit when doing.
%
-% % luat-bas.mkxl l-macro-imp-optimize % this will go away
-
-% c:/data/develop/context/sources/attr-eff.lua
-% c:/data/develop/context/sources/attr-mkr.lua
-% c:/data/develop/context/sources/attr-neg.lua
+% % luat-bas.mkxl l-macro-imp-optimize % this is no longer used
% c:/data/develop/context/sources/buff-imp-default.lua
% c:/data/develop/context/sources/buff-imp-escaped.lua
@@ -791,8 +787,6 @@
% c:/data/develop/context/sources/page-mix.lua
% c:/data/develop/context/sources/page-pst.lua
-% c:/data/develop/context/sources/phys-dim.lua
-
% c:/data/develop/context/sources/publ-aut.lua % shared
% c:/data/develop/context/sources/publ-dat.lua
% c:/data/develop/context/sources/publ-fnd.lua
@@ -837,5 +831,3 @@
% c:/data/develop/context/sources/typo-cln.lua -- wrong name for what it does
% c:/data/develop/context/sources/typo-dha.lua
-
-% c:/data/develop/context/sources/unic-ini.lua
diff --git a/tex/context/base/mkxl/enco-ini.mkxl b/tex/context/base/mkxl/enco-ini.mkxl
index 3d87ee776..dfe534f32 100644
--- a/tex/context/base/mkxl/enco-ini.mkxl
+++ b/tex/context/base/mkxl/enco-ini.mkxl
@@ -74,6 +74,17 @@
\immutable\letcsname\??accents\endcsname\empty
%D Because now have this (\type {\chr} issues a one|-|time warning):
+%D
+%D \stopbuffer
+%D \chr {e acute}
+%D \chr {i circumflex}
+%D \^{i} \^i \^{\i}
+%D \^{a} \"{a}
+%D \withcircumflex{a}
+%D \withdiaeresis{a}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
\permanent\protected\def\dodefinecombine#1#2%
{\ifcsname\string#1\endcsname\else
diff --git a/tex/context/base/mkxl/font-ctx.lmt b/tex/context/base/mkxl/font-ctx.lmt
index 23c676e4e..77953d64a 100644
--- a/tex/context/base/mkxl/font-ctx.lmt
+++ b/tex/context/base/mkxl/font-ctx.lmt
@@ -1383,25 +1383,35 @@ do -- else too many locals
local characters = tfmdata.characters
local parameters = tfmdata.parameters
local properties = tfmdata.properties
- -- we use char0 as signal; cf the spec pdf can handle this (no char in slot)
- characters[0] = nil
- tfmdata.original = specification.specification
- local id = definefont(tfmdata,properties.id)
- csnames[id] = specification.cs
- properties.id = id -- already set
- definers.register(tfmdata,id) -- to be sure, normally already done
- texdefinefont(global,cs,id)
- -- texdefinefont(cs,id,global and "global")
- constructors.finalize(tfmdata)
- if trace_defining then
- report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a",
- name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,"-")
+ if characters then
+ -- we use char0 as signal; cf the spec pdf can handle this (no char in slot)
+ characters[0] = nil
+ tfmdata.original = specification.specification
+ local id = definefont(tfmdata,properties.id)
+ csnames[id] = specification.cs
+ properties.id = id -- already set
+ definers.register(tfmdata,id) -- to be sure, normally already done
+ texdefinefont(global,cs,id)
+ -- texdefinefont(cs,id,global and "global")
+ constructors.finalize(tfmdata)
+ if trace_defining then
+ report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a, step %a",
+ name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,"-")
+ end
+ -- resolved (when designsize is used):
+ local size = round(tfmdata.parameters.size or 655360)
+ setmacro("somefontsize",size.."sp")
+ texsetcount(c_scaledfontsize,size)
+ lastfontid = id
+ else
+ -- case 1: same as **
+ local nice = nice_cs(cs)
+ if not reported[name][nice] then
+ report_defining("unable to define %a as %a",name,nice)
+ end
+ lastfontid = -1
+ texsetcount(c_scaledfontsize,0)
end
- -- resolved (when designsize is used):
- local size = round(tfmdata.parameters.size or 655360)
- setmacro("somefontsize",size.."sp")
- texsetcount(c_scaledfontsize,size)
- lastfontid = id
elseif tfmtype == "number" then
if trace_defining then
report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a",
@@ -1417,6 +1427,7 @@ do -- else too many locals
texsetcount(c_scaledfontsize,size)
lastfontid = tfmdata
else
+ -- case 2: same as **
local nice = nice_cs(cs)
if not reported[name][nice] then
report_defining("unable to define %a as %a",name,nice)
diff --git a/tex/context/base/mkxl/lang-def.mkxl b/tex/context/base/mkxl/lang-def.mkxl
index cd5fd4ba3..04215a779 100644
--- a/tex/context/base/mkxl/lang-def.mkxl
+++ b/tex/context/base/mkxl/lang-def.mkxl
@@ -257,7 +257,7 @@
\installlanguage
[\s!sl]
- [\c!command=\v!no,
+ [\c!define=\v!no,
\c!spacing=\v!packed,
\c!leftsentence=\hbox{\endash\space},
\c!rightsentence=\hbox{\space\endash},
@@ -271,7 +271,7 @@
\installlanguage % for now we copy from slovenian
[\s!sq]
- [\c!command=\v!no,
+ [\c!define=\v!no,
\s!lefthyphenmin=2,
\s!righthyphenmin=2,
\c!spacing=\v!packed,
@@ -284,12 +284,12 @@
\c!leftquotation=\rightguillemot,
\c!rightquotation=\leftguillemot,
\c!date={\v!day,{.},\space,\v!month,\space,\v!year}]
-
+
\installlanguage
[\s!hy]
[\c!spacing=\v!packed,
\c!leftsentence=\endash, % *sentences not confirmed
- \c!rightsentence=\endash,
+ \c!rightsentence=\endash,
\c!leftsubsentence=\endash,
\c!rightsubsentence=\endash,
\c!leftquote=\guilsingleleft,
@@ -613,7 +613,7 @@
\installlanguage
[\s!lt]
- [\c!command=\v!no,
+ [\c!define=\v!no,
\c!spacing=\v!packed,
\c!leftsentence=\emdash,
\c!rightsentence=\emdash,
@@ -755,7 +755,7 @@
\installlanguage
[\s!it]
- [\c!command=\v!no,
+ [\c!define=\v!no,
\c!spacing=\v!packed,
\c!leftsentence=\emdash,
\c!rightsentence=\emdash,
diff --git a/tex/context/base/mkxl/lpdf-xmp.lmt b/tex/context/base/mkxl/lpdf-xmp.lmt
index e147c796f..aec12b22f 100644
--- a/tex/context/base/mkxl/lpdf-xmp.lmt
+++ b/tex/context/base/mkxl/lpdf-xmp.lmt
@@ -346,7 +346,8 @@ local function setupidentity()
pdfaddtoinfo("ConTeXt.Jobname",jobname)
end
--
- pdfaddtoinfo("ConTeXt.Url","www.pragma-ade.com")
+ -- pdfaddtoinfo("ConTeXt.Url","www.pragma-ade.com")
+ pdfaddtoinfo("ConTeXt.Url","github.com/contextgarden/context")
pdfaddtoinfo("ConTeXt.Support","contextgarden.net")
pdfaddtoinfo("TeX.Support","tug.org")
--
diff --git a/tex/context/base/mkxl/math-acc.mklx b/tex/context/base/mkxl/math-acc.mklx
index 49f97ae9c..c3c4a5d34 100644
--- a/tex/context/base/mkxl/math-acc.mklx
+++ b/tex/context/base/mkxl/math-acc.mklx
@@ -92,15 +92,26 @@
\installlocalcurrenthandler \??mathaccents {mathaccent}
+%D \starttyping
+%D \im { \showboxes \showglyphs
+%D \hat{\tilde{\dot{x}}}
+%D }
+%D \im { \showboxes \showglyphs
+%D \hat[align=middle]{\tilde[align=middle]{\dot{x}}}
+%D }
+%D \stoptyping
+
\tolerant\protected\def\math_accent_make_double#class#kind#top#bottom#*[#settings]#:#content%
{\beginmathgroup
\setlocalmathaccentcurrent{#class}% \edef\currentmathaccent{#class}%
\startusemathstyleparameter\mathaccentparameter\c!mathstyle
\setupcurrentmathaccent[#settings]%
- \edef\m_fixed{\ifcstok{\mathaccentparameter\c!stretch}\v!yes\else\s!fixed\fi}%
+ \edef\m_fixed {\ifcstok{\mathaccentparameter\c!stretch}\v!yes \else\s!fixed \space\fi}%
+ \edef\m_center{\ifcstok{\mathaccentparameter\c!align }\v!middle \s!center\space\fi}%
\Umathaccent
\usedcolorparameterattributes{\mathaccentparameter\c!color}%
% nooverflow % there is never na overflow anyway but we do accept thekey
+ \m_center
\ifcase#kind\or
top \m_fixed
\fam\zerocount#top
@@ -170,8 +181,8 @@
%definemathtopaccent[\v!top][overturnedcomma] ["0312]
%definemathtopaccent[\v!top][overcommatopright] ["0315]
%definemathtopaccent[\v!top][leftangleabove] ["031A]
-\definemathtopaccent[\v!top][leftharpoonaccent] ["20D0]
-\definemathtopaccent[\v!top][rightharpoonaccent] ["20D1]
+\definemathtopaccent[\v!top][overleftharpoon] ["20D0]
+\definemathtopaccent[\v!top][overrightharpoon] ["20D1]
%definemathtopaccent[\v!top][verticaloverlayaccent]["20D2]
%definemathtopaccent[\v!top][vec] ["20D7]% We expect vec to stretch, so later
\definemathtopaccent[\v!top][dddot] ["20DB]
@@ -208,7 +219,7 @@
\definemathtopaccent[\v!top:\v!stretch][wideacute]["0301]
\definemathtopaccent[\v!top:\v!stretch][widehat] ["0302]
\definemathtopaccent[\v!top:\v!stretch][widetilde]["0303]
-\definemathtopaccent[\v!top:\v!stretch][widebar] ["0305]%or 305
+\definemathtopaccent[\v!top:\v!stretch][widebar] ["0305]% (not 304, the caret)
\definemathtopaccent[\v!top:\v!stretch][widebreve]["0306]
\definemathtopaccent[\v!top:\v!stretch][widedot] ["0307]
\definemathtopaccent[\v!top:\v!stretch][wideddot] ["0308]
@@ -220,17 +231,17 @@
\definemathtopaccent[\v!top:\v!stretch][wideoverleftharpoon] ["20D0]
\definemathtopaccent[\v!top:\v!stretch][wideoverrightharpoon] ["20D1]
-\definemathtopaccent[\v!top:\v!stretch][wideoverleftarrow] ["20D6]
-\definemathtopaccent[\v!top:\v!stretch][wideoverrightarrow] ["20D7]
+\definemathtopaccent[\v!top:\v!stretch][wideoverleftarrow] ["20D6]
+\definemathtopaccent[\v!top:\v!stretch][wideoverrightarrow] ["20D7]
\definemathtopaccent[\v!top:\v!stretch][wideoverleftrightarrow]["20E1]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideundertilde]["0330]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderbar]["0332]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftrightarrow]["034D]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderrightharpoon]["20EC]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftharpoon]["20ED]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftarrow]["20EE]
-\definemathbottomaccent[\v!bottom:\v!stretch][wideunderrightarrow]["20EF]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideundertilde] ["0330]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderbar] ["0332]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftrightarrow]["034D] % weird code
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderrightharpoon] ["20EC]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftharpoon] ["20ED]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderleftarrow] ["20EE]
+\definemathbottomaccent[\v!bottom:\v!stretch][wideunderrightarrow] ["20EF]
\aliased\let\mathring\ring % for a while
diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt
index a6614aaa5..0c75147f6 100644
--- a/tex/context/base/mkxl/math-act.lmt
+++ b/tex/context/base/mkxl/math-act.lmt
@@ -18,6 +18,7 @@ local type, next, tonumber = type, next, tonumber
local fastcopy, copytable, insert, remove, concat = table.fastcopy, table.copy, table.insert, table.remove, table.concat
local formatters = string.formatters
local byte = string.byte
+local max = math.max
local setmetatableindex, sortedkeys, sortedhash = table.setmetatableindex, table.sortedkeys, table.sortedhash
local lpegmatch = lpeg.match
@@ -45,13 +46,18 @@ local blocks = characters.blocks
local stepper = utilities.parsers.stepper
local helpers = fonts.helpers
-local upcommand = helpers.commands.up
-local downcommand = helpers.commands.down
-local rightcommand = helpers.commands.right
-local leftcommand = helpers.commands.left
-local charcommand = helpers.commands.char
local prependcommands = helpers.prependcommands
+local vfcommands = helpers.commands
+local upcommand = vfcommands.up
+local downcommand = vfcommands.down
+local rightcommand = vfcommands.right
+local leftcommand = vfcommands.left
+local slotcommand = vfcommands.slot
+local charcommand = vfcommands.char
+local push = vfcommands.push
+local pop = vfcommands.pop
+
local sequencers = utilities.sequencers
local appendgroup = sequencers.appendgroup
local appendaction = sequencers.appendaction
@@ -1710,7 +1716,7 @@ do
datasets.accentdimensions = candidates
local function adapt(c,factor,baseheight,basedepth)
--- if not c.tweaked then
+ if not c.tweaked then
local height = c.height or 0
local depth = c.depth or 0
local yoffset = 0
@@ -1736,8 +1742,8 @@ do
c.yoffset = yoffset ~= 0 and yoffset or nil
c.height = height > 0 and height or nil
c.depth = depth > 0 and depth or nil
--- c.tweaked = true
--- end
+ c.tweaked = true
+ end
end
local function process(target,original,characters,list,baseheight,basedepth)
@@ -1806,46 +1812,18 @@ end
do
- local addprivate = fonts.helpers.addprivate
- local privateslot = fonts.helpers.privateslot
-
- -- function mathtweaks.addrules(target,original,parameters)
- -- local characters = target.characters
- -- local height = target.mathparameters.OverbarRuleThickness
- -- local depth = target.mathparameters.UnderbarRuleThickness
- -- local width = target.parameters.emwidth/2
- -- local step = 0.8 * width
- -- characters[0x203E] = { -- over
- -- width = width,
- -- height = height,
- -- depth = 0,
- -- unicode = 0x203E,
- -- commands = { { "rule", height, width } },
- -- parts = {
- -- { advance = width, ["end"] = step, glyph = 0x203E, start = 0 },
- -- { advance = width, ["end"] = 0, glyph = 0x203E, start = step, extender = 1 },
- -- }
- -- }
- -- characters[0x0332] = { -- under
- -- width = width,
- -- height = 0,
- -- depth = depth,
- -- yoffset = -depth,
- -- unicode = 0x0332,
- -- commands = { { "rule", height, width } },
- -- parts = {
- -- { advance = width, ["end"] = step, glyph = 0x0332, start = 0 },
- -- { advance = width, ["end"] = 0, glyph = 0x0332, start = step, extender = 1 },
- -- }
- -- }
- -- end
+ local addprivate = fonts.helpers.addprivate
+ local privateslot = fonts.helpers.privateslot
+ local newprivateslot = fonts.helpers.newprivateslot
function mathtweaks.addrules(target,original,parameters)
local characters = target.characters
local thickness = target.mathparameters.OverbarRuleThickness
local width = target.parameters.emwidth / 2
- local step = 0.8 * width
- characters[0x203E] = { -- over
+ local width = target.parameters.emwidth / 3
+-- local step = 0.8 * width
+ local step = 0.5 * width
+ characters[0x203E] = { -- middle used for all kind
width = width,
height = thickness / 2,
depth = thickness / 2,
@@ -1858,8 +1836,43 @@ do
},
partsorientation = "horizontal",
}
- --
- characters[0x0332] = characters[0x203E]
+ local function build(target,leftarrow,rightarrow)
+ if leftarrow and rightarrow then
+ -- actually the same sort of code as we have for antykwa
+ local left = leftarrow.parts
+ local right = rightarrow.parts
+ if left and right then
+ local leftline = right[1].glyph
+ local rightline = left [#left].glyph
+ local leftdata = characters[leftline]
+ local rightdata = characters[rightline]
+ local leftwidth = leftdata.width
+ local rightwidth = rightdata.width
+ local result = characters[target] -- copytable(leftdata)
+ if not result or result.width == 0 then
+ result = {
+ height = leftdata.height,
+ depth = leftdata.depth,
+ width = 0.9*leftwidth + rightwidth,
+ unicode = target,
+ commands = {
+ slotcommand[0][leftline],
+ leftcommand[0.1*leftwidth],
+ slotcommand[0][rightline],
+ },
+ }
+ characters[target] = result
+ end
+ result.parts = {
+ { advance = leftwidth, glyph = leftline, ["end"] = .9*leftwidth, start = 0 },
+ { advance = rightwidth, glyph = rightline, ["end"] = .1*leftwidth, start = .9*rightwidth, extender = 1 },
+ }
+ result.partsorientation = "horizontal"
+ end
+ end
+ end
+ build(0x305,characters[0x20D6],characters[0x20D7]) -- overbar accent
+ build(0x332,characters[0x20EE],characters[0x20EF]) -- underbar accent
--
-- lucida lacks them ...
--
@@ -1875,11 +1888,16 @@ do
commands = { { "rule", thickness * 2.5, thickness } },
})
characters[0x23B4] = { -- over
- width = width,
+-- width = width,
+ width = 2*thickness+width,
height = half,
depth = double,
unicode = 0x23B4,
- commands = { { "rule", thickness, width } },
+ commands = {
+ slotcommand[0][tpiece],
+ slotcommand[0][0x203E],
+ slotcommand[0][tpiece],
+ },
parts = {
{ advance = thickness, glyph = tpiece, ["end"] = 0, start = half },
{ advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 },
@@ -1896,12 +1914,16 @@ do
yoffset = - half,
commands = { { "rule", thickness * 2.5, thickness } },
})
- characters[0x23B5] = { -- over
- width = width,
+ characters[0x23B5] = { -- under
+ width = 2*thickness+width,
height = double,
depth = half,
unicode = 0x23B5,
- commands = { { "rule", thickness, width } },
+ commands = {
+ slotcommand[0][bpiece],
+ slotcommand[0][0x203E],
+ slotcommand[0][bpiece],
+ },
parts = {
{ advance = thickness, glyph = bpiece, ["end"] = 0, start = half },
{ advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 },
@@ -1913,6 +1935,69 @@ do
--
end
+ -- vfmath.builders.extension(target)
+
+ local rbe = newprivateslot("radical bar extender")
+
+ local function useminus(unicode,characters,parameters)
+ local minus = characters[0x2212]
+ local xoffset = parameters.xoffset or .075
+ local yoffset = parameters.yoffset or .9
+ local xscale = parameters.xscale or 1
+ local yscale = parameters.yscale or 1
+ local xwidth = parameters.width or (1 - 2*xoffset)
+ local xheight = parameters.height or (1 - yoffset)
+ local mheight = minus.height
+ local mwidth = minus.width
+ local height = xheight*mheight
+ local xshift = xoffset * mwidth
+ local yshift = yoffset * mheight
+ local advance = xwidth * mwidth
+ local step = mwidth / 2
+ characters[unicode] = {
+ height = height,
+ depth = height,
+ width = advance,
+ commands = {
+ push,
+ leftcommand[xshift],
+ downcommand[yshift],
+ -- slotcommand[0][0x2212],
+ { "slot", 0, 0x2212, xscale, yscale },
+ pop,
+ },
+ unicode = unicode,
+ -- parts = {
+ -- { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw },
+ -- { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = mw },
+ -- { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = lw },
+ -- },
+ parts = {
+ { extender = 0, glyph = unicode, ["end"] = step, start = 0, advance = advance },
+ { extender = 1, glyph = unicode, ["end"] = step, start = step, advance = advance },
+ },
+ partsorientation = "horizontal",
+ }
+ end
+
+ function mathtweaks.replacerules(target,original,parameters)
+ local characters = target.characters
+ local fraction = parameters.fraction
+ local radical = parameters.radical
+ if fraction then
+ local template = fraction.template
+ if template == 0x2212 or template == "minus" then
+ useminus(0x203E,characters,fraction)
+ end
+ end
+ if radical then
+ local template = radical.template
+ if template == 0x2212 or template == "minus" then
+ useminus(rbe,characters,radical)
+ end
+ end
+ end
+
local force = false experiments.register("math.arrows", function(v) force = v end)
local function tighten(target,unicode,left,right,squeeze,yoffset)
@@ -1947,7 +2032,7 @@ do
if chardata and (force or overloads[unicode] == false or not chardata.parts) then
if not list then
-- chardata.parts = nil -- when we test
- chardata.parts = { { glyph = unicode } }
+-- chardata.parts = { { glyph = unicode } }
else
local overload = overloads[unicode]
local parts = { }
@@ -1982,7 +2067,8 @@ do
end
end
if #parts == #list then
- chardata.parts = parts
+ chardata.parts = parts
+ chardata.partsorientation = "horizontal"
end
end
end
@@ -2259,7 +2345,8 @@ do
local function fix(target,original,characters,u,l)
local data = characters[u]
if data then
- data.innerlocation = l.location == "right" and 2 or 1
+ -- data.innerlocation = l.location == "right" and 2 or 1
+ data.innerlocation = l.location == "right" and "right" or "left"
data.innerxoffset = (l.hfactor or 1) * (data.width or 0)
data.inneryoffset = (l.vfactor or 1) * ((data.height or 0) + (data.depth or 0))
end
@@ -2636,40 +2723,119 @@ do
end
+-- do
+--
+-- local single <const> = 0x003D
+-- local double <const> = 0x2A75
+-- local triple <const> = 0x2A76
+--
+-- function mathtweaks.addequals(target,original,parameters)
+-- local characters = target.characters
+-- local basechar = characters[single]
+-- local width = basechar.width
+-- local height = basechar.height
+-- local depth = basechar.depth
+-- local advance = (parameters.advance or 1/20) * width
+-- local char = charcommand[single]
+-- local left = leftcommand[advance]
+-- characters[double] = {
+-- unicode = double,
+-- width = 2*width - 1*advance,
+-- height = height,
+-- depth = depth,
+-- commands = { char, left, char },
+-- }
+-- characters[triple] = {
+-- unicode = triple,
+-- width = 3*width - 2*advance,
+-- height = height,
+-- depth = depth,
+-- commands = { char, left, char, left, char },
+-- }
+-- if trace_tweaking then
+-- report_tweak("double %U and triple %U equals added",target,original,double,triple)
+-- end
+-- end
+--
+-- end
+
do
- local single <const> = 0x003D
- local double <const> = 0x2A75
- local triple <const> = 0x2A76
+ local function jointwo(characters,force,unicode,ds,u1,d12,u2)
+ if force or not characters[unicode] then
+ local c1 = characters[u1]
+ local c2 = characters[u2]
+ if c1 and c2 then
+ local w1 = c1.width
+ local w2 = c2.width
+ local width
+ if d12 == false then
+ d12 = 0
+ width = w2
+ elseif d12 < 0 then
+ d12 = d12 * w2
+ width = w2
+ else
+ d12 = d12 * ds
+ width = w1 + w2 - d12
+ end
+ characters[unicode] = {
+ unicode = unicode,
+ width = width,
+ height = max(c1.height or 0, c2.height or 0),
+ depth = max(c1.depth or 0, c2.depth or 0),
+keepvirtual = true,
+ commands = {
+ -- { "inspect" },
+ -- { "trace" },
+ slotcommand[0][u1],
+ -- { "trace" },
+ d12 ~= 0 and leftcommand[d12] or false,
+ slotcommand[0][u2],
+ -- { "trace" },
+ },
+ }
+ end
+ end
+ end
+
+ local function jointhree(characters,force,unicode,ds,u1,d12,u2,d23,u3)
+ if force or not characters[unicode] then
+ local c1 = characters[u1]
+ local c2 = characters[u2]
+ local c3 = characters[u3]
+ if c1 and c2 and c3 then
+ local w1 = c1.width
+ local w2 = c2.width
+ local w3 = c3.width
+ d12 = d12 * ds
+ d23 = d23 * ds
+ characters[unicode] = {
+ unicode = unicode,
+ width = w1 + w2 + w3 - d12 - d23,
+ height = max(c1.height or 0, c2.height or 0, c3.height or 0),
+ depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0),
+ commands = {
+ slotcommand[0][u1],
+ d12 ~= 0 and leftcommand[d12] or false,
+ slotcommand[0][u2],
+ d23 ~= 0 and leftcommand[d23] or false,
+ slotcommand[0][u3],
+ }
+ }
+ end
+ end
+ end
function mathtweaks.addequals(target,original,parameters)
local characters = target.characters
- local basechar = characters[single]
- local width = basechar.width
- local height = basechar.height
- local depth = basechar.depth
- local advance = (parameters.advance or 1/20) * width
- local char = charcommand[single]
- local left = leftcommand[advance]
- characters[double] = {
- unicode = double,
- width = 2*width - 1*advance,
- height = height,
- depth = depth,
--- callback = "devirtualize",
- commands = { char, left, char },
- }
- characters[triple] = {
- unicode = triple,
- width = 3*width - 2*advance,
- height = height,
- depth = depth,
--- callback = "devirtualize",
- commands = { char, left, char, left, char },
- }
- if trace_tweaking then
- report_tweak("double %U and triple %U equals added",target,original,double,triple)
- end
+ local step = target.parameters.size/18
+ local force = parameters.force
+force = true
+ jointwo (characters,force,0x2254,step,0x03A,0,0x03D) -- :=
+ jointhree(characters,force,0x2A74,step,0x03A,0,0x03A,0,0x03D) -- ::=
+ jointwo (characters,force,0x2A75,step,0x03D,0,0x03D) -- ==
+ jointhree(characters,force,0x2A76,step,0x03D,0,0x03D,0,0x03D) -- ===
end
end
@@ -2807,28 +2973,45 @@ do
{ 0x030A, nps("delimited right ring"), nps("delimited ghost ring") },
{ 0x0303, nps("delimited right tilde"), nps("delimited ghost tilde") },
{ 0x20DB, nps("delimited right dddot"), nps("delimited ghost dddot") },
+
+ { 0x231C, nps("delimited left upper corner"), nps("delimited ghost upper corner") },
+ { 0x231D, nps("delimited right upper corner"), nps("delimited ghost upper corner") },
+ { 0x231E, nps("delimited left lower corner"), nps("delimited ghost lower corner"), true },
+ { 0x231F, nps("delimited right lower corner"), nps("delimited ghost lower corner"), true },
+
+ -- If needed we can have an installer:
+
{ 0x2020, nps("delimited right dagger"), nps("delimited ghost dagger") },
{ 0x2021, nps("delimited right ddagger"), nps("delimited ghost ddagger") },
{ 0x2217, nps("delimited right ast"), nps("delimited ghost ast") },
{ 0x22C6, nps("delimited right star"), nps("delimited ghost star") },
- { 0x231C, nps("delimited left upper corner"), nps("delimited ghost upper corner") },
- { 0x231D, nps("delimited right upper corner"), nps("delimited ghost upper corner") },
- { 0x231E, nps("delimited left lower corner"), nps("delimited ghost lower corner"), true },
- { 0x231F, nps("delimited right lower corner"), nps("delimited ghost lower corner"), true },
+ { 0x2020, nps("delimited right dagger 1"), nps("delimited ghost dagger 1"), false, 1 },
+ { 0x2021, nps("delimited right ddagger 1"), nps("delimited ghost ddagger 1"), false, 1 },
+ { 0x2217, nps("delimited right ast 1"), nps("delimited ghost ast 1"), false, 1 },
+ { 0x22C6, nps("delimited right star 1"), nps("delimited ghost star 1"), false, 1 },
}
function mathtweaks.addfourier(target,original,parameters)
local characters = target.characters
for i=1,#list do
- local entry = list[i]
- local basecode = entry[1]
- local fouriercode = entry[2]
- local movecode = entry[3]
- local reverse = entry[4]
- local basechar = characters[basecode]
+ local entry = list[i]
+ local basecode = entry[1]
+ local fouriercode = entry[2]
+ local movecode = entry[3]
+ local reverse = entry[4]
+ local size = entry[5] or 0
+ local basechar = characters[basecode]
+ local compactscale = 1
+ if basechar and target.properties.compactmath and size > 0 then
+ compactscale = target.parameters[size > 1 and "scriptscriptscale" or "scriptscale"] / 1000
+ for i=1,size do
+ basecode = basechar.smaller or basecode
+ basechar = characters[basecode]
+ end
+ end
if basechar then
- local scale = parameters.scale or 1
+ local scale = (parameters.scale or 1) * compactscale
local variant = parameters.variant
if variant then
for i=1,variant do
@@ -2846,9 +3029,9 @@ do
local basewidth = scale * (basechar.width or 0)
local used = baseheight/2
local total = baseheight + basedepth
-if reverse then
- used = total / 2 -- basedepth / 2
-end
+ if reverse then
+ used = total / 2 -- basedepth / 2
+ end
characters[movecode] = {
width = basewidth,
height = used,
@@ -3126,6 +3309,45 @@ end
do
+ function mathtweaks.sortvariants(target,original,parameters)
+ local list = parameters.list
+ if list then
+ local characters = target.characters
+ local horizontal = parameters.orientation == "horizontal"
+ for i=1,#list do
+ local u = list[i]
+ local c = characters[u]
+ if c then
+ local t = { }
+ while true do
+ local n = c.next
+ if n then
+ c = characters[n]
+ end
+ if c and not c.parts then
+ if horizontal then
+ t[c.width or 0] = n
+ else
+ t[(c.height or 0) + (c.depth or 0)] = n
+ end
+ else
+ break
+ end
+ end
+ local c = characters[u]
+ for k, v in sortedhash(t) do
+ c.next = v
+ c = characters[v]
+ end
+ end
+ end
+ end
+ end
+
+end
+
+do
+
-- We started with the list that xits has in rtlm but most of them can be derived from
-- the database, and others need to be added.
@@ -3251,7 +3473,11 @@ do
end
local next = data.next
if next then
- add(target,original,characters,next,"next")
+ if next == unicode then
+ report_tweak("skipping cyclic %U (%s)",target,original,unicode,"next")
+ else
+ add(target,original,characters,next,"next")
+ end
end
end
end
@@ -3462,6 +3688,7 @@ do
local feature = entry.feature
local thesource = entry.source
local thetarget = entry.target or thesource
+ local keep = (entry.keep == true) or (parameters.keep == true)
if thesource and thetarget then
local sourcerange = type(thesource) == "table" and thesource or blocks[thesource] -- .gaps
local targetrange = type(thetarget) == "table" and thetarget or blocks[thetarget] -- .gaps
@@ -3504,13 +3731,17 @@ do
local sourceunicode = mathgaps[s] or s
if chars[sourceunicode] then
local targetunicode = mathgaps[t] or t
- if feature then
- sourceunicode = getsubstitution(dropin,sourceunicode,feature,true,"math","dflt") or sourceunicode
+ if keep and characters[targetunicode] then
+ -- okay
+ else
+ if feature then
+ sourceunicode = getsubstitution(dropin,sourceunicode,feature,true,"math","dflt") or sourceunicode
+ end
+-- if trace_tweaking then
+-- report_tweak("copying %s %U from file %a to %s %U",target,original,thesource,sourceunicode,filename,thetarget,targetunicode)
+-- end
+ characters[targetunicode] = copiedglyph(target,characters,chars,sourceunicode,index)
end
--- if trace_tweaking then
--- report_tweak("copying %s %U from file %a to %s %U",target,original,thesource,sourceunicode,filename,thetarget,targetunicode)
--- end
- characters[targetunicode] = copiedglyph(target,characters,chars,sourceunicode,index)
end
end
--
diff --git a/tex/context/base/mkxl/math-def.mkxl b/tex/context/base/mkxl/math-def.mkxl
index a423a6a79..b2b8d776f 100644
--- a/tex/context/base/mkxl/math-def.mkxl
+++ b/tex/context/base/mkxl/math-def.mkxl
@@ -139,36 +139,58 @@
%D \formula {A \simcoloncolon B}
%D \stoplines
%D
-%D The next macros take care of the space between the colon and the
-%D relation symbol.
+%D The next macros take care of the space between the colon and the relation symbol,
+%D but they are kind of weird and not in \UNICODE. Either we define them virtual or
+%D we just keep these as bonus.
\pushoverloadmode
-\definemathcommand [colonsep] {\mkern-1.2mu}
-\definemathcommand [doublecolonsep] {\mkern-0.9mu}
-
-\definemathcommand [centercolon] [\s!relation] {\mathstylevcenteredhbox\colon}
-\definemathcommand [colonminus] [\s!relation] {\centercolon\colonsep\mathrel{-}}
-%definemathcommand [minuscolon] [\s!relation] {\mathrel{-}\colonsep\centercolon} % native char
-%definemathcommand [colonequals] [\s!relation] {\centercolon\colonsep=} % native char
-%definemathcommand [equalscolon] [\s!relation] {=\centercolon\colonsep} % native char
-\definemathcommand [colonapprox] [\s!relation] {\centercolon\colonsep\approx}
-\definemathcommand [approxcolon] [\s!relation] {\approx\centercolon\colonsep}
-\definemathcommand [colonsim] [\s!relation] {\centercolon\colonsep\sim}
-\definemathcommand [simcolon] [\s!relation] {\sim\centercolon\colonsep}
-
-\definemathcommand [coloncolon] [\s!relation] {\centercolon\doublecolonsep\centercolon}
-\definemathcommand [coloncolonminus] [\s!relation] {\coloncolon\colonsep\mathrel{-}}
-\definemathcommand [minuscoloncolon] [\s!relation] {\mathrel{-}\colonsep\coloncolon}
-\definemathcommand [coloncolonequals] [\s!relation] {\coloncolon\colonsep=} % native char
-\definemathcommand [equalscoloncolon] [\s!relation] {=\coloncolon\colonsep}
-\definemathcommand [coloncolonapprox] [\s!relation] {\coloncolon\colonsep\approx}
-\definemathcommand [approxcoloncolon] [\s!relation] {\approx\coloncolon\colonsep}
-\definemathcommand [coloncolonsim] [\s!relation] {\coloncolon\colonsep\sim}
-\definemathcommand [simcoloncolon] [\s!relation] {\sim\coloncolon\colonsep}
+\protected\def\math_relation_atom_ordinary{\mathatom \s!class \mathrelationcode \s!all \mathordcode}
+
+\definemathcommand [centercolon] {\math_relation_atom_ordinary{\colon}}
+\definemathcommand [colonminus] {\math_relation_atom_ordinary{\colon\minus}}
+\definemathcommand [colonapprox] {\math_relation_atom_ordinary{\colon\approx}}
+\definemathcommand [approxcolon] {\math_relation_atom_ordinary{\approx\colon}}
+\definemathcommand [colonsim] {\math_relation_atom_ordinary{\colon\sim}}
+\definemathcommand [simcolon] {\math_relation_atom_ordinary{\sim\colon}}
+
+\definemathcommand [coloncolon] {\math_relation_atom_ordinary{\colon\colon}}
+\definemathcommand [coloncolonminus] {\math_relation_atom_ordinary{\colon\colon\minus}}
+\definemathcommand [minuscoloncolon] {\math_relation_atom_ordinary{\minus\colon\colon}}
+\definemathcommand [coloncolonequals] {\math_relation_atom_ordinary{\colon\colon\eq}} % native char
+\definemathcommand [equalscoloncolon] {\math_relation_atom_ordinary{\eq\colon\colon}}
+\definemathcommand [coloncolonapprox] {\math_relation_atom_ordinary{\colon\colon\approx}}
+\definemathcommand [approxcoloncolon] {\math_relation_atom_ordinary{\approx\colon\colon}}
+\definemathcommand [coloncolonsim] {\math_relation_atom_ordinary{\colon\colon\sim}}
+\definemathcommand [simcoloncolon] {\math_relation_atom_ordinary{\sim\colon\colon}}
+
+% \definemathcommand [manycolons] [relation] [ordinary] {\colon\colon\colon\colon\colon\colon\colon}
\popoverloadmode
+%D \macros
+%D {amedian}
+%D
+%D Something language specific, the arithmic median:
+%D
+%D \starttyping
+%D \im {x + \amedian {x - a} + x}
+%D \mainlanguage[cs] \im {x + \amedian {x - a} + x}
+%D \stoptyping
+
+\defcsname \s!en:amedian\endcsname#1{\widebar {#1}}
+\defcsname \s!cs:amedian\endcsname#1{\widetilde{#1}}
+\defcsname \s!sk:amedian\endcsname#1{\widetilde{#1}}
+
+\permanent\protected\def\amedian
+ {\csname
+ \ifcsname\currentmainlanguage:amedian\endcsname
+ \currentmainlanguage\else
+ \s!en
+ \fi
+ :amedian%
+ \endcsname}
+
% \appendtoks
% \def\over{\primitive\over}%
% \to \everymathematics
diff --git a/tex/context/base/mkxl/math-dld.mklx b/tex/context/base/mkxl/math-dld.mklx
index dcbb17c5e..281ccedb2 100644
--- a/tex/context/base/mkxl/math-dld.mklx
+++ b/tex/context/base/mkxl/math-dld.mklx
@@ -28,7 +28,8 @@
\installcommandhandler \??mathdelimited {mathdelimited} \??mathdelimited
\setupmathdelimited
- [\c!alternative=\v!normal,
+ [\c!define=\v!yes,
+ \c!alternative=\v!normal,
\c!mpoffset=.25\exheight,
\c!topoffset=\zeropoint,
\c!bottomoffset=\zeropoint,
@@ -43,7 +44,7 @@
\c!rightmargin=\zeropoint]
\appendtoks
- \ifcstok{\mathdelimitedparameter\c!rightmargin}\v!no\else
+ \ifcstok{\mathdelimitedparameter\c!define}\v!yes
\frozen\protected\instance\edefcsname\currentmathdelimited\endcsname{\math_delimited_handle{\currentmathdelimited}}
\fi
\to \everydefinemathdelimited
@@ -70,7 +71,7 @@
\s!depth \dimexpr\mathdelimitedparameter\c!depth+\mathdelimitedparameter\c!bottomoffset\relax
\s!source\numexpr\namedboxanchor{\mathdelimitedparameter\c!source}\relax
\s!style \normalmathstyle
- \s!size \numexpr\namedboxanchor{\mathdelimitedparameter\c!size}\relax
+ \s!size \numexpr\mathdelimitedparameter\c!size\relax
\zerocount \mathdelimitedparameter\c!left
\zerocount \mathdelimitedparameter\c!right
\relax}
@@ -88,7 +89,6 @@
{\popcolor#body}%
\fi}
-
%integerdef\delimitedrightgraveuc \privatecharactercode{delimited right grave}
\integerdef\delimitedrightddotuc \privatecharactercode{delimited right ddot}
\integerdef\delimitedrightbaruc \privatecharactercode{delimited right bar}
@@ -100,10 +100,6 @@
\integerdef\delimitedrightringuc \privatecharactercode{delimited right ring}
\integerdef\delimitedrighttildeuc \privatecharactercode{delimited right tilde}
\integerdef\delimitedrightdddotuc \privatecharactercode{delimited right dddot}
-\integerdef\delimitedrightdaggeruc \privatecharactercode{delimited right dagger}
-\integerdef\delimitedrightddaggeruc \privatecharactercode{delimited right ddagger}
-\integerdef\delimitedrightastuc \privatecharactercode{delimited right ast}
-\integerdef\delimitedrightstaruc \privatecharactercode{delimited right star}
% \integerdef\delimitedrighthatuc \privatecharactercode{delimited right hat}
% \integerdef\delimitedrighttildeuc \privatecharactercode{delimited right tilde}
@@ -114,33 +110,38 @@
\definemathdelimited
[marked]
- [\c!command=\v!no,
+ [\c!define=\v!no,
\c!topoffset=.2\exheight]
\definemathdelimited
[ddotmarked]
[marked]
- [\c!right=\delimitedrightddotuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightddotuc]
\definemathdelimited
[barmarked]
[marked]
- [\c!right=\delimitedrightbaruc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightbaruc]
\definemathdelimited
[hatmarked]
[marked]
- [\c!right=\delimitedrighthatuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrighthatuc]
\definemathdelimited
[checkmarked]
[marked]
- [\c!right=\delimitedrightcheckuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightcheckuc]
\definemathdelimited
[brevemarked]
[marked]
- [\c!right=\delimitedrightbreveuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightbreveuc]
\definemathdelimited
[dotmarked]
@@ -150,44 +151,78 @@
\definemathdelimited
[ringmarked]
[marked]
- [\c!right=\delimitedrightringuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightringuc]
\definemathdelimited
[tildemarked]
[marked]
- [\c!right=\delimitedrighttildeuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrighttildeuc]
\definemathdelimited
[dddotmarked]
[marked]
- [\c!right=\delimitedrightdddotuc]
+ [\c!define=\v!yes,
+ \c!right=\delimitedrightdddotuc]
% The following ones are
% not really belonging here,
% but convenient
+% If there are more needed we can have:
+%
+% \c!ight=\privatecharactercode{delimited right dagger \mathdelimitedparameter\c!size}
+%
+% or even:
+%
+% \def\privatedelimitedcode#1{\privatecharactercode{delimited #1 \mathdelimitedparameter\c!size}}
+%
+% \c!right=\privatedelimitedcode{right dagger}
+%
+% with some glyph installer btu let's for now save some bytes in the format.
+
+\integerdef\delimitedrightdaggeruc \privatecharactercode{delimited right dagger}
+\integerdef\delimitedrightddaggeruc \privatecharactercode{delimited right ddagger}
+\integerdef\delimitedrightastuc \privatecharactercode{delimited right ast}
+\integerdef\delimitedrightstaruc \privatecharactercode{delimited right star}
+
+\integerdef\delimitedscriptrightdaggeruc \privatecharactercode{delimited right dagger 1}
+\integerdef\delimitedscriptrightddaggeruc \privatecharactercode{delimited right ddagger 1}
+\integerdef\delimitedscriptrightastuc \privatecharactercode{delimited right ast 1}
+\integerdef\delimitedscriptrightstaruc \privatecharactercode{delimited right star 1}
+
\definemathdelimited
[daggermarked]
[marked]
- [\c!size=1,
- \c!right=\delimitedrightdaggeruc]
+ [\c!define=\v!yes,
+ \c!size=1,
+ \c!right=\delimitedscriptrightdaggeruc]
+ %\c!right=\privatedelimitedcode{right dagger}]
\definemathdelimited
[ddaggermarked]
[marked]
- [\c!size=1,
- \c!right=\delimitedrightddaggeruc]
+ [\c!define=\v!yes,
+ \c!size=1,
+ \c!right=\delimitedscriptrightddaggeruc]
+ %\c!right=\privatedelimitedcode{right ddagger}]
\definemathdelimited
[astmarked]
- [\c!size=1,
- \c!right=\delimitedrightastuc]
+ [marked]
+ [\c!define=\v!yes,
+ \c!size=1,
+ \c!right=\delimitedscriptrightastuc]
+ %\c!right=\privatedelimitedcode{right ast}]
\definemathdelimited
[starmarked]
[marked]
- [\c!size=1,
- \c!right=\delimitedrightstaruc]
+ [\c!define=\v!yes,
+ \c!size=1,
+ \c!right=\delimitedscriptrightstaruc]
+ %\c!right=\privatedelimitedcode{right star}]
% More contextual
diff --git a/tex/context/base/mkxl/math-fen.mkxl b/tex/context/base/mkxl/math-fen.mkxl
index 1656f4b4a..a69cafb97 100644
--- a/tex/context/base/mkxl/math-fen.mkxl
+++ b/tex/context/base/mkxl/math-fen.mkxl
@@ -15,7 +15,7 @@
\unprotect
-% \definemathfence [fancybracket] [bracket] [command=yes,color=blue]
+% \definemathfence [fancybracket] [bracket] [define=yes,color=blue]
%
% test $|x|$ test \par
% test $||x||$ test (okay) \par
@@ -42,7 +42,7 @@
\c!middle=,
\c!mathstyle=,
\c!color=,
- \c!command=,
+ \c!define=, % was \c!command
\c!mathclass=,
\c!leftclass=\mathopencode,
\c!rightclass=\mathclosecode,
@@ -59,9 +59,7 @@
\c!factor=\v!auto]
\appendtoks
- \edef\p_command{\mathfenceparameter\c!command}%
- \ifx\p_command\v!yes
- % \instance
+ \ifcstok{\mathfenceparameter\c!define}\v!yes
\protected\edefcsname\currentmathfence\endcsname{\math_fenced_fenced{\currentmathfence}}%
\fi
\to \everydefinemathfence
@@ -338,6 +336,19 @@
% \definemathfence [tupdownarrows] [text] [\c!left="2191,\c!right="2193]
+\def\math_fenced_check#1%
+ {\iftok{\mathfenceparameter#1}\emptytoks\letmathfenceparameter#1\v!none\fi}
+
+\appendtoks
+ \math_fenced_check\c!left
+ \math_fenced_check\c!right
+\to \everysetupmathfence
+
+\appendtoks
+ \math_fenced_check\c!left
+ \math_fenced_check\c!right
+\to \everydefinemathfence
+
\protected\def\math_fenced_horizontal_common#1#2#3#4% \Uwhatever class symbol source
{\c_math_fenced_class\math_class_by_parameter\mathfenceparameter#2\relax
\edef\p_fence{#3}%
@@ -387,7 +398,7 @@
\setupmathfence
[\v!text]
[\c!text=\v!yes,
- \c!command=\v!yes,
+ \c!define=\v!yes,
\c!distance=.125\emwidth]
\tolerant\protected\def\math_fenced_vertical#1#*[#2]%
@@ -653,10 +664,23 @@
\immutable\protected\def\Lopenbracketmirrored {\math_fenced_fenced_stop {mirroredopenbracket}} \immutable\protected\def\Ropenbracketmirrored {\math_fenced_fenced_start{mirroredopenbracket}}
\immutable\protected\def\Lnothingmirrored {\math_fenced_fenced_stop {mirrorednothing}} \immutable\protected\def\Rnothingmirrored {\math_fenced_fenced_start{mirrorednothing}}
-\definemathfence [interval] [\c!left="2997,\c!right="2998]
-\definemathfence [openinterval] [interval] [\c!left="2998,\c!right="2998]
-\definemathfence [leftopeninterval] [interval] [\c!left="2997,\c!right="2997]
-\definemathfence [rightopeninterval] [interval] [\c!left="2998,\c!right="2998]
+% These tortoise chars almost only exist in stix (and ar not commonly used)
+
+% \definemathfence [interval] [\c!left="2997,\c!right="2998]
+% \definemathfence [openinterval] [interval] [\c!left="2998,\c!right="2998]
+% \definemathfence [leftopeninterval] [interval] [\c!left="2997,\c!right="2997]
+% \definemathfence [rightopeninterval] [interval] [\c!left="2998,\c!right="2998]
+
+% Different intervals. The variants are the ones suggested by Bourbaki.
+
+\definemathfence [interval] [\c!left="005B,\c!right="005D]
+\definemathfence [openinterval] [interval] [\c!left="0028,\c!right="0029]
+\definemathfence [closedinterval] [interval] [\c!left="005B,\c!right="005D]
+\definemathfence [leftopeninterval] [interval] [\c!left="0028,\c!right="005D]
+\definemathfence [rightopeninterval] [interval] [\c!left="005B,\c!right="0029]
+\definemathfence [varopeninterval] [interval] [\c!left="005D,\c!right="005B]
+\definemathfence [varleftopeninterval] [interval] [\c!left="005D,\c!right="005D]
+\definemathfence [varrightopeninterval] [interval] [\c!left="005B,\c!right="005B]
\immutable\protected\def\Linterval {\math_fenced_fenced_start{interval}}
\immutable\protected\def\Lointerval {\math_fenced_fenced_start{openinterval}}
@@ -1004,7 +1028,7 @@
% \vrule height 3cm depth 3cm
% \right\rintegral
-%definemathfence [fancybracket] [bracket] [command=yes,color=red]
+%definemathfence [fancybracket] [bracket] [define=yes,color=red]
%D The nested fences recovery code is needed for mathml and the original
%D code can still be found in the mkiv file.
@@ -1211,10 +1235,10 @@
% $x + \tdownuparrows{left}{right} + x$
% $x + \tupanddownarrows[color=red,leftcolor=green,rightcolor=blue]{left}{right} + x$
-\definemathfence [tupanddownarrows] [\v!text] [\c!left="2191,\c!right="2193]
-\definemathfence [tupdownarrows] [\v!text] [\c!left="21C5,\c!right=0]
-\definemathfence [tdownuparrows] [\v!text] [\c!middle="21F5]
-\definemathfence [tuparrow] [\v!text] [\c!middle="2191]
-\definemathfence [tdownarrow] [\v!text] [\c!middle="2193]
+\definemathfence [tupanddownarrows][\v!text][\c!left="2191,\c!right="2193]
+\definemathfence [tupdownarrows] [\v!text][\c!left="21C5,\c!right=0]
+\definemathfence [tdownuparrows] [\v!text][\c!middle="21F5]
+\definemathfence [tuparrow] [\v!text][\c!middle="2191]
+\definemathfence [tdownarrow] [\v!text][\c!middle="2193]
\protect
diff --git a/tex/context/base/mkxl/math-ini.mkxl b/tex/context/base/mkxl/math-ini.mkxl
index 7d0c8ef81..8c0615eb6 100644
--- a/tex/context/base/mkxl/math-ini.mkxl
+++ b/tex/context/base/mkxl/math-ini.mkxl
@@ -1732,6 +1732,9 @@
\permanent\protected\def\mathcodecommand#1%
{\mathatom \s!class \mathcodechecked{#1}}
+\permanent\protected\def\mathcodeallcommand#1#2%
+ {\mathatom \s!class \mathcodechecked{#1} \s!all \mathcodechecked{#2}}
+
\def\math_class_by_parameter #1#2{\normalexpanded{\noexpand\mathcodechecked{#1#2}}}
\def\math_atom_by_parameter #1{\normalexpanded{\noexpand\math_atom_by_parameter_indeed{#1\c!mathclass}}}
\def\math_atom_by_parameter_indeed#1{\mathatom \s!class \mathcodechecked{#1}}
@@ -1750,15 +1753,14 @@
\installcorenamespace{mathcommand}
-% todo: define these commands as frozen!
-
\permanent\tolerant\protected\def\definemathcommand[#1]#*[#2]#*[#3]#:#*#4% command class args meaning
{\ifparameter#3\or
- \edef\scratchstringone{#3}% make this one m_arguments
- \ifx\scratchstringone\v!one
+ \ifcstok{#3}\v!one
\frozen\protected\defcsname\??mathcommand#1\endcsname##1{\mathcodecommand{#2}{#4{##1}}}%
- \orelse\ifx\scratchstringone\v!two
+ \orelse\ifcstok{#3}\v!two
\frozen\protected\defcsname\??mathcommand#1\endcsname##1##2{\mathcodecommand{#2}{#4{##1}{##2}}}%
+ \orelse\ifchknum\mathcodechecked{#3}\or
+ \frozen\protected\defcsname\??mathcommand#1\endcsname{\mathcodeallcommand{#2}{#3}{#4}}%
\else
\frozen\protected\defcsname\??mathcommand#1\endcsname{\mathcodecommand{#2}{#4}}%
\fi
diff --git a/tex/context/base/mkxl/math-rad.mklx b/tex/context/base/mkxl/math-rad.mklx
index 703481c08..863bb2128 100644
--- a/tex/context/base/mkxl/math-rad.mklx
+++ b/tex/context/base/mkxl/math-rad.mklx
@@ -195,8 +195,8 @@
\zerocount
\fi
\Urooted
- \s!height\dimexpr\mathradicalparameter\c!height\relax
- \s!depth \dimexpr\mathradicalparameter\c!depth\relax
+ \s!height\dimexpr\ifcstok{\mathradicalparameter\c!height}\v!none\scaledpoint\else\mathradicalparameter\c!height\fi\relax
+ \s!depth \dimexpr\ifcstok{\mathradicalparameter\c!depth }\v!none\scaledpoint\else\mathradicalparameter\c!depth \fi\relax
\s!source\numexpr\namedboxanchor{\mathradicalparameter\c!source}\relax
\s!style \normalmathstyle
\ifzeronum\scratchcounter\else
diff --git a/tex/context/base/mkxl/math-spa.lmt b/tex/context/base/mkxl/math-spa.lmt
index 9875f8b2d..d2927ff58 100644
--- a/tex/context/base/mkxl/math-spa.lmt
+++ b/tex/context/base/mkxl/math-spa.lmt
@@ -47,6 +47,9 @@ local nextlist = nuts.traversers.list
local nextboundary = nuts.traversers.boundary
local nextnode = nuts.traversers.node
+local insertafter = nuts.insertafter
+local newkern = nuts.pool.kern
+
local texsetdimen = tex.setdimen
local texgetdimen = tex.getdimen
local texsetcount = tex.setcount
@@ -83,42 +86,6 @@ local function moveon(s)
return s
end
--- stages[1] = function(specification,stage)
--- local box = getbox(specification.box)
--- local head = getlist(box)
--- local align = specification.alignstate
--- local distance = specification.distance
--- for s in nextboundary, head do
--- local data = getdata(s)
--- if data == boundary then
--- -- todo: skip over ghost, maybe penalty, maybe glues all in one loop
--- s = moveon(s)
--- for n, id, subtype in nextnode, getnext(s) do
--- s = n
--- if id == kern_code then
--- -- move on (s_2 case)
--- elseif id == glue_code then
--- -- move on
--- elseif id == penalty_code then
--- -- move on (untested)
--- elseif id == hlist_code and subtype == ghost_code then
--- -- move on
--- else
--- break
--- end
--- end
--- distance = distance + getdimensions(head,s)
--- break
--- end
--- end
--- texsetdimen("global",d_strc_math_indent,distance)
--- if align == 2 then
--- for n in nextglue, head do
--- setglue(n,getwidth(n),0,0,0,0)
--- end
--- end
--- end
-
-- -- todo: skip over ghost, maybe penalty, maybe glues all in one loop
--
-- local n = getnext(s)
@@ -175,12 +142,11 @@ stages[1] = function(specification,stage)
local f = found[1]
local delta = f[2] - max
if delta ~= 0 then
- nuts.insertafter(head,moveon(head),nuts.pool.kern(-delta))
+ insertafter(head,moveon(head),newkern(-delta))
end
for i=2,#found do
local f = found[i]
- local delta = f[2] - max
- nuts.insertafter(head,moveon(f[3]),nuts.pool.kern(-f[2])) -- check head
+ insertafter(head,moveon(f[3]),newkern(-f[2])) -- check head
end
end
texsetdimen("global",d_strc_math_indent,max)
diff --git a/tex/context/base/mkxl/math-stc.mklx b/tex/context/base/mkxl/math-stc.mklx
index 5922fb116..fdad71978 100644
--- a/tex/context/base/mkxl/math-stc.mklx
+++ b/tex/context/base/mkxl/math-stc.mklx
@@ -78,47 +78,35 @@
% At some point we can consider to use the more natural \LUAMETATEX\ features but the
% problem is that we lack proper support in fonts and we also have less control.
-\installcorenamespace {mathextensiblefallbacks}
+%installcorenamespace {mathextensiblefallbacks}
-% currently no italic correction ... problem is that we don't know yet if we have an italic
-% below so we we need to postpone
-
-% \def\math_stackers_fallback
-% {\hbox to \scratchwidth{\csname\??mathextensiblefallbacks\ifcsname\??mathextensiblefallbacks\number\scratchunicode\endcsname\number\scratchunicode\fi\endcsname}}
-% %{\csname\??mathextensiblefallbacks\ifcsname\??mathextensiblefallbacks\number\scratchunicode\endcsname\number\scratchunicode\fi\endcsname }
+% In math mode we no longer fallback, simply because only a few fonts implement
+% extensible using minus and equal signs. So either we provide a tweaked one or we
+% simply ignore the lack. Better choose a font that matches expectations that some
+% fragile imperfect hackery.
\def\math_stackers_fallback
{\mathstylehbox to \scratchwidth{\usemathstackerscolorparameter\c!color
\hss
\hskip\mathstackersparameter\c!topoffset\relax % for manual italic correction
- \ifcsname\??mathextensiblefallbacks\number\scratchunicode\endcsname
- \lastnamedcs
- \else
+ % \ifcsname\??mathextensiblefallbacks\number\scratchunicode\endcsname
+ % \lastnamedcs
+ % \else
\Umathchar\zerocount\zerocount\scratchunicode
- \fi
+ % \fi
\hss}}
-% \def\math_stackers_regular
-% {\mathstylehbox{\usemathstackerscolorparameter\c!color
-% \hskip\d_math_stackers_offset_l
-% \Umathaccent\zerocount\zerocount\scratchunicode
-% {\hskip\dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
-% \hskip\d_math_stackers_offset_r
-% }}
-
-% \def\math_stackers_stretch % we don't have that one yet
-% {\mathstylehbox{\usemathstackerscolorparameter\c!color
-% \hskip\d_math_stackers_offset_l
-% \Umathaccent\zerocount\zerocount\scratchunicode
-% {\hskip\dimexpr\hsize-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
-% \hskip\d_math_stackers_offset_r
-% }}
-
\def\math_stackers_regular
{\mathstylehbox{\usemathstackerscolorparameter\c!color
\hskip\d_math_stackers_offset_l
\Uhextensible
middle
+ \ifcstok{\mathstackersparameter\c!stretch}\v!yes
+ stretch
+ \fi
+ \ifcstok{\mathstackersparameter\c!shrink}\v!yes
+ shrink
+ \fi
width \dimexpr\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r\relax
\zerocount\scratchunicode
\relax
@@ -130,18 +118,8 @@
% $\Umathaccent 0 0 "2190{x}$ \par $\Umathaccent 0 0 "27F8{x}$\par
% $\Udelimiterunder 0 "2190{x}$ \par $\Udelimiterunder 0 "27F8{x}$\par
-\defcsname\??mathextensiblefallbacks\endcsname
- {\hpack{\vrule\s!width\scratchwidth\s!height.1\mathexheight\s!depth\zeropoint}}
-
-% \def\math_stackers_with_fallback#codepoint%
-% {\begingroup
-% \scratchunicode#codepoint\relax
-% \ifcase\mathextensiblecode\fam\scratchunicode\relax
-% \math_stackers_fallback
-% \else
-% \math_stackers_stretch
-% \fi
-% \endgroup}
+% \defcsname\??mathextensiblefallbacks\endcsname
+% {\hpack{\vrule\s!width\scratchwidth\s!height.1\mathexheight\s!depth\zeropoint}}
%D We don't really need this because we can assume that fonts have the right
%D extensibles. If needed I will make a general virtual extender for \OPENTYPE\
@@ -337,6 +315,28 @@
\scratchbottomoffset\zeropoint
\fi}
+\def\math_stackers_get_max_width
+ {\ifdim\wd\scratchboxone>\scratchwidth
+ \scratchwidth\wd\scratchboxone
+ \fi
+ \ifdim\wd\scratchboxtwo>\scratchwidth
+ \scratchwidth\wd\scratchboxtwo
+ \fi
+ \ifdim\wd\scratchboxthree>\scratchwidth
+ \scratchwidth\wd\scratchboxthree
+ \fi}
+
+\def\math_stackers_set_max_width
+ {\ifdim\wd\scratchboxone<\scratchwidth
+ \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% unhboxing makes leaders work
+ \fi
+ \ifdim\wd\scratchboxtwo<\scratchwidth
+ \setbox\scratchboxtwo\hpack to \scratchwidth{\hss\unhbox\scratchboxtwo\hss}%
+ \fi
+ \ifdim\wd\scratchboxthree<\scratchwidth
+ \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}%
+ \fi}
+
\protected\def\math_stackers_triplet#method#category#codepoint#toptext#bottomtext%
{\begingroup
\edef\currentmathstackers{#category}%
@@ -395,19 +395,7 @@
\else
\setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
\fi
- \scratchwidth\wd
- \ifdim\wd\scratchboxone>\wd\scratchboxtwo
- \ifdim\wd\scratchboxone>\wd\scratchboxthree
- \scratchboxone
- \else
- \scratchboxthree
- \fi
- \orelse\ifdim\wd\scratchboxtwo>\wd\scratchboxthree
- \scratchboxtwo
- \else
- \scratchboxthree
- \fi
- \relax
+ \math_stackers_get_max_width
\fi
%
\scratchdimen\mathstackersparameter\c!minwidth\relax
@@ -421,19 +409,11 @@
\setbox\scratchboxthree\csname\??mathstackersalternative\p_alternative\endcsname
\dostoptagged
\fi
- \ifdim\wd\scratchboxthree>\scratchwidth
- \scratchwidth\wd\scratchboxthree
- \fi
+% \ifdim\wd\scratchboxthree>\scratchwidth
+% \scratchwidth\wd\scratchboxthree
+% \fi
%
- \ifdim\wd\scratchboxone<\scratchwidth
- \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% unhboxing makes leaders work
- \fi
- \ifdim\wd\scratchboxtwo<\scratchwidth
- \setbox\scratchboxtwo\hpack to \scratchwidth{\hss\unhbox\scratchboxtwo\hss}%
- \fi
- \ifdim\wd\scratchboxthree<\scratchwidth
- \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}%
- \fi
+ \math_stackers_set_max_width
%
\ifcsname\??mathstackerslocation\p_location\endcsname
\ifcase\csname\??mathstackerslocation\p_location\endcsname\relax
@@ -458,7 +438,6 @@
\ifzeropt\scratchdistance\else
\setbox\scratchboxthree\hpack{\lower\scratchdistance\box\scratchboxthree}%
\fi
- %
\math_stackers_normalize_three
% analysis
\ifdim\htdp\scratchboxtwo>\zeropoint
@@ -625,6 +604,8 @@
\fi
%
\math_stackers_normalize_three
+ \math_stackers_get_max_width
+ \math_stackers_set_max_width
% analysis
\ifcase\c_math_stackers_bottom
\ifcase\c_math_stackers_top
@@ -654,7 +635,7 @@
\math_stackers_bottom\bgroup
\lower\dimexpr
\scratchdepth
- +\ht\scratchboxtwo
+ +\ht\ifcase\c_math_stackers_top\scratchboxtwo\else\scratchboxone\fi
+\mathstackersparameter\c!distance % was \c!voffset
\relax
\ifcase\c_math_stackers_top
@@ -973,6 +954,7 @@
[\v!both]
[\v!mathematics]
[\c!location=\v!top, % ?
+ \c!mathclass=\s!accent, % check chemistry
\c!strut=\v!no,
\c!middlecommand=\mathematics,
\c!hoffset=\zeropoint]
@@ -989,7 +971,10 @@
[\v!vfenced]
[\v!both]
[\c!mathclass=\s!ordinary,
- \c!mathlimits=\v!yes]
+ \c!mathlimits=\v!yes,
+ % only these arrows make sense
+ \c!stretch=\v!yes,
+ \c!shrink=\v!yes]
% these are needed for mathml:
@@ -1085,10 +1070,10 @@
\definemathextensible [\v!mathematics] [mequal] ["003D]
\definemathextensible [\v!mathematics] [mleftarrow] ["2190] % ["27F5]
\definemathextensible [\v!mathematics] [mrightarrow] ["2192] % ["27F6]
-\definemathextensible [\v!mathematics] [mleftrightarrow] ["27F7]
-\definemathextensible [\v!mathematics] [mLeftarrow] ["27F8]
-\definemathextensible [\v!mathematics] [mRightarrow] ["27F9]
-\definemathextensible [\v!mathematics] [mLeftrightarrow] ["27FA]
+\definemathextensible [\v!mathematics] [mleftrightarrow] ["2194]
+\definemathextensible [\v!mathematics] [mLeftarrow] ["21D0]
+\definemathextensible [\v!mathematics] [mRightarrow] ["21D2]
+\definemathextensible [\v!mathematics] [mLeftrightarrow] ["21D4]
\definemathextensible [\v!mathematics] [mtwoheadleftarrow] ["219E]
\definemathextensible [\v!mathematics] [mtwoheadrightarrow] ["21A0]
\definemathextensible [\v!mathematics] [mmapsto] ["21A6]
@@ -1109,12 +1094,13 @@
\definemathextensible [\v!text] [tmapsto] ["21A6]
\definemathextensible [\v!text] [tleftarrow] ["2190] % ["27F5]
\definemathextensible [\v!text] [trightarrow] ["2192] % ["27F6]
-\definemathextensible [\v!text] [tleftrightarrow] ["27F7]
-\definemathextensible [\v!text] [tLeftarrow] ["27F8]
-\definemathextensible [\v!text] [tRightarrow] ["27F9]
-\definemathextensible [\v!text] [tLeftrightarrow] ["27FA]
+\definemathextensible [\v!text] [tleftrightarrow] ["2194]
+\definemathextensible [\v!text] [tLeftarrow] ["21D0]
+\definemathextensible [\v!text] [tRightarrow] ["21D2]
+\definemathextensible [\v!text] [tLeftrightarrow] ["21D4]
\definemathextensible [\v!text] [ttwoheadleftarrow] ["219E]
\definemathextensible [\v!text] [ttwoheadrightarrow] ["21A0]
+\definemathextensible [\v!text] [tmapsto] ["21A6]
\definemathextensible [\v!text] [thookleftarrow] ["21A9]
\definemathextensible [\v!text] [thookrightarrow] ["21AA]
\definemathextensible [\v!text] [tleftharpoondown] ["21BD]
@@ -1127,25 +1113,47 @@
\definemathextensible [\v!text] [trightleftharpoons] ["21CC]
\definemathextensible [\v!text] [ttriplerel] ["2261]
-\definemathoverextensible [\v!top] [overleftarrow] ["2190] % ["27F5]
-\definemathoverextensible [\v!top] [overrightarrow] ["2192] % ["27F6]
-\definemathoverextensible [\v!top] [overleftrightarrow] ["27F7]
-\definemathoverextensible [\v!top] [overtwoheadleftarrow] ["27F8]
-\definemathoverextensible [\v!top] [overtwoheadrightarrow] ["27F9]
-\definemathoverextensible [\v!top] [overleftharpoondown] ["21BD]
-\definemathoverextensible [\v!top] [overleftharpoonup] ["21BC]
-\definemathoverextensible [\v!top] [overrightharpoondown] ["21C1]
-\definemathoverextensible [\v!top] [overrightharpoonup] ["21C0]
+\definemathoverextensible [\v!top] [overleftarrow] ["2190] % ["27F5]
+\definemathoverextensible [\v!top] [overrightarrow] ["2192] % ["27F6]
+\definemathoverextensible [\v!top] [overleftrightarrow] ["2194] % ["27F7]
+\definemathoverextensible [\v!top] [overtwoheadleftarrow] ["219E] % ["27F8]
+\definemathoverextensible [\v!top] [overtwoheadrightarrow] ["21A0] % ["27F9]
+\definemathoverextensible [\v!top] [overlefttailarrow] ["21A2]
+\definemathoverextensible [\v!top] [overrighttailarrow] ["21A3]
+\definemathoverextensible [\v!top] [overleftbararrow] ["21A4]
+\definemathoverextensible [\v!top] [overrightbararrow] ["21A6]
+\definemathoverextensible [\v!top] [overlefthookarrow] ["21A9]
+\definemathoverextensible [\v!top] [overrighthookarrow] ["21AA]
+\definemathoverextensible [\v!top] [overleftharpoondown] ["21BD]
+\definemathoverextensible [\v!top] [overleftharpoonup] ["21BC]
+\definemathoverextensible [\v!top] [overrightharpoondown] ["21C1]
+\definemathoverextensible [\v!top] [overrightharpoonup] ["21C0]
+\definemathoverextensible [\v!top] [overRightarrow] ["21D2] % ["27F9]
+\definemathoverextensible [\v!top] [overLeftarrow] ["21D0] % ["27F8]
+\definemathoverextensible [\v!top] [overLeftrightarrow] ["21D4] % ["27F8]
+\definemathoverextensible [\v!top] [overLeftbararrow] ["2906]
+\definemathoverextensible [\v!top] [overRightbararrow] ["2907]
\definemathunderextensible [\v!bottom] [underleftarrow] ["2190] % ["27F5]
\definemathunderextensible [\v!bottom] [underrightarrow] ["2192] % ["27F6]
-\definemathunderextensible [\v!bottom] [underleftrightarrow] ["27F7]
-\definemathunderextensible [\v!bottom] [undertwoheadleftarrow] ["27F8]
-\definemathunderextensible [\v!bottom] [undertwoheadrightarrow] ["27F9]
+\definemathunderextensible [\v!bottom] [underleftrightarrow] ["2194] % ["27F7]
+\definemathunderextensible [\v!bottom] [undertwoheadleftarrow] ["219E] % ["27F8]
+\definemathunderextensible [\v!bottom] [undertwoheadrightarrow] ["21A0] % ["27F9]
+\definemathunderextensible [\v!bottom] [underlefttailarrow] ["21A2]
+\definemathunderextensible [\v!bottom] [underrighttailarrow] ["21A3]
+\definemathunderextensible [\v!bottom] [underleftbararrow] ["21A4]
+\definemathunderextensible [\v!bottom] [underrightbararrow] ["21A6]
+\definemathunderextensible [\v!bottom] [underlefthookarrow] ["21A9]
+\definemathunderextensible [\v!bottom] [underrighthookarrow] ["21AA]
\definemathunderextensible [\v!bottom] [underleftharpoondown] ["21BD]
\definemathunderextensible [\v!bottom] [underleftharpoonup] ["21BC]
\definemathunderextensible [\v!bottom] [underrightharpoondown] ["21C1]
\definemathunderextensible [\v!bottom] [underrightharpoonup] ["21C0]
+\definemathunderextensible [\v!bottom] [underRightarrow] ["21D2] % ["27F9]
+\definemathunderextensible [\v!bottom] [underLeftarrow] ["21D0] % ["27F8]
+\definemathunderextensible [\v!bottom] [underLeftrightarrow] ["21D4] % ["27F8]
+\definemathunderextensible [\v!bottom] [underLeftbararrow] ["2906]
+\definemathunderextensible [\v!bottom] [underRightbararrow] ["2907]
%D We don't use overline and underline. This is one of the overlooked aspects of
%D unicode cq. opentype math: why treat rules different than e.g. arrows and
@@ -1206,53 +1214,76 @@
\definemathextensible [\v!chemistry] [crightoverleftarrow] ["21C4]
\definemathextensible [\v!chemistry] [cleftoverrightarrow] ["21C6]
-\def\math_stackers_hacked_fill#1#2#3%
- {\mathematics
- {\begingroup
- \mathsurround\zeropoint
- \thickmuskip \zeromuskip
- \medmuskip \zeromuskip
- \thinmuskip \zeromuskip
- \tinymuskip \zeromuskip
- \pettymuskip \zeromuskip
- \ifrelax#1%
- \cleaders\mathstylehbox{#2}\hfill
- \else
- #1%
- \mkern-7\onemuskip
- \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill
- \mkern-7\onemuskip
- #3%
- \fi
- \endgroup}}
-
-\immutable\protected\def\rightarrowfill {\math_stackers_hacked_fill \relbar \relbar \rightarrow}
-\immutable\protected\def\leftarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \relbar}
-\immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \relax \crightoverleftarrow \relax}
-\immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \relax \cleftoverrightarrow \relax}
-\immutable\protected\def\equalfill {\math_stackers_hacked_fill \Relbar \Relbar \Relbar}
-\immutable\protected\def\Rightarrowfill {\math_stackers_hacked_fill \Relbar \Relbar \Rightarrow}
-\immutable\protected\def\Leftarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Relbar}
-\immutable\protected\def\Leftrightarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Rightarrow}
-\immutable\protected\def\leftrightarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \rightarrow}
-\immutable\protected\def\mapstofill {\math_stackers_hacked_fill{\mapstochar\relbar} \relbar \rightarrow}
-\immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar \relbar \twoheadrightarrow}
-\immutable\protected\def\twoheadleftarrowfill {\math_stackers_hacked_fill \twoheadleftarrow \relbar \relbar}
-\immutable\protected\def\rightharpoondownfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoondown}
-\immutable\protected\def\rightharpoonupfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoonup}
-\immutable\protected\def\leftharpoondownfill {\math_stackers_hacked_fill \leftharpoondown \relbar \relbar}
-\immutable\protected\def\leftharpoonupfill {\math_stackers_hacked_fill \leftharpoonup \relbar \relbar}
-\immutable\protected\def\hookleftfill {\math_stackers_hacked_fill \leftarrow \relbar {\relbar\joinrel\rhook}}
-\immutable\protected\def\hookrightfill {\math_stackers_hacked_fill{\lhook\joinrel\relbar}\relbar \rightarrow}
-\immutable\protected\def\relfill {\math_stackers_hacked_fill \relbar \relbar \relbar}
-\immutable\protected\def\triplerelfill {\math_stackers_hacked_fill \equiv \equiv \equiv}
-
-%D For the moment (needs checking):
+% \def\math_stackers_hacked_fill#1#2#3%
+% {\mathematics
+% {\begingroup
+% \mathsurround\zeropoint
+% \thickmuskip \zeromuskip
+% \medmuskip \zeromuskip
+% \thinmuskip \zeromuskip
+% \tinymuskip \zeromuskip
+% \pettymuskip \zeromuskip
+% \ifrelax#1%
+% \cleaders\mathstylehbox{#2}\hfill
+% \else
+% #1%
+% \mkern-7\onemuskip
+% \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill
+% \mkern-7\onemuskip
+% #3%
+% \fi
+% \endgroup}}
+%
+% \immutable\protected\def\rightarrowfill {\math_stackers_hacked_fill \relbar \relbar \rightarrow}
+% \immutable\protected\def\leftarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \relbar}
+% \immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \relax \crightoverleftarrow \relax}
+% \immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \relax \cleftoverrightarrow \relax}
+% \immutable\protected\def\equalfill {\math_stackers_hacked_fill \Relbar \Relbar \Relbar}
+% \immutable\protected\def\Rightarrowfill {\math_stackers_hacked_fill \Relbar \Relbar \Rightarrow}
+% \immutable\protected\def\Leftarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Relbar}
+% \immutable\protected\def\Leftrightarrowfill {\math_stackers_hacked_fill \Leftarrow \Relbar \Rightarrow}
+% \immutable\protected\def\leftrightarrowfill {\math_stackers_hacked_fill \leftarrow \relbar \rightarrow}
+% \immutable\protected\def\mapstofill {\math_stackers_hacked_fill{\mapstochar\relbar} \relbar \rightarrow}
+% \immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar \relbar \twoheadrightarrow}
+% \immutable\protected\def\twoheadleftarrowfill {\math_stackers_hacked_fill \twoheadleftarrow \relbar \relbar}
+% \immutable\protected\def\rightharpoondownfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoondown}
+% \immutable\protected\def\rightharpoonupfill {\math_stackers_hacked_fill \relbar \relbar \rightharpoonup}
+% \immutable\protected\def\leftharpoondownfill {\math_stackers_hacked_fill \leftharpoondown \relbar \relbar}
+% \immutable\protected\def\leftharpoonupfill {\math_stackers_hacked_fill \leftharpoonup \relbar \relbar}
+% \immutable\protected\def\hookleftfill {\math_stackers_hacked_fill \leftarrow \relbar {\relbar\joinrel\rhook}}
+% \immutable\protected\def\hookrightfill {\math_stackers_hacked_fill{\lhook\joinrel\relbar}\relbar \rightarrow}
+% \immutable\protected\def\relfill {\math_stackers_hacked_fill \relbar \relbar \relbar}
+% \immutable\protected\def\triplerelfill {\math_stackers_hacked_fill \equiv \equiv \equiv}
+%
+% \permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]%
+% {\immutable\letcsname\??mathextensiblefallbacks\number#2\expandafter\endcsname\csname#1\endcsname}
+
+\installcorenamespace {mathadaptiveextensible}
+
+\defineadaptive
+ [mathfiller]
+ [\c!setups=adaptive:mathfiller,
+ \c!stretch=1fill]
+
+\startsetups adaptive:mathfiller
+ \setbox\usedadaptivebox\hbox to \usedadaptivewidth \bgroup
+ \startimath
+ \Uhextensible
+ \s!width \usedadaptivewidth
+ \s!middle \zerocount \usedadaptivealternative
+ \relax
+ \stopimath
+ \egroup
+\stopsetups
+
+\def\mathfiller#1%
+ {\begingroup
+ \scratchunicode#1\relax
+ \adaptivebox[mathfiller][\c!alternative=#1]{\hss\strut\hss}%
+ \endgroup}
\permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]%
- {\immutable\letcsname\??mathextensiblefallbacks\number#2\expandafter\endcsname\csname#1\endcsname
- %\immutable\letcsname#1\expandafter\endcsname\csname#1\endcsname
- } % huh?
+ {\frozen\instance\edefcsname#1\endcsname{\mathfiller{\number#2}}}
%defineextensiblefiller [barfill] ["203E] % yet undefined
\defineextensiblefiller [relfill] ["002D]
@@ -1302,14 +1333,18 @@
{\begingroup
\edef\currentmathstackers{#category}%
\edef\p_moffset{\mathstackersparameter\c!moffset}%
- \ifempty\p_moffset \else
- \mskip\p_moffset\relax
+ \ifconditional\indisplaymath
+ \ifempty\p_moffset \else
+ \ifmmode\mskip\else\hskip\fi\p_moffset\relax
+ \fi
\fi
\ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi
{\usemathstackerscolorparameter\c!color
\Umathchar\zerocount\zerocount#codepoint}%
- \ifempty\p_moffset \else
- \mskip\p_moffset\relax
+ \ifconditional\indisplaymath
+ \ifempty\p_moffset \else
+ \ifmmode\mskip\else\hskip\fi\p_moffset\relax
+ \fi
\fi
\endgroup}
@@ -1319,6 +1354,7 @@
\definemathunstacked [\v!wide] [impliedby] ["27F8] % \mathrel{\;\Longleftarrow\;}
\definemathunstacked [\v!wide] [implies] ["27F9] % \mathrel{\;\Longrightarrow\;}
\definemathunstacked [\v!wide] [iff] ["27FA] % \mathrel{\;\Longleftrightarrow\;}
+\definemathunstacked [\v!wide] [impliesby] ["27FA] % \mathrel{\;\Longleftrightarrow\;}
% New (an example of using \mathexheight):
diff --git a/tex/context/base/mkxl/math-vfu.lmt b/tex/context/base/mkxl/math-vfu.lmt
index f3e0ea814..0a2b440a1 100644
--- a/tex/context/base/mkxl/math-vfu.lmt
+++ b/tex/context/base/mkxl/math-vfu.lmt
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['math-vfu'] = {
license = "see context related readme files"
}
+-- somehow an italic gets passed for 'next'
+
-- All these math vectors .. thanks to Aditya and Mojca they become better and
-- better. If you have problems with math fonts or miss characters report it to the
-- ConTeXt mailing list. Also thanks to Boguslaw for finding a couple of errors.
@@ -62,6 +64,25 @@ local staycommand = vfcommands.stay
local nps = fonts.helpers.newprivateslot
local ps = fonts.helpers.privateslot
+nps("rule middle piece")
+nps("rule right piece")
+nps("rule left piece")
+nps("double rule middle piece")
+nps("double rule right piece")
+nps("double rule left piece")
+nps("arrow left piece")
+nps("arrow right piece")
+nps("double arrow left piece")
+nps("double arrow right piece")
+
+nps("flat rule left piece")
+nps("flat rule middle piece")
+nps("flat rule right piece")
+
+nps("flat double rule left piece")
+nps("flat double rule middle piece")
+nps("flat double rule right piece")
+
do
local function horibar(main,unicode,rule,left,right,normal)
@@ -89,11 +110,11 @@ do
if not characters[p_rule] then
p_rule = addprivate(main,f_rule,{
height = height,
- width = mwidth,
- width = .95*mwidth,
+ width = .95*mwidth,
+-- keepvirtual = true,
commands = {
push,
- leftcommand[.025*mwidth],
+ leftcommand[.025*mwidth],
downcommand[down],
slotcommand[0][rule],
pop,
@@ -103,11 +124,11 @@ do
if not characters[p_left] then
p_left = addprivate(main,f_left,{
height = height,
- width = lwidth,
- width = .95*lwidth,
+ width = .95*lwidth,
+-- keepvirtual = true,
commands = {
push,
- leftcommand[.025*lwidth],
+ leftcommand[.025*lwidth],
downcommand[down],
slotcommand[0][left],
pop,
@@ -117,11 +138,11 @@ do
if not characters[p_right] then
p_right = addprivate(main,f_right,{
height = height,
- width = rwidth,
- width = .95*rwidth,
+ width = .95*rwidth,
+-- keepvirtual = true,
commands = {
push,
- leftcommand[.025*rwidth],
+ leftcommand[.025*rwidth],
downcommand[down],
slotcommand[0][right],
pop,
@@ -133,6 +154,7 @@ do
partsorientation = "horizontal",
height = height,
width = nwidth,
+-- keepvirtual = true,
commands = {
downcommand[down],
slotcommand[0][normal]
@@ -149,11 +171,14 @@ do
p_rule = addprivate(main,f_rule,{
height = height,
width = width,
+-- keepvirtual = true,
commands = { push, { "rule", height, width }, pop },
})
end
characters[unicode] = {
- keepvirtual = true,
+ height = height,
+ width = nwidth,
+-- keepvirtual = true,
partsorientation = "horizontal",
parts = {
{ glyph = p_rule },
@@ -234,21 +259,29 @@ do
if characters[unicode] then
local template = characters[first]
if template then
- if not characters[rule] then
- local xheight = main.mathparameters.xheight
+ local crule = characters[rule]
+ local xheight = main.mathparameters.xheight
+ local rheight = 0
+ local rdepth = 0
+-- if crule then
+-- rheight = crule.height
+-- rdepth = crule.depth
+-- else
local width = template.width / 4
local height = template.height
local depth = template.depth
- local rheight = where == "top" and height or 3*height
- local rdepth = where == "top" and 2*height or 0
+ rheight = where == "top" and height or 3*height
+ rdepth = where == "top" and 2*height or 0
characters[rule] = {
height = rheight,
depth = rdepth,
width = width,
commands = { push, { "rule", height, width }, pop },
}
- characters[first].depth = rdepth
- characters[last] .depth = rdepth
+-- end
+ characters[first].depth = rdepth
+ characters[last] .depth = rdepth
+ if where == "top" then
while true do
chardata.height = chardata.height - xheight
chardata.depth = 0
@@ -261,41 +294,49 @@ do
break
end
end
+ else
+ while true do
+ chardata.height = 0
+ local next = chardata.next
+ if next then
+ unicode = next
+ chardata = characters[unicode]
+ else
+ break
+ end
+ end
end
chardata.keepvirtual = true
chardata.partsorientation = "horizontal"
chardata.parts = {
{ glyph = first },
- { glyph = rule, extender = 1 },
+ { glyph = rule, extender = 1, start = width/2, ["end"] = width/2 },
{ glyph = last },
}
end
end
end
- local function brace(main,unicode,first,rule,left,right,rule,last)
+ local function brace(main,unicode,first,rule,left,right,rule,last,where)
local characters = main.characters
local chardata = characters[unicode]
if chardata then
local template = characters[first]
if template then
- if not characters[rule] then
- local xheight = main.mathparameters.xheight
- local width = template.width / 4
- local height = template.height
- local depth = template.depth
- local rheight = 3*height
- local rdepth = 2*height
- characters[rule] = {
- height = rheight,
- depth = rdepth,
- width = width,
- commands = { push, { "rule", height, width }, pop },
- }
- characters[first].depth = rdepth
- characters[last] .depth = rdepth
- characters[left] .height = rheight
- characters[right].height = rheight
+ local xheight = main.mathparameters.xheight
+ local width = template.width / 4
+ local height = template.height
+ local depth = template.depth
+ local rheight = 3*height
+ local rdepth = 2*height
+ characters[rule] = {
+ height = rheight,
+ depth = rdepth,
+ width = width,
+ commands = { push, { "rule", height, width }, pop },
+ }
+ -- don't change snippets, they serve dual purposes
+ if where == "top" then
while true do
chardata.height = chardata.height - xheight
chardata.depth = 0
@@ -308,15 +349,26 @@ do
break
end
end
+ else
+ while true do
+ chardata.height = 0
+ local next = chardata.next
+ if next then
+ unicode = next
+ chardata = characters[unicode]
+ else
+ break
+ end
+ end
end
chardata.keepvirtual = true
chardata.partsorientation = "horizontal"
chardata.parts = {
{ glyph = first },
- { glyph = rule, extender = 1 },
+ { glyph = rule, extender = 1, start = width/2, ["end"] = width/2 },
{ glyph = left },
{ glyph = right },
- { glyph = rule, extender = 1 },
+ { glyph = rule, extender = 1, start = width/2, ["end"] = width/2 },
{ glyph = last },
}
end
@@ -436,9 +488,11 @@ do
width = w1 + w2 - d12
end
characters[unicode] = {
+ unicode = unicode,
width = width,
height = max(c1.height or 0, c2.height or 0),
depth = max(c1.depth or 0, c2.depth or 0),
+keepvirtual = true,
commands = {
-- { "inspect" },
-- { "trace" },
@@ -482,10 +536,11 @@ do
local w1 = c1.width
local w2 = c2.width
local w3 = c3.width
- local mu = main.parameters.size/18
+ local ds = main.parameters.size/18
d12 = d12 * ds
d23 = d23 * ds
characters[unicode] = {
+ unicode = unicode,
width = w1 + w2 + w3 - d12 - d23,
height = max(c1.height or 0, c2.height or 0, c3.height or 0),
depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0),
@@ -572,6 +627,40 @@ do
end
end
+ local function extension(main,unicode,first,middle,last,ffactor,mfactor,lfactor)
+ local characters = main.characters
+ local chardata = characters[unicode]
+ if chardata then
+ local fw = first and characters[first]
+ local mw = middle and characters[middle]
+ local lw = last and characters[last]
+ if fw and lw then
+ fw = fw.width ; if fw == 0 then fw = 1 end
+ lw = lw.width ; if lw == 0 then lw = 1 end
+ if middle == "left" then
+ chardata.parts = {
+ { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw },
+ { extender = 1, glyph = last, ["end"] = lw/2, start = lw/2, advance = lw },
+ }
+ elseif middle == "right" then
+ chardata.parts = {
+ { extender = 1, glyph = first, ["end"] = fw/2, start = fw/2, advance = fw },
+ { extender = 0, glyph = last, ["end"] = lw/2, start = 0, advance = lw },
+ }
+ elseif mw then
+ mw = mw.width ; if mw == 0 then mw = 1 end
+ chardata.parts = {
+ { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = (ffactor or 1)*fw },
+ { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = (mfactor or 1)*mw },
+ { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = (lfactor or 1)*lw },
+ }
+ end
+ chardata.keepvirtual = true -- why this issue with nested virtuals
+ chardata.partsorientation = "horizontal"
+ end
+ end
+ end
+
vfmath.builders = {
horibar = horibar,
rootbar = rootbar,
@@ -583,6 +672,7 @@ do
jointhree = jointhree,
stack = stack,
repeated = repeated,
+ extension = extension,
}
-- todo: move this to the lfg files
@@ -1113,6 +1203,11 @@ function vfmath.define(specification,set,goodies)
fake = 0.9, -- replace multiples with this width proportion
})
--
+ mathematics.tweaks.addequals(main, main, {
+ tweak = "addequals",
+ force = true,
+ })
+ --
-- mathematics.tweaks.addbars(main,main,{
-- tweak = "addbars",
-- advance = 0.52,
@@ -1148,40 +1243,6 @@ function vfmath.setdigits(font_encoding, name, digits)
end
end
--- local function extension(main,characters,id,size,unicode,first,middle,last)
--- local chr = characters[unicode]
--- if not chr then
--- return -- skip
--- end
--- local fw = characters[first]
--- if not fw then
--- return
--- end
--- local mw = characters[middle]
--- if not mw then
--- return
--- end
--- local lw = characters[last]
--- if not lw then
--- return
--- end
--- fw = fw.width
--- mw = mw.width
--- lw = lw.width
--- if fw == 0 then
--- fw = 1
--- end
--- if lw == 0 then
--- lw = 1
--- end
--- chr.partsorientation = "horizontal"
--- chr.parts = {
--- { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw },
--- { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = mw },
--- { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = lw },
--- }
--- end
-
-- local step = 0.2 -- 0.1 is nicer but gives larger files
-- local function clipped(main,characters,id,size,unicode,original) -- push/pop needed?
diff --git a/tex/context/base/mkxl/mult-sys.mkxl b/tex/context/base/mkxl/mult-sys.mkxl
index 428a8ddcf..47119ad20 100644
--- a/tex/context/base/mkxl/mult-sys.mkxl
+++ b/tex/context/base/mkxl/mult-sys.mkxl
@@ -114,6 +114,7 @@
%D For proper \UNICODE\ support we need a few font related constants.
+\definesystemconstant {accent}
\definesystemconstant {action}
\definesystemconstant {all}
\definesystemconstant {ampersand}
@@ -164,6 +165,7 @@
\definesystemconstant {leftclass}
\definesystemconstant {rightclass}
\definesystemconstant {calligraphic}
+\definesystemconstant {center}
\definesystemconstant {clone}
\definesystemconstant {close}
\definesystemconstant {cmyk}
diff --git a/tex/context/base/mkxl/node-ali.lmt b/tex/context/base/mkxl/node-ali.lmt
index ba2ccdde7..5eff779dc 100644
--- a/tex/context/base/mkxl/node-ali.lmt
+++ b/tex/context/base/mkxl/node-ali.lmt
@@ -21,7 +21,6 @@ local setnext = nuts.setnext
local getnext = nuts.getnext
local getprev = nuts.getprev
local getboth = nuts.getboth
-local setglue = nuts.setglue
local getglue = nuts.getglue
local setglue = nuts.setglue
local getwhd = nuts.getwhd
@@ -372,6 +371,7 @@ do
if noflines > 0 then
local currentline = 1
for n, subtype in nextglue, head do
+-- print(currentline,height/65536,depth/65536)
-- one day we can decide what to do with intertext stuff based on the
-- subtype but not now ... on our agenda (intertext etc)
if subtype == baselineskip_code or subtype == lineskip_code then
@@ -383,9 +383,11 @@ do
if prevdp < depth then
setdepth(lines[currentline][1],depth)
delta = delta + (depth - prevdp)
+-- lines[currentline][5] = depth
end
if nextht < height then
setheight(lines[nextline][1],height)
+-- lines[nextline][4] = height
delta = delta + (height - nextht)
end
-- if subtype == lineskip_code then
@@ -394,7 +396,7 @@ do
-- else
setglue(n,amount+inbetween-delta,stretch,shrink)
-- end
- curline = nextline
+ currentline = nextline -- was curline
-- if currentline > noflines then
-- break
-- end
diff --git a/tex/context/base/mkxl/page-brk.mkxl b/tex/context/base/mkxl/page-brk.mkxl
index 23ffc872d..8c92148fc 100644
--- a/tex/context/base/mkxl/page-brk.mkxl
+++ b/tex/context/base/mkxl/page-brk.mkxl
@@ -90,7 +90,7 @@
% disable reset after shipout
\global\pageornamentstate\plustwo
\fi
- % maybe \ifcstok{#1}\emptytoks
+ % maybe \iftok{#1}\emptytoks
\ifparameter#1\or
\page_breaks_handle{#1}%
\else % so, no pagebreak when \pagebreak[] ! ! !
diff --git a/tex/context/base/mkxl/phys-dim.lmt b/tex/context/base/mkxl/phys-dim.lmt
new file mode 100644
index 000000000..8575962e9
--- /dev/null
+++ b/tex/context/base/mkxl/phys-dim.lmt
@@ -0,0 +1,1116 @@
+if not modules then modules = { } end modules ['phys-dim'] = {
+ version = 1.001,
+ comment = "companion to phys-dim.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This is pretty old code that I found back, but let's give it a try
+-- in practice. It started out as m-units.lua but as we want to keep that
+-- module around we moved the code to the dimensions module.
+--
+-- todo: maybe also an sciunit command that converts to si units (1 inch -> 0.0254 m)
+-- etc .. typical something to do when listening to a news whow or b-movie
+--
+-- todo: collect used units for logging (and list of units, but then we need
+-- associations too).
+
+-- The lists have been checked and completed by Robin Kirkham.
+
+-- dubious/wrong
+
+-- Atom = [[u]], -- should be amu (atomic mass unit)
+-- Bell = [[B]], -- should be bel
+-- Sterant = [[sr]], -- should be steradian
+-- Equivalent = [[eql]], -- qualifier?
+-- At = [[at]], -- qualifier?
+-- Force = [[f]], -- qualifier?
+-- eVolt = [[eV]],
+-- -- AC or DC voltages should be qualified in the text
+-- VoltAC = [[V\unitsbackspace\unitslower{ac}]],
+-- VoltDC = [[V\unitsbackspace\unitslower{dc}]],
+-- AC = [[V\unitsbackspace\unitslower{ac}]],
+-- DC = [[V\unitsbackspace\unitslower{dc}]],
+-- -- probably not harmful but there are better alternatives
+-- -- e.g., revolution per second (rev/s)
+-- RPS = [[RPS]],
+-- RPM = [[RPM]],
+-- RevPerSec = [[RPS]],
+-- RevPerMin = [[RPM]],
+
+local rawset, next = rawset, next
+local V, P, S, R, C, Cc, Cs, matchlpeg = lpeg.V, lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.match
+local format, lower, gsub = string.format, string.lower, string.gsub
+local appendlpeg = lpeg.append
+local utfchartabletopattern = lpeg.utfchartabletopattern
+local mergetable, mergedtable, keys, loweredkeys, sortedhash = table.merge, table.merged, table.keys, table.loweredkeys, table.sortedhash
+local setmetatablenewindex = table.setmetatablenewindex
+local utfchar = utf.char
+
+physics = physics or { }
+physics.units = physics.units or { }
+
+local allocate = utilities.storage.allocate
+
+local context = context
+local commands = commands
+local implement = interfaces.implement
+
+local trace_units = false
+local report_units = logs.reporter("units")
+
+trackers.register("physics.units", function(v) trace_units = v end)
+
+-- digits parser (todo : use patterns)
+
+local math_one = Cs((P("$") /"") * (1-P("$"))^1 * (P("$")/"")) / context.m
+local math_two = Cs((P("\\m {")/"") * (1-P("}"))^1 * (P("}")/"")) / context.m -- watch the space after \m
+
+local digit = R("09")
+local plus = P("+")
+local minus = P("-")
+local plusminus = P("±")
+local sign = plus + minus
+local power = S("^e")
+local digitspace = S("~@_")
+local comma = P(",")
+local period = P(".")
+local semicolon = P(";")
+local colon = P(":")
+local signspace = P("/")
+local positive = P("++") -- was p
+local negative = P("--") -- was n
+local highspace = P("//") -- was s
+local padding = P("=")
+local space = P(" ")
+local lparent = P("(")
+local rparent = P(")")
+
+local lbrace = P("{")
+local rbrace = P("}")
+
+local digits = digit^1
+
+local powerdigits = plus * C(digits) / context.digitspowerplus
+ + minus * C(digits) / context.digitspowerminus
+ + C(digits) / context.digitspower
+
+local ddigitspace = digitspace / "" / context.digitsspace
+local ddigit = digits / context.digitsdigit
+local dsemicomma = semicolon / "" / context.digitsseparatorspace
+local dsemiperiod = colon / "" / context.digitsseparatorspace
+local dfinalcomma = comma / "" / context.digitsfinalcomma
+local dfinalperiod = period / "" / context.digitsfinalperiod
+local dintercomma = comma / "" / context.digitsintermediatecomma
+local dinterperiod = period / "" / context.digitsintermediateperiod
+local dskipcomma = comma / "" / context.digitsseparatorspace
+local dskipperiod = period / "" / context.digitsseparatorspace
+local dsignspace = signspace / "" / context.digitssignspace
+local dpositive = positive / "" / context.digitspositive
+local dnegative = negative / "" / context.digitsnegative
+local dhighspace = highspace / "" / context.digitshighspace
+local dsomesign = plus / "" / context.digitsplus
+ + minus / "" / context.digitsminus
+ + plusminus / "" / context.digitsplusminus
+local dpower = power / "" * ( powerdigits + lbrace * powerdigits * rbrace )
+
+local dpadding = padding / "" / context.digitszeropadding -- todo
+
+local dleader = (dpositive + dnegative + dhighspace + dsomesign + dsignspace)^0
+local dtrailer = dpower^0
+local dfinal = P(-1) + #P(1 - comma - period - semicolon - colon)
+local dnumber = (ddigitspace + ddigit)^1
+
+-- ___,000,000 ___,___,000 ___,___,__0 000,000,000 000.00 000,000,000.00 000,000,000.==
+
+-- : ; for the moment not used, maybe for invisible fraction . , when no leading number
+
+-- local c_p = (ddigitspace^1 * dskipcomma)^0 -- ___,
+-- * (ddigitspace^0 * ddigit * dintercomma)^0 -- _00, 000,
+-- * ddigitspace^0 * ddigit^0 -- _00 000
+-- * (
+-- dfinalperiod * ddigit -- .00
+-- + dskipperiod * dpadding^1 -- .==
+-- + dsemiperiod * ddigit -- :00
+-- + dsemiperiod * dpadding^1 -- :==
+-- )^0
+-- + ddigit -- 00
+--
+-- local p_c = (ddigitspace^1 * dskipperiod)^0 -- ___.
+-- * (ddigitspace^0 * ddigit * dinterperiod)^0 -- _00. 000.
+-- * ddigitspace^0 * ddigit^0 -- _00 000
+-- * (
+-- dfinalcomma * ddigit -- ,00
+-- + dskipcomma * dpadding^1 -- ,==
+-- + dsemicomma * ddigit -- :00
+-- + dsemicomma * dpadding^1 -- :==
+-- )^0
+-- + ddigit -- 00
+--
+-- fix by WS/SB (needs further testing)
+
+local c_p = (ddigitspace^1 * dskipcomma)^0 -- ___,
+ * (ddigitspace^0 * ddigit * dintercomma)^0 -- _00, 000,
+ * ddigitspace^0 * ddigit^0 -- _00 000
+ * (
+ dfinalperiod * ddigit^1 * dpadding^1 -- .0=
+ + dfinalperiod * ddigit * (dintercomma * ddigit)^0 -- .00
+ + dskipperiod * dpadding^1 -- .==
+ + dsemiperiod * ddigit * (dintercomma * ddigit)^0 -- :00
+ + dsemiperiod * dpadding^1 -- :==
+ )^0
+ + ddigit -- 00
+
+local p_c = (ddigitspace^1 * dskipperiod)^0 -- ___.
+ * (ddigitspace^0 * ddigit * dinterperiod)^0 -- _00. 000.
+ * ddigitspace^0 * ddigit^0 -- _00 000
+ * (
+ dfinalcomma * ddigit^1 * dpadding^1 -- ,0=
+ + dfinalcomma * ddigit * (dinterperiod * ddigit)^0 -- 00
+ + dskipcomma * dpadding^1 -- ,==
+ + dsemicomma * ddigit * (dinterperiod * ddigit)^0 -- :00
+ + dsemicomma * dpadding^1 -- :==
+ )^0
+ + ddigit -- 00
+
+local p_c_dparser = math_one + math_two + dleader * p_c * dtrailer * dfinal
+local c_p_dparser = math_one + math_two + dleader * c_p * dtrailer * dfinal
+
+local function makedigits(str,reverse)
+ if reverse then
+ matchlpeg(p_c_dparser,str)
+ else
+ matchlpeg(c_p_dparser,str)
+ end
+end
+
+-- tables:
+
+local user_long_prefixes = { }
+local user_long_units = { }
+local user_long_operators = { }
+local user_long_suffixes = { }
+local user_symbol_units = { }
+local user_packaged_units = { }
+
+local user_short_prefixes = { }
+local user_short_units = { }
+local user_short_operators = { }
+local user_short_suffixes = { }
+
+local long_prefixes = {
+
+ -- Le Système international d'unités (SI) 8e édition (Table 5)
+
+ Yocto = "yocto", -- 10^{-24}
+ Zepto = "zepto", -- 10^{-21}
+ Atto = "atto", -- 10^{-18}
+ Femto = "femto", -- 10^{-15}
+ Pico = "pico", -- 10^{-12}
+ Nano = "nano", -- 10^{-9}
+ Micro = "micro", -- 10^{-6}
+ Milli = "milli", -- 10^{-3}
+ Centi = "centi", -- 10^{-2}
+ Deci = "deci", -- 10^{-1}
+
+ Deca = "deca", -- 10^{1}
+ Hecto = "hecto", -- 10^{2}
+ Kilo = "kilo", -- 10^{3}
+ Mega = "mega", -- 10^{6}
+ Giga = "giga", -- 10^{9}
+ Tera = "tera", -- 10^{12}
+ Peta = "peta", -- 10^{15}
+ Exa = "exa", -- 10^{18}
+ Zetta = "zetta", -- 10^{21}
+ Yotta = "yotta", -- 10^{24}
+
+ -- IEC 60027-2: 2005, third edition, Part 2
+
+ Kibi = "kibi", -- 2^{10} (not ki)
+ Mebi = "mebi", -- 2^{20}
+ Gibi = "gibi", -- 2^{30}
+ Tebi = "tebi", -- 2^{40}
+ Pebi = "pebi", -- 2^{50}
+ Exbi = "exbi", -- 2^{60}
+
+ -- not standard
+
+ Zebi = "zebi", -- binary
+ Yobi = "yobi", -- binary
+
+ Micro = "micro",
+ Root = "root",
+}
+
+local long_units = {
+
+ -- Le Système international d'unités (SI) 8e édition (except synonyms)
+ -- SI base units (Table 1)
+
+ Meter = "meter",
+ Gram = "gram",
+ Second = "second",
+ Ampere = "ampere",
+ Kelvin = "kelvin",
+ Mole = "mole",
+ Candela = "candela",
+
+ -- synonyms
+
+ Mol = "mole",
+ Metre = "meter",
+
+ -- SI derived units with special names (Table 3)
+
+ Radian = "radian",
+ Steradian = "steradian",
+ Hertz = "hertz",
+ Newton = "newton",
+ Pascal = "pascal",
+ Joule = "joule",
+ Watt = "watt",
+ Coulomb = "coulomb",
+ Volt = "volt",
+ Farad = "farad",
+ Ohm = "ohm",
+ Siemens = "siemens",
+ Weber = "weber",
+ Tesla = "tesla",
+ Henry = "henry",
+ Celsius = "celsius",
+ Lumen = "lumen",
+ Lux = "lux",
+ Becquerel = "becquerel",
+ Gray = "gray",
+ Sievert = "sievert",
+ Katal = "katal",
+
+ -- non SI units accepted for use with SI (Table 6)
+
+ Minute = "minute",
+ Hour = "hour",
+ Day = "day",
+
+ -- (degree, minute, second of arc are treated specially later)
+
+ Gon = "gon",
+ Grad = "grad",
+ Hectare = "hectare",
+ Liter = "liter",
+
+ Tonne = "tonne",
+
+ -- synonyms
+
+ MetricTon = "tonne",
+ Litre = "liter",
+
+ ["Metric Ton"] = "tonne",
+
+ -- non-SI units whose values must be obtained experimentally (Table 7)
+
+ AtomicMassUnit = "atomicmassunit",
+ AstronomicalUnit = "astronomicalunit",
+ ElectronVolt = "electronvolt",
+ Dalton = "dalton",
+
+ ["Atomic Mass Unit"] = "atomicmassunit",
+ ["Astronomical Unit"] = "astronomicalunit",
+ ["Electron Volt"] = "electronvolt",
+
+ -- special cases (catch doubles, okay, a bit over the top)
+
+ DegreesCelsius = "celsius",
+ DegreesFahrenheit = "fahrenheit",
+ DegreeCelsius = "celsius",
+ DegreeFahrenheit = "fahrenheit",
+
+ ["Degrees Celsius"] = "celsius",
+ ["Degrees Fahrenheit"] = "fahrenheit",
+ ["Degree Celsius"] = "celsius",
+ ["Degree Fahrenheit"] = "fahrenheit",
+
+ -- too late as we already have connected symbols catched:
+ --
+ -- ["° Celsius"] = "celsius",
+ -- ["° Fahrenheit"] = "fahrenheit",
+ -- ["°Celsius"] = "celsius",
+ -- ["°Fahrenheit"] = "fahrenheit",
+
+ -- the "natural units" and "atomic units" are omitted for now
+ -- synonyms
+
+ eV = "electronvolt",
+ AMU = "atomicmassunit",
+
+ -- other non-SI units (Table 8)
+
+ Bar = "bar",
+ Hg = "mercury",
+ -- ["Millimetre Of Mercury"] = [[mmHg]],
+ Angstrom = "angstrom", -- strictly Ångström
+ NauticalMile = "nauticalmile",
+ Barn = "barn",
+ Knot = "knot",
+ Neper = "neper",
+ Bel = "bel", -- in practice only decibel used
+
+ ["Nautical Mile"] = "nauticalmile",
+
+ -- other non-SI units from CGS system (Table 9)
+
+ Erg = "erg",
+ Dyne = "dyne",
+ Poise = "poise",
+ Stokes = "stokes",
+ Stilb = "stilb",
+ Phot = "phot",
+ Gal = "gal",
+ Maxwell = "maxwell",
+ Gauss = "gauss",
+ Oersted = "oersted",
+
+ -- end of SI
+
+ -- data: for use with the binary prefixes (except Erlang)
+
+ Bit = "bit",
+ Byte = "byte" ,
+ Baud = "baud",
+ Erlang = "erlang",
+
+ -- common units, not part of SI
+
+ Atmosphere = "atmosphere",
+ Revolution = "revolution",
+
+ -- synonyms
+
+ Atm = "atmosphere",
+ Rev = "revolution",
+
+ -- imperial units (very incomplete)
+
+ Fahrenheit = "fahrenheit",
+ Foot = "foot",
+ Inch = "inch",
+ Calorie = "calorie",
+
+ -- synonyms
+
+ Cal = "calorie",
+
+}
+
+local long_operators = {
+
+ Times = "times",
+ Solidus = "solidus",
+ Per = "per",
+ OutOf = "outof",
+
+}
+
+local long_suffixes = {
+
+ Linear = "linear",
+ Square = "square",
+ Cubic = "cubic",
+ Quadratic = "quadratic",
+ Inverse = "inverse",
+ ILinear = "ilinear",
+ ISquare = "isquare",
+ ICubic = "icubic",
+ IQuadratic = "iquadratic",
+
+}
+
+local short_prefixes = {
+
+ y = "yocto",
+ z = "zetto",
+ a = "atto",
+ f = "femto",
+ p = "pico",
+ n = "nano",
+ u = "micro",
+ m = "milli",
+ c = "centi",
+ d = "deci",
+ da = "deca",
+ h = "hecto",
+ k = "kilo",
+ M = "mega",
+ G = "giga",
+ T = "tera",
+ P = "peta",
+ E = "exa",
+ Z = "zetta",
+ Y = "yotta",
+
+}
+
+local short_units = { -- I'm not sure about casing
+
+ m = "meter",
+ Hz = "hertz",
+ hz = "hertz",
+ B = "bel",
+ b = "bel",
+ lx = "lux",
+ -- da = "dalton",
+ h = "hour",
+ s = "second",
+ g = "gram",
+ n = "newton",
+ v = "volt",
+ t = "tonne",
+ l = "liter",
+ -- w = "watt",
+ W = "watt",
+ -- a = "ampere",
+ A = "ampere",
+
+-- C = "coulomb", -- needs checking with (c)enti
+-- K = "kelvin", -- needs checking with (k)ilo
+-- N = "newton", -- needs checking with (n)ewton
+
+ min = "minute",
+
+ [utfchar(0x2103)] = "celsius",
+ [utfchar(0x2109)] = "fahrenheit",
+}
+
+local short_operators = {
+ ["."] = "times",
+ ["*"] = "times",
+ ["/"] = "solidus",
+ [":"] = "outof",
+}
+
+local short_suffixes = { -- maybe just raw digit match
+ ["1"] = "linear",
+ ["2"] = "square",
+ ["3"] = "cubic",
+ ["4"] = "quadratic",
+ ["+1"] = "linear",
+ ["+2"] = "square",
+ ["+3"] = "cubic",
+ ["+4"] = "quadratic",
+ ["-1"] = "inverse",
+ ["-1"] = "ilinear",
+ ["-2"] = "isquare",
+ ["-3"] = "icubic",
+ ["-4"] = "iquadratic",
+ ["^1"] = "linear",
+ ["^2"] = "square",
+ ["^3"] = "cubic",
+ ["^4"] = "quadratic",
+ ["^+1"] = "linear",
+ ["^+2"] = "square",
+ ["^+3"] = "cubic",
+ ["^+4"] = "quadratic",
+ ["^-1"] = "inverse",
+ ["^-1"] = "ilinear",
+ ["^-2"] = "isquare",
+ ["^-3"] = "icubic",
+ ["^-4"] = "iquadratic",
+}
+
+local symbol_units = {
+ Degrees = "degree",
+ Degree = "degree",
+ -- Deg = "degree",
+ ["°"] = "degree",
+ ArcMinute = "arcminute",
+ ["′"] = "arcminute", -- 0x2032
+ ArcSecond = "arcsecond",
+ ["″"] = "arcsecond", -- 0x2033
+ Percent = "percent",
+ ["%"] = "percent",
+ Promille = "permille",
+ Permille = "permille",
+}
+
+local packaged_units = {
+ Micron = "micron",
+ mmHg = "millimetermercury",
+}
+
+-- rendering:
+
+local ctx_unitsPUS = context.unitsPUS
+local ctx_unitsPU = context.unitsPU
+local ctx_unitsPS = context.unitsPS
+local ctx_unitsP = context.unitsP
+local ctx_unitsUS = context.unitsUS
+local ctx_unitsU = context.unitsU
+local ctx_unitsS = context.unitsS
+local ctx_unitsO = context.unitsO
+local ctx_unitsN = context.unitsN
+local ctx_unitsC = context.unitsC
+local ctx_unitsQ = context.unitsQ
+local ctx_unitsRPM = context.unitsRPM
+local ctx_unitsRTO = context.unitsRTO
+local ctx_unitsRabout = context.unitsRabout
+local ctx_unitsNstart = context.unitsNstart
+local ctx_unitsNstop = context.unitsNstop
+local ctx_unitsNspace = context.unitsNspace
+local ctx_unitsPopen = context.unitsPopen
+local ctx_unitsPclose = context.unitsPclose
+
+local labels = languages.data.labels
+
+labels.prefixes = allocate {
+ yocto = { labels = { en = [[y]] } }, -- 10^{-24}
+ zepto = { labels = { en = [[z]] } }, -- 10^{-21}
+ atto = { labels = { en = [[a]] } }, -- 10^{-18}
+ femto = { labels = { en = [[f]] } }, -- 10^{-15}
+ pico = { labels = { en = [[p]] } }, -- 10^{-12}
+ nano = { labels = { en = [[n]] } }, -- 10^{-9}
+ micro = { labels = { en = [[\mu]] } }, -- 10^{-6}
+ milli = { labels = { en = [[m]] } }, -- 10^{-3}
+ centi = { labels = { en = [[c]] } }, -- 10^{-2}
+ deci = { labels = { en = [[d]] } }, -- 10^{-1}
+ deca = { labels = { en = [[da]] } }, -- 10^{1}
+ hecto = { labels = { en = [[h]] } }, -- 10^{2}
+ kilo = { labels = { en = [[k]] } }, -- 10^{3}
+ mega = { labels = { en = [[M]] } }, -- 10^{6}
+ giga = { labels = { en = [[G]] } }, -- 10^{9}
+ tera = { labels = { en = [[T]] } }, -- 10^{12}
+ peta = { labels = { en = [[P]] } }, -- 10^{15}
+ exa = { labels = { en = [[E]] } }, -- 10^{18}
+ zetta = { labels = { en = [[Z]] } }, -- 10^{21}
+ yotta = { labels = { en = [[Y]] } }, -- 10^{24}
+ kibi = { labels = { en = [[Ki]] } }, -- 2^{10} (not ki)
+ mebi = { labels = { en = [[Mi]] } }, -- 2^{20}
+ gibi = { labels = { en = [[Gi]] } }, -- 2^{30}
+ tebi = { labels = { en = [[Ti]] } }, -- 2^{40}
+ pebi = { labels = { en = [[Pi]] } }, -- 2^{50}
+ exbi = { labels = { en = [[Ei]] } }, -- 2^{60}
+ zebi = { labels = { en = [[Zi]] } }, -- binary
+ yobi = { labels = { en = [[Yi]] } }, -- binary
+ micro = { labels = { en = [[µ]] } }, -- 0x00B5 \textmu
+ root = { labels = { en = [[√]] } }, -- 0x221A
+}
+
+labels.units = allocate {
+ meter = { labels = { en = [[m]] } },
+ gram = { labels = { en = [[g]] } }, -- strictly kg is the base unit
+ second = { labels = { en = [[s]] } },
+ ampere = { labels = { en = [[A]] } },
+ kelvin = { labels = { en = [[K]] } },
+ mole = { labels = { en = [[mol]] } },
+ candela = { labels = { en = [[cd]] } },
+ mol = { labels = { en = [[mol]] } },
+ radian = { labels = { en = [[rad]] } },
+ steradian = { labels = { en = [[sr]] } },
+ hertz = { labels = { en = [[Hz]] } },
+ newton = { labels = { en = [[N]] } },
+ pascal = { labels = { en = [[Pa]] } },
+ joule = { labels = { en = [[J]] } },
+ watt = { labels = { en = [[W]] } },
+ coulomb = { labels = { en = [[C]] } },
+ volt = { labels = { en = [[V]] } },
+ farad = { labels = { en = [[F]] } },
+ ohm = { labels = { en = [[Ω]] } }, -- 0x2126 \textohm
+ siemens = { labels = { en = [[S]] } },
+ weber = { labels = { en = [[Wb]] } },
+ mercury = { labels = { en = [[Hg]] } },
+ millimetermercury = { labels = { en = [[mmHg]] } }, -- connected
+ tesla = { labels = { en = [[T]] } },
+ henry = { labels = { en = [[H]] } },
+ celsius = { labels = { en = [[\checkedtextcelsius]] } }, -- 0x2103
+ lumen = { labels = { en = [[lm]] } },
+ lux = { labels = { en = [[lx]] } },
+ becquerel = { labels = { en = [[Bq]] } },
+ gray = { labels = { en = [[Gy]] } },
+ sievert = { labels = { en = [[Sv]] } },
+ katal = { labels = { en = [[kat]] } },
+ minute = { labels = { en = [[min]] } },
+ hour = { labels = { en = [[h]] } },
+ day = { labels = { en = [[d]] } },
+ gon = { labels = { en = [[gon]] } },
+ grad = { labels = { en = [[grad]] } },
+ hectare = { labels = { en = [[ha]] } },
+ liter = { labels = { en = [[l]] } }, -- symbol l or L
+ tonne = { labels = { en = [[t]] } },
+ electronvolt = { labels = { en = [[eV]] } },
+ dalton = { labels = { en = [[Da]] } },
+ atomicmassunit = { labels = { en = [[u]] } },
+ astronomicalunit = { labels = { en = [[au]] } },
+ bar = { labels = { en = [[bar]] } },
+ angstrom = { labels = { en = [[Å]] } }, -- strictly Ångström
+ nauticalmile = { labels = { en = [[M]] } },
+ barn = { labels = { en = [[b]] } },
+ knot = { labels = { en = [[kn]] } },
+ neper = { labels = { en = [[Np]] } },
+ bel = { labels = { en = [[B]] } }, -- in practice only decibel used
+ erg = { labels = { en = [[erg]] } },
+ dyne = { labels = { en = [[dyn]] } },
+ poise = { labels = { en = [[P]] } },
+ stokes = { labels = { en = [[St]] } },
+ stilb = { labels = { en = [[sb]] } },
+ phot = { labels = { en = [[phot]] } },
+ gal = { labels = { en = [[gal]] } },
+ maxwell = { labels = { en = [[Mx]] } },
+ gauss = { labels = { en = [[G]] } },
+ oersted = { labels = { en = [[Oe]] } }, -- strictly Œrsted
+ bit = { labels = { en = [[bit]] } },
+ byte = { labels = { en = [[B]] } },
+ baud = { labels = { en = [[Bd]] } },
+ erlang = { labels = { en = [[E]] } },
+ atmosphere = { labels = { en = [[atm]] } },
+ revolution = { labels = { en = [[rev]] } },
+ fahrenheit = { labels = { en = [[\checkedtextfahrenheit]] } }, -- 0x2109
+ foot = { labels = { en = [[ft]] } },
+ inch = { labels = { en = [[inch]] } },
+ calorie = { labels = { en = [[cal]] } },
+ --
+ degree = { labels = { en = [[°]]} },
+ arcminute = { labels = { en = [[\checkedtextprime]] } }, -- ′ 0x2032
+ arcsecond = { labels = { en = [[\checkedtextdoubleprime]] } }, -- ″ 0x2033
+ percent = { labels = { en = [[\percent]] } },
+ permille = { labels = { en = [[\promille]] } },
+ --
+ micron = { labels = { en = [[\textmu m]] } },
+}
+
+labels.operators = allocate {
+ times = { labels = { en = [[\unitsTIMES]] } },
+ solidus = { labels = { en = [[\unitsSOLIDUS]] } },
+ per = { labels = { en = [[\unitsSOLIDUS]] } },
+ outof = { labels = { en = [[\unitsOUTOF]] } },
+}
+
+labels.suffixes = allocate {
+ linear = { labels = { en = [[1]] } },
+ square = { labels = { en = [[2]] } },
+ cubic = { labels = { en = [[3]] } },
+ quadratic = { labels = { en = [[4]] } },
+ inverse = { labels = { en = [[\mathminus1]] } },
+ ilinear = { labels = { en = [[\mathminus1]] } },
+ isquare = { labels = { en = [[\mathminus2]] } },
+ icubic = { labels = { en = [[\mathminus3]] } },
+ iquadratic = { labels = { en = [[\mathminus4]] } },
+}
+
+local function dimpus(p,u,s)
+ if trace_units then
+ report_units("prefix %a, unit %a, suffix %a",p,u,s)
+ end --
+ if p ~= "" then
+ if u ~= "" then
+ if s ~= "" then
+ ctx_unitsPUS(p,u,s)
+ else
+ ctx_unitsPU(p,u)
+ end
+ elseif s ~= "" then
+ ctx_unitsPS(p,s)
+ else
+ ctx_unitsP(p)
+ end
+ else
+ if u ~= "" then
+ if s ~= "" then
+ ctx_unitsUS(u,s)
+ -- elseif c then
+ -- ctx_unitsC(u)
+ else
+ ctx_unitsU(u)
+ end
+ elseif s ~= "" then
+ ctx_unitsS(s)
+ else
+ ctx_unitsP(p)
+ end
+ end
+end
+
+local function dimspu(s,p,u)
+ return dimpus(p,u,s)
+end
+
+local function dimop(o)
+ if trace_units then
+ report_units("operator %a",o)
+ end
+ if o then
+ ctx_unitsO(o)
+ end
+end
+
+local function dimsym(s)
+ if trace_units then
+ report_units("symbol %a",s)
+ end
+ s = symbol_units[s] or s
+ if s then
+ ctx_unitsC(s)
+ end
+end
+
+local function dimpre(p)
+ if trace_units then
+ report_units("prefix [%a",p)
+ end
+ p = packaged_units[p] or p
+ if p then
+ ctx_unitsU(p)
+ end
+end
+
+-- patterns:
+--
+-- space inside Cs else funny captures and args to function
+--
+-- square centi meter per square kilo seconds
+
+-- todo 0x -> rm
+
+local function update_parsers(keepcase) -- todo: don't remap utf sequences
+
+ local all_long_prefixes = { }
+ local all_long_units = { }
+ local all_long_operators = { }
+ local all_long_suffixes = { }
+ local all_symbol_units = { }
+ local all_packaged_units = { }
+
+ local all_short_prefixes = { }
+ local all_short_units = { }
+ local all_short_operators = { }
+ local all_short_suffixes = { }
+
+ for k, v in sortedhash(long_prefixes) do all_long_prefixes [k] = v all_long_prefixes [lower(k)] = v end
+ for k, v in sortedhash(long_units) do all_long_units [k] = v all_long_units [lower(k)] = v end
+ for k, v in sortedhash(long_operators) do all_long_operators[k] = v all_long_operators[lower(k)] = v end
+ for k, v in sortedhash(long_suffixes) do all_long_suffixes [k] = v all_long_suffixes [lower(k)] = v end
+ for k, v in sortedhash(symbol_units) do all_symbol_units [k] = v all_symbol_units [lower(k)] = v end
+ for k, v in sortedhash(packaged_units) do all_packaged_units[k] = v all_packaged_units[lower(k)] = v end
+
+ for k, v in sortedhash(user_long_prefixes) do all_long_prefixes [k] = v if not keepcase then all_long_prefixes [lower(k)] = v end end
+ for k, v in sortedhash(user_long_units) do all_long_units [k] = v if not keepcase then all_long_units [lower(k)] = v end end
+ for k, v in sortedhash(user_long_operators) do all_long_operators[k] = v if not keepcase then all_long_operators[lower(k)] = v end end
+ for k, v in sortedhash(user_long_suffixes) do all_long_suffixes [k] = v if not keepcase then all_long_suffixes [lower(k)] = v end end
+ for k, v in sortedhash(user_symbol_units) do all_symbol_units [k] = v if not keepcase then all_symbol_units [lower(k)] = v end end
+ for k, v in sortedhash(user_packaged_units) do all_packaged_units[k] = v if not keepcase then all_packaged_units[lower(k)] = v end end
+
+ for k, v in sortedhash(short_prefixes) do all_short_prefixes [k] = v end
+ for k, v in sortedhash(short_units) do all_short_units [k] = v end
+ for k, v in sortedhash(short_operators) do all_short_operators[k] = v end
+ for k, v in sortedhash(short_suffixes) do all_short_suffixes [k] = v end
+
+ for k, v in sortedhash(user_short_prefixes) do all_short_prefixes [k] = v end
+ for k, v in sortedhash(user_short_units) do all_short_units [k] = v end
+ for k, v in sortedhash(user_short_operators) do all_short_operators[k] = v end
+ for k, v in sortedhash(user_short_suffixes) do all_short_suffixes [k] = v end
+
+ local somespace = P(" ")^0/""
+
+ local p_long_prefix = appendlpeg(all_long_prefixes,nil,true)
+ local p_long_unit = appendlpeg(all_long_units,nil,true)
+ local p_long_operator = appendlpeg(all_long_operators,nil,true)
+ local p_long_suffix = appendlpeg(all_long_suffixes,nil,true)
+ local p_symbol = appendlpeg(all_symbol_units,nil,true)
+ local p_packaged = appendlpeg(all_packaged_units,nil,true)
+
+ local p_short_prefix = appendlpeg(all_short_prefixes)
+ local p_short_unit = appendlpeg(all_short_units)
+ local p_short_operator = appendlpeg(all_short_operators)
+ local p_short_suffix = appendlpeg(all_short_suffixes)
+
+ -- more efficient but needs testing
+
+-- local p_long_prefix = utfchartabletopattern(all_long_prefixes) / all_long_prefixes
+-- local p_long_unit = utfchartabletopattern(all_long_units) / all_long_units
+-- local p_long_operator = utfchartabletopattern(all_long_operators) / all_long_operators
+-- local p_long_suffix = utfchartabletopattern(all_long_suffixes) / all_long_suffixes
+-- local p_symbol = utfchartabletopattern(all_symbol_units) / all_symbol_units
+-- local p_packaged = utfchartabletopattern(all_packaged_units) / all_packaged_units
+
+-- local p_short_prefix = utfchartabletopattern(all_short_prefixes) / all_short_prefixes
+-- local p_short_unit = utfchartabletopattern(all_short_units) / all_short_units
+-- local p_short_operator = utfchartabletopattern(all_short_operators) / all_short_operators
+-- local p_short_suffix = utfchartabletopattern(all_short_suffixes) / all_short_suffixes
+
+ -- we can can cleanup some space issues here (todo)
+
+ local unitparser = P { "unit",
+ --
+ longprefix = Cs(V("somespace") * p_long_prefix),
+ shortprefix = Cs(V("somespace") * p_short_prefix),
+ longsuffix = Cs(V("somespace") * p_long_suffix),
+ shortsuffix = Cs(V("somespace") * p_short_suffix),
+ shortunit = Cs(V("somespace") * p_short_unit),
+ longunit = Cs(V("somespace") * p_long_unit),
+ longoperator = Cs(V("somespace") * p_long_operator),
+ shortoperator = Cs(V("somespace") * p_short_operator),
+ packaged = Cs(V("somespace") * p_packaged),
+ --
+ nothing = Cc(""),
+ somespace = somespace,
+ nospace = (1-somespace)^1, -- was 0
+ -- ignore = P(-1),
+ --
+ qualifier = Cs(V("somespace") * (lparent/"") * (1-rparent)^1 * (rparent/"")),
+ --
+ somesymbol = V("somespace")
+ * (p_symbol/dimsym)
+ * V("somespace"),
+ somepackaged = V("somespace")
+ * (V("packaged") / dimpre)
+ * V("somespace"),
+ -- someunknown = V("somespace")
+ -- * (V("nospace")/ctx_unitsU)
+ -- * V("somespace"),
+ --
+ combination = V("longprefix") * V("longunit") -- centi meter
+ + V("nothing") * V("longunit")
+ + V("shortprefix") * V("shortunit") -- c m
+ + V("nothing") * V("shortunit")
+ + V("longprefix") * V("shortunit") -- centi m
+ + V("shortprefix") * V("longunit"), -- c meter
+
+-- combination = ( V("longprefix") -- centi meter
+-- + V("nothing")
+-- ) * V("longunit")
+-- + ( V("shortprefix") -- c m
+-- + V("nothing")
+-- + V("longprefix")
+-- ) * V("shortunit") -- centi m
+-- + ( V("shortprefix") -- c meter
+-- ) * V("longunit"),
+
+
+ dimension = V("somespace")
+ * (
+ V("packaged") / dimpre
+ + (V("longsuffix") * V("combination")) / dimspu
+ + (V("combination") * (V("shortsuffix") + V("nothing"))) / dimpus
+ )
+ * (V("qualifier") / ctx_unitsQ)^-1
+ * V("somespace"),
+ operator = V("somespace")
+ * ((V("longoperator") + V("shortoperator")) / dimop)
+ * V("somespace"),
+ snippet = V("dimension")
+ + V("somesymbol"),
+ unit = ( V("snippet") * (V("operator") * V("snippet"))^0
+ + V("somepackaged")
+ )^1,
+ }
+
+ -- todo: avoid \ctx_unitsNstart\ctx_unitsNstop (weird that it can happen .. now catched at tex end)
+
+ local letter = R("az","AZ")
+ local bound = #(1-letter)
+ -- local number = lpeg.patterns.number
+ local number = Cs( P("$") * (1-P("$"))^1 * P("$")
+ + P([[\m{]]) * (1-P("}"))^1 * P("}")
+ + (1-letter-P(" "))^1 -- todo: catch { } -- not ok
+ ) / ctx_unitsN
+
+ local start = Cc(nil) / ctx_unitsNstart
+ local stop = Cc(nil) / ctx_unitsNstop
+ local space = P(" ") * Cc(nil) / ctx_unitsNspace
+ local open = P("(") * Cc(nil) / ctx_unitsPopen
+ local close = P(")") * Cc(nil) / ctx_unitsPclose
+
+ local range = somespace
+ * ( (P("±") + P("pm") * bound) / "" / ctx_unitsRPM
+ + (P("–") + P("to") * bound) / "" / ctx_unitsRTO )
+ * somespace
+
+ local about = (P("±") + P("pm") * bound) / "" / ctx_unitsRabout
+ * somespace
+
+ -- todo: start / stop
+
+ local function combine(parser)
+ return P { "start",
+ number = start * dleader * (parser + number) * stop,
+ anumber = space
+ * open
+ * V("about")^-1
+ * V("number")
+ * close,
+ rule = V("number")^-1
+ * (V("range") * V("number") + V("anumber"))^-1,
+ unit = unitparser,
+ about = about,
+ range = range,
+ space = space,
+ start = V("rule")
+ * V("unit")
+ * (V("space") * V("rule") * V("unit"))^0
+ + open
+ * V("number")
+ * (V("range") * V("number"))^-1
+ * close
+ * dtrailer^-1
+ * V("unit")
+ + V("number")
+ }
+ end
+
+ return combine(p_c_dparser), combine(c_p_dparser)
+end
+
+local p_c_parser_lowercase = nil
+local c_p_parser_lowercase = nil
+local p_c_parser_keepcase = nil
+local c_p_parser_keepcase = nil
+
+local dirty_lowercase = true
+local dirty_keepcase = true
+
+local v_reverse = interfaces.variables.reverse
+local v_keep = interfaces.variables.keep
+
+local function makeunit(order,option,str)
+ local reverse = order == v_reverse
+ local keep = option == v_keep
+ local parser
+ if keep then
+ if dirty_keepcase then
+ if trace_units then
+ report_units("initializing case %s parser","sensititive")
+ end
+ p_c_parser_keepcase, c_p_parser_keepcase = update_parsers(true)
+ dirty_keepcase = false
+ end
+ parser = reverse and p_c_parser_keepcase or c_p_parser_keepcase
+ else
+ if dirty_lowercase then
+ if trace_units then
+ report_units("initializing case %s parser","insensititive")
+ end
+ p_c_parser_lowercase, c_p_parser_lowercase = update_parsers()
+ dirty_lowercase = false
+ end
+ parser = reverse and p_c_parser_lowercase or c_p_parser_lowercase
+ end
+ if not matchlpeg(parser,str) then
+ report_units("unable to parse: %s",str)
+ context(str)
+ end
+end
+
+local function trigger(t,k,v)
+ rawset(t,k,v)
+ dirty_lowercase = true
+ dirty_keepcase = true
+end
+
+local t_units = {
+ prefixes = setmetatablenewindex(long_prefixes,trigger),
+ units = setmetatablenewindex(long_units,trigger),
+ operators = setmetatablenewindex(long_operators,trigger),
+ suffixes = setmetatablenewindex(long_suffixes,trigger),
+ symbols = setmetatablenewindex(symbol_units,trigger),
+ packaged = setmetatablenewindex(packaged_units,trigger),
+}
+
+local t_shortcuts = {
+ prefixes = setmetatablenewindex(short_prefixes,trigger),
+ units = setmetatablenewindex(short_units,trigger),
+ operators = setmetatablenewindex(short_operators,trigger),
+ suffixes = setmetatablenewindex(short_suffixes,trigger),
+}
+
+local t_userunits = {
+ prefixes = setmetatablenewindex(user_long_prefixes,trigger),
+ units = setmetatablenewindex(user_long_units,trigger),
+ operators = setmetatablenewindex(user_long_operators,trigger),
+ suffixes = setmetatablenewindex(user_long_suffixes,trigger),
+ symbols = setmetatablenewindex(user_symbol_units,trigger),
+ packaged = setmetatablenewindex(user_packaged_units,trigger),
+}
+
+local t_usershortcuts = {
+ prefixes = setmetatablenewindex(user_short_prefixes,trigger),
+ units = setmetatablenewindex(user_short_units,trigger),
+ operators = setmetatablenewindex(user_short_operators,trigger),
+ suffixes = setmetatablenewindex(user_short_suffixes,trigger),
+}
+
+physics.units.tables = allocate {
+ units = t_units,
+ shortcuts = t_shortcuts,
+ userunits = t_userunits,
+ usershortcuts = t_usershortcuts,
+}
+
+local mapping = {
+ prefix = "prefixes",
+ unit = "units",
+ operator = "operators",
+ suffix = "suffixes",
+ symbol = "symbols",
+ packaged = "packaged",
+}
+
+local function register(category,list,target)
+ if not list or list == "" then
+ list = category
+ category = "unit"
+ end
+ local t = target[mapping[category]]
+ if t then
+ for k, v in next, utilities.parsers.settings_to_hash(list or "") do
+ t[k] = v
+ end
+ end
+ -- inspect(tables)
+end
+
+local function registerunit (category,list) register(category,list,t_userunits) end
+local function registershortcut(category,list) register(category,list,t_usershortcuts) end
+
+physics.units.registerunit = registerunit
+physics.units.registershortcut = registershortcut
+
+implement {
+ name = "digits_normal",
+ actions = makedigits,
+ arguments = "string",
+}
+
+implement {
+ name = "digits_reverse",
+ actions = makedigits,
+ arguments = { "string", true },
+}
+
+implement {
+ name = "unit",
+ actions = makeunit,
+ arguments = "3 strings"
+}
+
+implement {
+ name = "registerunit",
+ actions = registerunit,
+ arguments = "2 strings",
+}
+
+implement {
+ name = "registerunitshortcut",
+ actions = registershortcut,
+ arguments = "2 strings",
+}
+
+implement {
+ name = "hyphenateddigits",
+ public = true,
+ protected = true,
+ arguments = { "optional", "string" },
+ actions = function(filler, digits)
+ digits = gsub(digits,"(%d)","%1\\digitsbreak ") -- space needed for following letters
+ digits = gsub(digits,"\\-$",filler)
+ context(digits)
+ end
+}
diff --git a/tex/context/base/mkxl/phys-dim.mkxl b/tex/context/base/mkxl/phys-dim.mkxl
index 8277ba231..1d5e7fff6 100644
--- a/tex/context/base/mkxl/phys-dim.mkxl
+++ b/tex/context/base/mkxl/phys-dim.mkxl
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\registerctxluafile{phys-dim}{}
+\registerctxluafile{phys-dim}{autosuffix}
% TAGGING NEEDS CHECKING ... WILL DO WHEN PARSER IS OK
@@ -354,7 +354,8 @@
[\c!alternative=, % done: text
\c!separator=\v!normal, % done: cdot|big|medium|space
\s!language=\currentlanguage, % done: (no interface yet)
- \c!order=\v!normal, % ,. (reverse: .,)
+ \c!order=, % reverse
+ \c!option=, % keep (case)
\c!method=0,
%\c!grid=\v!yes, % (maybe)
%\c!style=..., % done
@@ -431,7 +432,7 @@
\to \everyunits
\appendtoks
- \frozen\instance\setuevalue\currentunit{\phys_units_direct{\currentunit}}
+ \frozen\protected\instance\edefcsname\currentunit\endcsname{\phys_units_direct{\currentunit}}
\to \everydefineunit
\protected\def\phys_units_direct#1%
@@ -441,9 +442,10 @@
\settrue\c_phys_units_dospace
\removelastskip
\fi
+ \edef\currentunit{#1}%
\c_phys_digits_method\unitparameter\c!method\relax
\ifmmode\else\dontleavehmode\fi
- \edef\currentunit{#1}%
+% \edef\currentunit{#1}%
\enforced\edef\unitlanguage{\unitparameter\s!language}%
\enforced\let\prefixlanguage\unitlanguage
\enforced\let\operatorlanguage\unitlanguage
@@ -503,9 +505,17 @@
\let\phys_units_direct\phys_units_direct_nested
\to \everyunits
+% \protected\def\phys_units_indeed#1%
+% {\edef\p_order{\unitparameter\c!order}%
+% \ifx\p_order\v!reverse
+% \expandafter\clf_unit_reverse
+% \else
+% \expandafter\clf_unit_normal
+% \fi
+% {\detokenize{#1}}}
+
\protected\def\phys_units_indeed#1%
- {\edef\p_order{\unitparameter\c!order}%
- \ifx\p_order\v!reverse\expandafter\clf_unit_reverse\else\expandafter\clf_unit_normal\fi{\detokenize{#1}}}
+ {\clf_unit{\unitparameter\c!order}{\unitparameter\c!option}{\detokenize{#1}}}
\permanent\protected\def\unitsPUS#1#2#3{\phys_units_next\prefixtext{#1}\unittext{#2}\unitsraise{\suffixtext{#3}}\c_phys_units_state\plusone} % suffix
\permanent\protected\def\unitsPU #1#2{\phys_units_next\prefixtext{#1}\unittext{#2}\c_phys_units_state\plusthree} % unit
@@ -682,7 +692,7 @@
\setfalse\c_phys_units_dospace
\phys_units_start}
-\permanent\protected\def\unitsTIMES % GP: Does this do anything? HH: yes "times"
+\permanent\protected\def\unitsTIMES % GP: Does this do anything? HH: yes "times"
{\ifnum\c_phys_units_state=\plusone % suffix
\else
\unitssmallspace
@@ -737,8 +747,44 @@
%D cicero=cc]
%D \stoptyping
-\permanent\tolerant\protected\def\registerunit[#1]#*[#2]% todo: public implementer
- {\clf_registerunit{#1}{#2}}
+\permanent\tolerant\protected\def\registerunit [#1]#*[#2]{\clf_registerunit {#1}{#2}}
+\permanent\tolerant\protected\def\registerunitshortcut[#1]#*[#2]{\clf_registerunitshortcut{#1}{#2}}
+
+%D \starttyping
+%D \registerunit
+%D [unit]
+%D [Point=PT,
+%D point=pt,
+%D Basepoint=BP,
+%D % basepoint=bp,
+%D ]
+%D
+%D \registerunitshortcut
+%D [unit]
+%D [C=coulomb]
+%D
+%D \startlines
+%D 10 \unit {square meter per second}
+%D 10 \unit {square Meter per Second}
+%D 10 \unit {point}
+%D 10 \unit {Point}
+%D 10 \unit {basepoint}
+%D 10 \unit {Basepoint}
+%D 10 \unit {C}
+%D \stoplines
+%D
+%D \setupunit[unit][option=keep]
+%D
+%D \startlines
+%D 10 \unit {square meter per second}
+%D 10 \unit {square Meter per Second}
+%D 10 \unit {point}
+%D 10 \unit {Point}
+%D 10 \unit {basepoint}
+%D 10 \unit {Basepoint}
+%D 10 \unit {C}
+%D \stoplines
+%D \stoptyping
%D You can generate a list as follows:
%D
diff --git a/tex/context/base/mkxl/strc-flt.mklx b/tex/context/base/mkxl/strc-flt.mklx
index 6af22631a..c96fb02d0 100644
--- a/tex/context/base/mkxl/strc-flt.mklx
+++ b/tex/context/base/mkxl/strc-flt.mklx
@@ -531,9 +531,9 @@
\def\strc_floats_apply_caption_command
{\setbox\b_strc_floats_caption\hbox\bgroup
- %\unless\ifcstok{\floatcaptionparameter\c!command}\emptytoks
+ %\unless\iftok{\floatcaptionparameter\c!command}\emptytoks
\floatcaptionparameter\c!command{\box\b_strc_floats_caption}%
- %\orunless\ifcstok{\floatcaptionparameter\c!deeptextcommand}\emptytoks
+ %\orunless\iftok{\floatcaptionparameter\c!deeptextcommand}\emptytoks
% \floatcaptionparameter\c!deeptextcommand{\unvbox\b_strc_floats_caption}%
%\else
% \box\b_strc_floats_caption
diff --git a/tex/context/base/mkxl/strc-lst.mklx b/tex/context/base/mkxl/strc-lst.mklx
index 6b8f2504f..dd9f1fb4d 100644
--- a/tex/context/base/mkxl/strc-lst.mklx
+++ b/tex/context/base/mkxl/strc-lst.mklx
@@ -1498,7 +1498,8 @@
\ifcsname\??listinteractions\p_interaction_forward\endcsname
%\expandafter\let\expandafter\p_interaction_forward\csname\??listinteractions\p_interaction_forward\endcsname
\expandafter\let\expandafter\p_interaction_forward\lastnamedcs
- \ifcstok{\structurelistexternal}\emptytoks % luacall
+ %\ifcstok{\structurelistexternal}\emptytoks % luacall
+ \iftok{\structurelistexternal}\emptytoks % luacall
\strc_references_get_simple_reference{internal(\currentlistentrylocation)}%
\else
% \writestatus{FAR OUT LIST}{\structurelistexternal::page(\number\structurelistrealpagenumber)}%
diff --git a/tex/context/base/mkxl/syst-aux.mkxl b/tex/context/base/mkxl/syst-aux.mkxl
index 2b87f4b3d..c3a4a97b2 100644
--- a/tex/context/base/mkxl/syst-aux.mkxl
+++ b/tex/context/base/mkxl/syst-aux.mkxl
@@ -587,7 +587,7 @@
% or (test this):
%
% \permanent\protected\def\processallactionsinset[#1]%
-% {\ifcstok{#1}\emptytoks
+% {\iftok{#1}\emptytoks
% \expandafter\processaction
% \else
% \expandafter\syst_helpers_process_all_actions_in_set_indeed
diff --git a/tex/context/base/mkxl/syst-ini.mkxl b/tex/context/base/mkxl/syst-ini.mkxl
index 2b37e30c6..46f02653a 100644
--- a/tex/context/base/mkxl/syst-ini.mkxl
+++ b/tex/context/base/mkxl/syst-ini.mkxl
@@ -1308,7 +1308,7 @@
\endlocalcontrol
#2}
-\permanent\protected\def\suggestedalias#1#2%
+\permanent\protected\def\suggestedalias#1#2% old new
{\ifflags#2\permanent\permanent\fi % the rest is taken with the copy
\def#1{\syst_suggested_alias#1#2}}
diff --git a/tex/context/base/mkxl/tabl-ntb.mkxl b/tex/context/base/mkxl/tabl-ntb.mkxl
index 414a04f3a..6e95512cd 100644
--- a/tex/context/base/mkxl/tabl-ntb.mkxl
+++ b/tex/context/base/mkxl/tabl-ntb.mkxl
@@ -2377,7 +2377,7 @@
\tabl_ntb_section_disable}
\tolerant\permanent\protected\def\bTABLEsection[#1]%
- {\ifempty{#1}%
+ {\iftok{#1}\emptytoks
\global\c_tabl_ntb_section_repeat\zerocount
\else
\letdummyparameter\c!repeat\zerocount
diff --git a/tex/context/base/mkxl/tabl-tab.mkxl b/tex/context/base/mkxl/tabl-tab.mkxl
index 8c872cd47..c680a4474 100644
--- a/tex/context/base/mkxl/tabl-tab.mkxl
+++ b/tex/context/base/mkxl/tabl-tab.mkxl
@@ -504,7 +504,7 @@
% Key "M": Displaymath mode.
\newtableformatkey M%
- {\doreadtableformatkeys \{ b{\normalstartimath\displaystyle} a{\normalstopimath}}
+ {\doreadtableformatkeys \{ b{\normalstartimath\forcedisplaymath} a{\normalstopimath}}
% Key "\m": Template ${}#\hfil$
diff --git a/tex/context/base/mkxl/tabl-tbl.mkxl b/tex/context/base/mkxl/tabl-tbl.mkxl
index 6c4c3fd47..d353074d5 100644
--- a/tex/context/base/mkxl/tabl-tbl.mkxl
+++ b/tex/context/base/mkxl/tabl-tbl.mkxl
@@ -589,7 +589,7 @@
\installtabulatepreambleoption{m}{\t_tabl_tabulate_bmath{\normalstartimath}%
\t_tabl_tabulate_emath{\normalstopimath}%
\tabl_tabulate_set_preamble}
-\installtabulatepreambleoption{M}{\t_tabl_tabulate_bmath{\normalstartimath\displaystyle}%
+\installtabulatepreambleoption{M}{\t_tabl_tabulate_bmath{\normalstartimath\forcedisplaymath}%
\t_tabl_tabulate_emath{\normalstopimath}%
\tabl_tabulate_set_preamble}
\installtabulatepreambleoption{h}{\tabl_tabulate_set_hook}
diff --git a/tex/context/base/mkxl/typo-ada.lmt b/tex/context/base/mkxl/typo-ada.lmt
index 37393ca77..099479383 100644
--- a/tex/context/base/mkxl/typo-ada.lmt
+++ b/tex/context/base/mkxl/typo-ada.lmt
@@ -62,12 +62,13 @@ function adaptive.set(settings)
texsetattribute(a_adaptive,registervalue(a_adaptive,settings))
end
-local function setadaptive(w,h,d,l,c)
+local function setadaptive(w,h,d,l,c,a)
setdimen(d_adaptive_width,w)
setdimen(d_adaptive_height,h)
setdimen(d_adaptive_depth,d)
setdimen(d_adaptive_line,l)
setmacro("m_adaptive_color",c)
+ setmacro("m_adaptive_alternative",a)
end
local methods = {
@@ -76,7 +77,7 @@ local methods = {
local setups = settings.setups
if setups and setups ~= "" then
local w, h, d = getwhd(parent)
- setadaptive(w,h,d,settings.rulethickness,settings.color)
+ setadaptive(w,h,d,settings.rulethickness,settings.color,settings.alternative)
expandmacro("setup",true,setups)
local l = takebox("b_adaptive_box")
if l then
@@ -150,6 +151,7 @@ interfaces.implement {
{ "mp", "string" },
{ "color", "string" },
{ "rulethickness", "dimension" },
+ { "alternative", "string" },
}
}
}
diff --git a/tex/context/base/mkxl/typo-ada.mkxl b/tex/context/base/mkxl/typo-ada.mkxl
index 733b2ca5b..d6eae4249 100644
--- a/tex/context/base/mkxl/typo-ada.mkxl
+++ b/tex/context/base/mkxl/typo-ada.mkxl
@@ -39,6 +39,10 @@
\aliased\let\usedadaptivebox\b_adaptive_box
\mutable\lettonothing\m_adaptive_color
+\mutable\lettonothing\m_adaptive_alternative
+
+\permanent\def\usedadaptivecolor {\m_adaptive_color}
+\permanent\def\usedadaptivealternative{\m_adaptive_alternative}
\protected\untraced\def\usedadaptivetotal{\dimexpr\usedadaptiveheight+\usedadaptivedepth\relax}
@@ -56,6 +60,7 @@
[\c!foregroundstyle=,
\c!foregroundcolor=,
\c!color=gray,
+ \c!alternative=,
\c!rulethickness=\linewidth,
\c!method=1,
\c!stretch=,
@@ -95,6 +100,7 @@
method \adaptiveparameter\c!method
setups {\p_setups}%
color {\adaptiveparameter\c!color}%
+ alternative {\adaptiveparameter\c!alternative}%
rulethickness \adaptiveparameter\c!rulethickness
}%
\fi
diff --git a/tex/context/base/mkxl/typo-adj.mkxl b/tex/context/base/mkxl/typo-adj.mkxl
index 5c129f07e..bf754cdbf 100644
--- a/tex/context/base/mkxl/typo-adj.mkxl
+++ b/tex/context/base/mkxl/typo-adj.mkxl
@@ -51,7 +51,7 @@
\tolerant\def\typo_adjusters_blank#1[#2]% no need for speed
{\begingroup
- % \setbox\scratchbox\vbox{\ifcstok{#2}\emptytoks\blank\else\blank[#2]\fi}%
+ % \setbox\scratchbox\vbox{\iftok{#2}\emptytoks\blank\else\blank[#2]\fi}%
\setbox\scratchbox\vbox{\blank[#2]}%
\vadjust #1 index \plustwo {\vskip\htdp\scratchbox}%
\endgroup}
diff --git a/tex/context/base/mkxl/unic-ini.lmt b/tex/context/base/mkxl/unic-ini.lmt
new file mode 100644
index 000000000..aafaf0ae7
--- /dev/null
+++ b/tex/context/base/mkxl/unic-ini.lmt
@@ -0,0 +1,26 @@
+if not modules then modules = { } end modules ['unic-ini'] = {
+ version = 1.001,
+ comment = "companion to unic-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local context = context
+local utfchar = utf.char
+
+-- Beware, initializing unicodechar happens at first usage and takes
+-- 0.05 -- 0.1 second (lots of function calls).
+
+interfaces.implement {
+ name = "unicodechar",
+ public = true,
+ protected = true,
+ arguments = "argument",
+ actions = function(asked)
+ local n = characters.unicodechar(asked)
+ if n then
+ context(utfchar(n))
+ end
+ end
+}
diff --git a/tex/context/base/mkxl/unic-ini.mkxl b/tex/context/base/mkxl/unic-ini.mkxl
index aedfe47ed..7d2302dae 100644
--- a/tex/context/base/mkxl/unic-ini.mkxl
+++ b/tex/context/base/mkxl/unic-ini.mkxl
@@ -13,7 +13,7 @@
\writestatus{loading}{ConTeXt Unicode Support / Initialization}
-\registerctxluafile{unic-ini}{}
+\registerctxluafile{unic-ini}{autosuffix}
\unprotect
@@ -26,7 +26,8 @@
%D
%D \typebuffer \getbuffer
-\permanent\def\unicodechar#1{\clf_unicodechar{#1}}
+% \permanent\def\unicodechar#1% defined at the lua end
+% {\clf_unicodechar{#1}}
\permanent\protected\def\unknownchar
{\dontleavehmode\hpack{\vrule\s!width.5\emwidth\s!height\exheight\s!depth\zeropoint}}
diff --git a/tex/context/fonts/mkiv/antykwa-math.lfg b/tex/context/fonts/mkiv/antykwa-math.lfg
index 5bbd2cf6c..2965332e4 100644
--- a/tex/context/fonts/mkiv/antykwa-math.lfg
+++ b/tex/context/fonts/mkiv/antykwa-math.lfg
@@ -3,19 +3,19 @@ local helpers = common.mathematics.helpers
if not fonts.encodings.math["extensible-jmn-private"] then
- local nps = fonts.helpers.newprivateslot
+ local ps = fonts.helpers.privateslot
fonts.encodings.math["extensible-jmn-private"] = {
- [nps("rule middle piece")] = 200, -- minusjmn
- [nps("rule right piece")] = 201, -- minusrightjmn
- [nps("rule left piece")] = 202, -- minusleftjmn
- [nps("double rule middle piece")] = 203, -- equaljmn
- [nps("double rule right piece")] = 204, -- equalrightjmn
- [nps("double rule left piece")] = 205, -- equalleftjmn
- [nps("arrow left piece")] = 206, -- arrowleftjmn
- [nps("arrow right piece")] = 207, -- arrowrightjmn
- [nps("double arrow left piece")] = 208, -- arrowdblleftjmn
- [nps("double arrow right piece")] = 209, -- arrowdblrightjmn
+ [ps("rule middle piece")] = 200, -- minusjmn
+ [ps("rule right piece")] = 201, -- minusrightjmn
+ [ps("rule left piece")] = 202, -- minusleftjmn
+ [ps("double rule middle piece")] = 203, -- equaljmn
+ [ps("double rule right piece")] = 204, -- equalrightjmn
+ [ps("double rule left piece")] = 205, -- equalleftjmn
+ [ps("arrow left piece")] = 206, -- arrowleftjmn
+ [ps("arrow right piece")] = 207, -- arrowrightjmn
+ [ps("double arrow left piece")] = 208, -- arrowdblleftjmn
+ [ps("double arrow right piece")] = 209, -- arrowdblrightjmn
}
end
diff --git a/tex/context/fonts/mkiv/common-math-jmn.lfg b/tex/context/fonts/mkiv/common-math-jmn.lfg
index 331d65a5d..bcbe77962 100644
--- a/tex/context/fonts/mkiv/common-math-jmn.lfg
+++ b/tex/context/fonts/mkiv/common-math-jmn.lfg
@@ -8,6 +8,10 @@ return {
helpers = {
addmissing = function(main)
+ local max = math.max
+ local copytable = table.copy
+ local slotcommand = fonts.helpers.commands.slot
+
local builders = fonts.handlers.vf.math.builders
local ps = fonts.helpers.privateslot
@@ -25,8 +29,8 @@ return {
local llbracepiece = ps("ll brace piece")
local lrbracepiece = ps("lr brace piece")
- builders.brace(main,0x23DE,ulbracepiece,cmbracepiece,lrbracepiece,llbracepiece,cmbracepiece,urbracepiece)
- builders.brace(main,0x23DF,llbracepiece,cmbracepiece,urbracepiece,ulbracepiece,cmbracepiece,lrbracepiece)
+ builders.brace(main,0x23DE,ulbracepiece,cmbracepiece,lrbracepiece,llbracepiece,cmbracepiece,urbracepiece,"top")
+ builders.brace(main,0x23DF,llbracepiece,cmbracepiece,urbracepiece,ulbracepiece,cmbracepiece,lrbracepiece,"bottom")
builders.parent(main,0x23DC,ulbracepiece,umbracepiece,urbracepiece,"top")
builders.parent(main,0x23DD,llbracepiece,lmbracepiece,lrbracepiece,"bottom")
@@ -39,13 +43,21 @@ return {
builders.jointwo(main,0x21A6,ps("maps to piece"),.15,0x02192) -- \mapstochar\rightarrow
+ local srl = ps("rule left piece")
local srm = ps("rule middle piece")
local srr = ps("rule right piece")
- local srl = ps("rule left piece")
+ local drl = ps("double rule left piece")
local drm = ps("double rule middle piece")
local drr = ps("double rule right piece")
- local drl = ps("double rule left piece")
+
+ local sfl = ps("flat rule left piece")
+ local sfm = ps("flat rule middle piece")
+ local sfr = ps("flat rule right piece")
+
+ local dfl = ps("flat double rule left piece")
+ local dfm = ps("flat double rule middle piece")
+ local dfr = ps("flat double rule right piece")
local sal = ps("arrow left piece")
local sar = ps("arrow right piece")
@@ -55,32 +67,90 @@ return {
local rad = ps("radical bar extender")
- if characters[srm] then
+ local antykwa = characters[srm]
+
+ if not antykwa then
- builders.jointwo(main,0x27F5,sak,joinrelfactor,srr)
- builders.jointwo(main,0x27F6,srl,joinrelfactor,sar)
- builders.jointwo(main,0x27F7,sak,joinrelfactor,sar)
- builders.jointwo(main,0x27F8,dal,joinrelfactor,drr)
- builders.jointwo(main,0x27F9,drl,joinrelfactor,dar)
- builders.jointwo(main,0x27FA,dal,joinrelfactor,dar)
+ sal = 0x02190 sar = 0x02192
+ dal = 0x021D0 dar = 0x021D2
+ srl = 0x0002D srr = 0x0002D
+ drl = 0x0003D drr = 0x0003D
+
+ sfl = 0x0002D srm = 0x0002D
+ dfl = 0x0003D drm = 0x0003D
+
+ end
+
+ if not characters[sfm] then
+
+ local csal = characters[sal] local sheight = csal.height local sdepth = csal.depth
+ local cdal = characters[dal] local dheight = cdal.height local ddepth = cdal.depth
+
+ local csfl = copytable(characters[srl]) characters[sfl] = csfl csfl.height = sheight csfl.depth = sdepth csfl.italic = nil
+ local csfm = copytable(characters[srm]) characters[sfm] = csfm csfm.height = sheight csfm.depth = sdepth csfm.italic = nil
+ local csfr = copytable(characters[srr]) characters[sfr] = csfr csfr.height = sheight csfr.depth = sdepth csfr.italic = nil
+ local cdfl = copytable(characters[drl]) characters[dfl] = cdfl cdfl.height = dheight cdfl.depth = ddepth cdfl.italic = nil
+ local cdfm = copytable(characters[drm]) characters[dfm] = cdfm cdfm.height = dheight cdfm.depth = ddepth cdfm.italic = nil
+ local cdfr = copytable(characters[drr]) characters[dfr] = cdfr cdfr.height = dheight cdfr.depth = ddepth cdfr.italic = nil
+
+ end
+
+ builders.jointwo(main,0x27F5,sal,joinrelfactor,srr)
+ builders.jointwo(main,0x27F6,srl,joinrelfactor,sar)
+ builders.jointwo(main,0x27F7,sal,joinrelfactor,sar)
+ builders.jointwo(main,0x27F8,dal,joinrelfactor,drr)
+ builders.jointwo(main,0x27F9,drl,joinrelfactor,dar)
+ builders.jointwo(main,0x27FA,dal,joinrelfactor,dar)
+
+ if antykwa then
builders.horibar(main,0x203E,srm,srl,srr,0x02212) -- overbar underbar fraction (we take 90/91/92 too!)
-- builders.horibar(main,0x203E,srm,srl,srr,0x0002D) -- overbar underbar fraction (we take 90/91/92 too!)
+ builders.rootbar(main,rad,srm,srr,0x02212) -- radical
+ else
+ builders.horibar(main,0x203E,0xFE073) -- overbar underbar
+ end
- builders.rootbar(main,ps("radical bar extender"),srm,srr,0x02212) -- radical
+ local ffactor = antykwa and 1 or 1
+ local mfactor = antykwa and 1 or .8
+ local lfactor = antykwa and 1 or .8
- else
+ builders.extension(main,0x2190,sal,sfm,sfr,ffactor,mfactor,lfactor) -- \leftarrow
+ builders.extension(main,0x2192,sfl,sfm,sar,ffactor,mfactor,lfactor) -- \rightarrow
+ builders.extension(main,0x27F5,sal,sfm,sfr,ffactor,mfactor,lfactor)
+ builders.extension(main,0x27F6,sfl,sfm,sar,ffactor,mfactor,lfactor)
+ builders.extension(main,0x27F7,sal,sfm,sar,ffactor,mfactor,lfactor)
+ builders.extension(main,0x27F8,dal,dfm,dfr,ffactor,mfactor,lfactor)
+ builders.extension(main,0x27F9,dfl,dfm,dar,ffactor,mfactor,lfactor)
+ builders.extension(main,0x27FA,dal,dfm,dar,ffactor,mfactor,lfactor)
- builders.jointwo(main,0x27F5,0x02190,joinrelfactor,0x0002D) -- \leftarrow\joinrel\relbar
- builders.jointwo(main,0x27F6,0x0002D,joinrelfactor,0x02192) -- \relbar\joinrel\rightarrow
- builders.jointwo(main,0x27F7,0x02190,joinrelfactor,0x02192) -- \leftarrow\joinrel\rightarrow
- builders.jointwo(main,0x27F8,0x021D0,joinrelfactor,0x0003D) -- \Leftarrow\joinrel\Relbar
- builders.jointwo(main,0x27F9,0x0003D,joinrelfactor,0x021D2) -- \Relbar\joinrel\Rightarrow
- builders.jointwo(main,0x27FA,0x021D0,joinrelfactor,0x021D2) -- \Leftarrow\joinrel\Rightarrow
+ local tfactor = antykwa and -0.8 or -0.8
+ local bfactor = antykwa and 0.1 or 0.1
- builders.horibar(main,0x203E,0xFE073) -- overbar underbar
+ local left = characters[0x27F5]
+ local right = characters[0x27F6]
+ local both = characters[0x27F7]
- end
+ local height = max(left.height or 0,right.height or 0,both.height or 0)
+ local depth = max(left.depth or 0,right.depth or 0,both.depth or 0)
+
+ left .height = height left .depth = depth
+ right.height = height right.depth = depth
+ both .height = height both .depth = depth
+
+ local t = copytable(left) characters[0x20D6] = t t.inneryoffset = tfactor*height t.innerlocation = "top" t.next = nil t.italic = nil -- over
+ local t = copytable(right) characters[0x20D7] = t t.inneryoffset = tfactor*height t.innerlocation = "top" t.next = nil t.italic = nil
+ local t = copytable(both) characters[0x20E1] = t t.inneryoffset = tfactor*height t.innerlocation = "top" t.next = nil t.italic = nil
+
+ local t = copytable(left) characters[0x20EE] = t t.inneryoffset = bfactor*height t.innerlocation = "bottom" t.next = nil t.italic = nil -- under
+ local t = copytable(right) characters[0x20EF] = t t.inneryoffset = bfactor*height t.innerlocation = "bottom" t.next = nil t.italic = nil
+ local t = copytable(both) characters[0x034D] = t t.inneryoffset = bfactor*height t.innerlocation = "bottom" t.next = nil t.italic = nil
+
+ local tfactor = antykwa and -15 or -15
+ local bfactor = antykwa and 1 or 1
+
+ local t = copytable(characters[0x203E]) characters[0x0305] = t t.inneryoffset = tfactor*t.height t.innerlocation = "top" t.next = nil t.italic = nil
+ local t = copytable(characters[0x203E]) characters[0x0332] = t t.inneryoffset = bfactor*t.height t.innerlocation = "bottom" t.next = nil t.italic = nil
builders.jointwo(main,0x2016,0x007C,0.20,0x007C)
builders.jointwo(main,0x2980,0x007C,0.20,0x007C,0.20,0x007C)
@@ -105,7 +175,9 @@ return {
builders.overlaytwo(main,0x2285,0x00338,notshiftfactor,0x02283) -- \not\supset
builders.overlaytwo(main,0x2209,0x00338,notshiftfactor,0x02208) -- \not\in
- builders.jointwo(main,0x2254,0x03A,0,0x03D) -- := (≔)
+ -- builders.jointwo (main,0x2254,0x03A,0,0x03D) -- :=
+ -- builders.jointhree(main,0x2A74,0x03A,0,0x03A,0,0x03D) -- ::=
+ -- builders.jointwo (main,0x2A75,0x03D,0,0x03D) -- ==
builders.repeated(main,0x222B,0x222B,1,1/2)
builders.repeated(main,0x222C,0x222B,2,1/2)
@@ -113,6 +185,11 @@ return {
characters[0x02B9] = characters[0x2032] -- we're nice
+ -- some things are done automatically:
+
+ -- add primes
+ -- add equals and alike
+
end
}
}
diff --git a/tex/context/fonts/mkiv/ebgaramond-math.lfg b/tex/context/fonts/mkiv/ebgaramond-math.lfg
index 812430525..f6f552dfe 100644
--- a/tex/context/fonts/mkiv/ebgaramond-math.lfg
+++ b/tex/context/fonts/mkiv/ebgaramond-math.lfg
@@ -12,8 +12,8 @@ return {
FractionRuleThickness = 60,
OverbarRuleThickness = 60,
UnderbarRuleThickness = 60,
- AccentTopShiftUp = -75,
- FlattenedAccentTopShiftUp = -75,
+ AccentTopShiftUp = -25, -- was 075
+ FlattenedAccentTopShiftUp = -25, -- was 075
AccentBaseDepth = 75,
DelimiterPercent = 90,
DelimiterShortfall = 400,
@@ -82,9 +82,9 @@ return {
[0x27EB] = { topright = -0.1, bottomright = -0.1 },
["0x27EB.variants.*"] = { topright = -0.2, bottomright = -0.2 },
- [0x51] = { bottomright = 0.25 }, -- Upright Q
- [0x211A] = { bottomright = 0.2 }, -- Blackboard bold Q
- [0x1D410] = { bottomright = 0.2 }, -- Bold Q
+ [0x00051] = { bottomright = 0.25 }, -- Upright Q
+ [0x0211A] = { bottomright = 0.2 }, -- Blackboard bold Q
+ [0x1D410] = { bottomright = 0.2 }, -- Bold Q
[0x1D478] = { bottomright = 0.05 }, -- Bold Q
[0x1D5B0] = { bottomright = 0.05 }, -- Sans Q
},
@@ -173,6 +173,24 @@ return {
tweak = "addrules",
},
{
+ tweak = "replacerules",
+ fraction = {
+ template = "minus", -- 0x2212,
+ xoffset = 0.075,
+ yoffset = 0.9,
+ -- width = 0.85,
+ -- height = 0.1,
+ },
+ radical = {
+ template = "minus", -- 0x2212,
+ xoffset = 0.075,
+ yoffset = 0.9,
+ yscale = 0.975,
+ -- width = 0.85,
+ -- height = 0.1,
+ },
+ },
+ {
tweak = "addbars",
advance = 0.6,
},
diff --git a/tex/context/fonts/mkiv/lucida-math.lfg b/tex/context/fonts/mkiv/lucida-math.lfg
index 64f53dc33..28510ac2d 100644
--- a/tex/context/fonts/mkiv/lucida-math.lfg
+++ b/tex/context/fonts/mkiv/lucida-math.lfg
@@ -14,7 +14,7 @@ return {
mathematics = {
parameters = {
FractionRuleThickness = 55,
- AccentBaseDepth = 250,
+ -- AccentBaseDepth = 250,
DelimiterPercent = 90,
DelimiterShortfall = 400,
SuperscriptBottomMaxWithSubscript = 325,
@@ -32,18 +32,18 @@ return {
tweak = "fixoldschool",
version = "Version 1.802",
},
-{
- tweak = "parameters",
- feature = "boldmath",
- list = {
--- RadicalRuleThickness = 55,
- RadicalRuleThickness = 60,
--- RadicalRuleThickness = "1.09*RadicalRuleThickness",
--- FractionRuleThickness = 65,
--- OverRuleThickness = 65,
--- UnderRuleThickness = 65,
- }
-},
+ {
+ tweak = "parameters",
+ feature = "boldmath",
+ list = {
+ -- RadicalRuleThickness = 55,
+ RadicalRuleThickness = 60,
+ -- RadicalRuleThickness = "1.09*RadicalRuleThickness",
+ -- FractionRuleThickness = 65,
+ -- OverRuleThickness = 65,
+ -- UnderRuleThickness = 65,
+ }
+ },
{
tweak = "addmirrors",
},
@@ -59,6 +59,22 @@ return {
presets.moveintegrals { factor = 1.5 },
presets.wipeitalics { },
{
+ tweak = "replacealphabets",
+ filename = "lucidabrightot.otf",
+ keep = true,
+ list = {
+ { source = "latinsupplement" },
+ -- { source = "latinextendeda" },
+ -- { source = "latinextendedadditional" },
+ -- { source = "latinextendedb" },
+ -- { source = "latinextendedc" },
+ -- { source = "latinextendedd" },
+ -- { source = "latinextendede" },
+ -- { source = "latinextendedf" },
+ -- { source = "latinextendedg" },
+ },
+ },
+ {
tweak = "replacealphabets",
list = {
{
@@ -140,12 +156,12 @@ return {
tweak = "kerns",
list = {
[0x002F] = { topleft = -0.2, bottomright = -0.2 },
- ["0x7D.parts.top"] = { topright = -0.15 }, -- right brace top
- ["0x7D.parts.bottom"] = { bottomright = -0.15 }, -- right brace bottom
- ["0x7D.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right brace variants
- ["0x29.parts.top"] = { topright = -0.25 }, -- right parenthesis top
- ["0x29.parts.bottom"] = { bottomright = -0.25 }, -- right parenthesis bottom
- ["0x29.variants.*"] = { topright = -0.2, bottomright = -0.2 }, -- right parenthesis variants
+ ["0x007D.parts.top"] = { topright = -0.15 }, -- right brace top
+ ["0x007D.parts.bottom"] = { bottomright = -0.15 }, -- right brace bottom
+ ["0x007D.variants.*"] = { topright = -0.15, bottomright = -0.15 }, -- right brace variants
+ ["0x0029.parts.top"] = { topright = -0.25 }, -- right parenthesis top
+ ["0x0029.parts.bottom"] = { bottomright = -0.25 }, -- right parenthesis bottom
+ ["0x0029.variants.*"] = { topright = -0.2, bottomright = -0.2 }, -- right parenthesis variants
["0x221A.parts.top"] = { topright = 0.2 }, -- right radical top
["0x221A.parts.bottom"] = { bottomright = 0.2 }, -- right radical bottom
["0x221A.variants.*"] = { topright = 0.2, bottomright = 0.2 }, -- right radical variants
@@ -196,6 +212,12 @@ return {
[0x21A0] = false,
}
},
+ -- fix a bug (todo: version)
+ {
+ tweak = "sortvariants",
+ list = { 0x23DE },
+ orientation = "horizontal",
+ },
-- this is the mkiv section
{
tweak = "emulatelmtx",
diff --git a/tex/context/fonts/mkiv/type-imp-concrete.mkiv b/tex/context/fonts/mkiv/type-imp-concrete.mkiv
index ff4033f81..abf9b2cb1 100644
--- a/tex/context/fonts/mkiv/type-imp-concrete.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-concrete.mkiv
@@ -1,5 +1,5 @@
%D \module
-%D [ file=type-imp-erewhon,
+%D [ file=type-imp-concrete,
%D version=2022.30.09, % a bit older
%D title=\CONTEXT\ Typescript Macros,
%D subtitle=\TEX Gyre Fonts,
@@ -11,9 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%\loadtypescriptfile[texgyre]
-%\resetfontfallback [concrete-euler-fix]
-%\definefontfallback[concrete-euler-fix][texgyrepagella-math] [0x022EE,0x022F0,0x022F1,0x02661,0x02220][force=yes]
+% lm is already preloaded so we can actually move this to lm
\starttypescriptcollection[concrete]
@@ -21,33 +19,35 @@
%\definefontfeature[none-slanted-concrete] [none] [slant=.2]
\doifunknownfontfeature {concrete-math-bold} {\definefontfeature[concrete-math-bold][boldened]}
+ \doifunknownfontfeature {concrete-text-bold} {\definefontfeature[concrete-text-bold][boldened-15]}
\starttypescript [\s!serif] [concrete]
- \definefontsynonym [\s!Serif] [\s!file:cmunorm] [\s!features=\s!default]
- \definefontsynonym [\s!SerifItalic] [\s!file:cmunoti] [\s!features=\s!default]
- \definefontsynonym [\s!SerifSlanted] [\s!file:cmunorm] [\s!features=default-slanted-concrete]
- \definefontsynonym [\s!SerifBold] [\s!file:cmunobx] [\s!features=\s!default]
- \definefontsynonym [\s!SerifBoldItalic] [\s!file:cmunobi] [\s!features=\s!default]
- \definefontsynonym [\s!SerifBoldSlanted] [\s!file:cmunobx] [\s!features=default-slanted-concrete]
+ \definefontsynonym [\s!Serif] [LMTypewriterVarWd-Regular] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SerifBold] [LMTypewriterVarWd-Dark] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SerifItalic] [LMTypewriterVarWd-Oblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SerifSlanted] [LMTypewriterVarWd-Oblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SerifBoldItalic] [LMTypewriterVarWd-DarkOblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SerifBoldSlanted] [LMTypewriterVarWd-DarkOblique] [\s!features={\s!default,concrete-text-bold}]
\stoptypescript
\starttypescript [\s!sans] [concrete]
- \definefontsynonym [\s!Sans] [\s!file:cmunss] [\s!features=\s!default]
- \definefontsynonym [\s!SansItalic] [\s!file:cmunsi] [\s!features=\s!default]
- \definefontsynonym [\s!SansSlanted] [\s!file:cmunss] [\s!features=default-slanted-concrete]
- \definefontsynonym [\s!SansBold] [\s!file:cmunsx] [\s!features=\s!default]
- \definefontsynonym [\s!SansBoldItalic] [\s!file:cmunso] [\s!features=\s!default]
- \definefontsynonym [\s!SansBoldSlanted] [\s!file:cmunsx] [\s!features=default-slanted-concrete]
+ \definefontsynonym [\s!Sans] [LMTypewriterVarWd-Regular] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SansItalic] [LMTypewriterVarWd-Dark] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SansSlanted] [LMTypewriterVarWd-Oblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SansBold] [LMTypewriterVarWd-Oblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SansBoldItalic] [LMTypewriterVarWd-DarkOblique] [\s!features={\s!default,concrete-text-bold}]
+ \definefontsynonym [\s!SansBoldSlanted] [LMTypewriterVarWd-DarkOblique] [\s!features={\s!default,concrete-text-bold}]
\stoptypescript
\starttypescript [\s!mono] [concrete]
- \definefontsynonym [\s!Mono] [\s!file:cmuntt] [\s!features=\s!none]
- \definefontsynonym [\s!MonoItalic] [\s!file:cmunit] [\s!features=\s!none]
- \definefontsynonym [\s!MonoSlanted] [\s!file:cmunst] [\s!features=\s!none]
- \definefontsynonym [\s!MonoBold] [\s!file:cmuntb] [\s!features=\s!none]
- \definefontsynonym [\s!MonoBoldItalic] [\s!file:cmuntx] [\s!features=\s!none]
- \definefontsynonym [\s!MonoBoldSlanted] [\s!file:cmuntb] [\s!features=none-slanted-concrete]
- \stoptypescript
+ \loadfontgoodies[lm]
+ \definefontsynonym [\s!Mono] [LMTypewriter-Regular] [\s!features={\s!none,concrete-text-bold}]
+ \definefontsynonym [\s!MonoBold] [LMTypewriter-Dark] [\s!features={\s!none,concrete-text-bold}]
+ \definefontsynonym [\s!MonoItalic] [LMTypewriter-Italic] [\s!features={\s!none,concrete-text-bold}]
+ \definefontsynonym [\s!MonoSlanted] [LMTypewriter-Oblique] [\s!features={\s!none,concrete-text-bold}]
+ \definefontsynonym [\s!MonoBoldItalic] [LMTypewriter-DarkOblique] [\s!features={\s!none,concrete-text-bold}]
+ \definefontsynonym [\s!MonoBoldSlanted] [LMTypewriter-DarkOblique] [\s!features={\s!none,concrete-text-bold}]
+ \stoptypescript
\starttypescript [\s!math] [concrete]
\checkedmapfontsize[\typescripttwo][\s!script] [.76]
diff --git a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv
index 31026df5b..966e50ba8 100644
--- a/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-ebgaramond.mkiv
@@ -65,6 +65,14 @@
\starttypescriptcollection[ebgaramond]
+ \startsetups[ebgaramond]
+ \letmathfractionparameter\c!rule\v!symbol
+ \setmathfractionparameter\c!middle{"203E}%
+ \letmathradicalparameter \c!rule\v!symbol
+ \setmathradicalparameter \c!top{\radicalbarextenderuc}%
+ % \setmathfenceparameter \c!alternative{1}%
+ \stopsetups
+
\doifunknownfontfeature {ebgaramond-math-bold} {\definefontfeature[ebgaramond-math-bold][boldened]}
\starttypescript [\s!serif] [ebgaramond]
@@ -76,15 +84,13 @@
\definefontsynonym [\s!SerifCaps] [\s!Serif] [\s!features=eb-garamond-smallcaps]
\stoptypescript
-
-
- \starttypescript [\s!sans] [ysabeau]
- % \setups[font:fallback:sans]
- \definefontsynonym [\s!Sans] [\s!file:ysabeau-regular] [\s!features=\s!default]
- \definefontsynonym [\s!SansItalic] [\s!file:ysabeau-italic] [\s!features=\s!default]
- \definefontsynonym [\s!SansBold] [\s!file:ysabeau-bold] [\s!features=\s!default]
- \definefontsynonym [\s!SansBoldItalic][\s!file:ysabeau-bolditalic] [\s!features=\s!default]
- \definefontsynonym [\s!SansCaps] [\s!Sans] [\s!features=ysabeau-smallcaps]
+ \starttypescript [\s!sans] [ysabeau]
+ % \setups[font:fallback:sans]
+ \definefontsynonym [\s!Sans] [\s!file:ysabeau-regular] [\s!features=\s!default]
+ \definefontsynonym [\s!SansItalic] [\s!file:ysabeau-italic] [\s!features=\s!default]
+ \definefontsynonym [\s!SansBold] [\s!file:ysabeau-bold] [\s!features=\s!default]
+ \definefontsynonym [\s!SansBoldItalic][\s!file:ysabeau-bolditalic] [\s!features=\s!default]
+ \definefontsynonym [\s!SansCaps] [\s!Sans] [\s!features=ysabeau-smallcaps]
\stoptypescript
\starttypescript [\s!math] [ebgaramond,ebgaramond-nt]
diff --git a/tex/context/fonts/mkiv/type-imp-iwona.mkiv b/tex/context/fonts/mkiv/type-imp-iwona.mkiv
index f43731250..528cb3208 100644
--- a/tex/context/fonts/mkiv/type-imp-iwona.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-iwona.mkiv
@@ -66,12 +66,15 @@
\starttypescript [\s!math][iwona][\s!all]
\definefontsynonym[\s!MathRoman] [iwonamath@iwona-math]
+ \definefontsynonym[\s!MathRomanBold][iwonamediummath@iwona-medium-math]
\stoptypescript
\starttypescript [\s!math][iwona-light][\s!all]
\definefontsynonym[\s!MathRoman] [iwonalightmath@iwona-light-math]
+ \definefontsynonym[\s!MathRomanBold][iwonamath@kurier-medium-math]
\stoptypescript
\starttypescript [\s!math][iwona-medium][\s!all]
\definefontsynonym[\s!MathRoman] [iwonamediummath@iwona-medium-math]
+ \definefontsynonym[\s!MathRomanBold][kurierheavymath@kurier-heavy-math]
\stoptypescript
\starttypescript [\s!math][iwona-heavy][\s!all]
\definefontsynonym[\s!MathRoman][iwonaheavymath@iwona-heavy-math]
diff --git a/tex/context/fonts/mkiv/type-imp-kpfonts.mkiv b/tex/context/fonts/mkiv/type-imp-kpfonts.mkiv
index 472619cd9..c8e92d20b 100644
--- a/tex/context/fonts/mkiv/type-imp-kpfonts.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-kpfonts.mkiv
@@ -68,14 +68,14 @@
\starttypescript [\s!serif] [kpfonts-bold]
\setups[\s!font:\s!fallback:\s!serif]
- \definefontsynonym [\s!Serif] [\s!file:KpRoman-Regular.otf]
+ \definefontsynonym [\s!Serif] [\s!file:KpRoman-SemiBold.otf]
\definefontsynonym [\s!SerifBold] [\s!file:KpRoman-Bold.otf]
- \definefontsynonym [\s!SerifItalic] [\s!file:KpRoman-Italic.otf]
+ \definefontsynonym [\s!SerifItalic] [\s!file:KpRoman-SemiboldItalic.otf]
\definefontsynonym [\s!SerifBoldItalic] [\s!file:KpRoman-BoldItalic.otf]
\stoptypescript
\starttypescript [\s!math] [kpfonts-bold]
- \definefontsynonym [\s!MathRoman] [\s!file:KpMath-Regular.otf] [\s!features={\s!math\mathsizesuffix,kpfonts:mathextra,mathextra},\s!goodies=kpfonts-math]
+ \definefontsynonym [\s!MathRoman] [\s!file:KpMath-SemiBold.otf] [\s!features={\s!math\mathsizesuffix,kpfonts:mathextra,mathextra},\s!goodies=kpfonts-math]
\definefontsynonym [\s!MathRomanBold] [\s!file:KpMath-Bold.otf] [\s!features={\s!math\mathsizesuffix,kpfonts:mathextra,mathextra},\s!goodies=kpfonts-math]
\stoptypescript
diff --git a/tex/context/fonts/mkiv/type-imp-kurier.mkiv b/tex/context/fonts/mkiv/type-imp-kurier.mkiv
index 0bf1a43ca..af1e2a28d 100644
--- a/tex/context/fonts/mkiv/type-imp-kurier.mkiv
+++ b/tex/context/fonts/mkiv/type-imp-kurier.mkiv
@@ -13,12 +13,30 @@
\starttypescriptcollection [kurier]
+ \startsetups[kurier]
+ % \setupmathfence [\c!alternative=1]%
+ \setmathfenceparameter \c!alternative{1}%
+% \letmathfractionparameter\c!rule\v!symbol
+% \setmathfractionparameter\c!middle{"203E}%
+% \letmathradicalparameter \c!rule\v!symbol
+% \setmathradicalparameter \c!top{\radicalbarextenderuc}%
+% \setmathfenceparameter \c!alternative{1}%
+ \stopsetups
+
+ \startsetups[kurier-light] \directsetup{antykwa}\stopsetups
+ \startsetups[kurier-medium] \directsetup{antykwa}\stopsetups
+ \startsetups[kurier-heavy] \directsetup{antykwa}\stopsetups
+ \startsetups[kurier-cond] \directsetup{antykwa}\stopsetups
+ \startsetups[kurier-light-cond] \directsetup{antykwa}\stopsetups
+ \startsetups[kurier-medium-cond]\directsetup{antykwa}\stopsetups
+ \startsetups[kurier-heavy-cond] \directsetup{antykwa}\stopsetups
+
\definefontfeature[virtualmath-kurier] [virtualmath][virtualweight=kurier]
\definefontfeature[virtualmath-kurier-light] [virtualmath][virtualweight=kurier-light]
\definefontfeature[virtualmath-kurier-medium][virtualmath][virtualweight=kurier-medium]
\definefontfeature[virtualmath-kurier-heavy] [virtualmath][virtualweight=kurier-heavy]
- \starttypescript [\s!sans] [kurier-light,kurier,kurier-medium]
+ \starttypescript [\s!sans] [kurier-light,kurier,kurier-medium,kurier-heavy]
\definefontsynonym [Kurier-Light] [\s!file:kurierlightregular] [\s!features=\s!default]
\definefontsynonym [Kurier-LightItalic] [\s!file:kurierlightitalic] [\s!features=\s!default]
\definefontsynonym [Kurier-Regular] [\s!file:kurierregular] [\s!features=\s!default]
@@ -88,6 +106,14 @@
\definefontsynonym [\s!SansBoldItalic] [Kurier-HeavyItalic]
\stoptypescript
+ \starttypescript [\s!sans] [kurier-heavy] [\s!name]
+ \setups[\s!font:\s!fallback:\s!sans]
+ \definefontsynonym [\s!Sans] [Kurier-Heavy]
+ \definefontsynonym [\s!SansItalic] [Kurier-HeavyItalic]
+ \definefontsynonym [\s!SansBold] [Kurier-Heavy]
+ \definefontsynonym [\s!SansBoldItalic] [Kurier-Heavy]
+ \stoptypescript
+
\starttypescript [\s!sans] [kurier-lightcond]
\setups[\s!font:\s!fallback:\s!sans]
\definefontsynonym [\s!Sans] [Kurier-CondLight]
@@ -112,7 +138,7 @@
\definefontsynonym [\s!SansBoldItalic] [Kurier-CondHeavyItalic]
\stoptypescript
- \starttypescript [kurier-light,kurier,kurier-medium,kurier-lightcond,kurier-cond,kurier-mediumcond]
+ \starttypescript [kurier-light,kurier,kurier-medium,kurier-heavy,kurier-lightcond,kurier-cond,kurier-mediumcond]
\definetypeface [\typescriptone] [\s!ss] [\s!sans] [\typescriptone] [\s!default]
\definetypeface [\typescriptone] [\s!rm] [\s!serif] [modern] [\s!default]
\definetypeface [\typescriptone] [\s!tt] [\s!mono] [modern] [\s!default]
diff --git a/tex/context/fonts/mkiv/xcharter-math.lfg b/tex/context/fonts/mkiv/xcharter-math.lfg
index 1ff5d41d8..193c0fd1b 100644
--- a/tex/context/fonts/mkiv/xcharter-math.lfg
+++ b/tex/context/fonts/mkiv/xcharter-math.lfg
@@ -86,6 +86,9 @@ return {
{
tweak = "addprimed",
},
+-- {
+-- tweak = "addarrows",
+-- },
{
tweak = "addfourier",
variant = 2,
diff --git a/tex/context/interface/mkii/keys-it.xml b/tex/context/interface/mkii/keys-it.xml
index e456732ef..4804c39a7 100644
--- a/tex/context/interface/mkii/keys-it.xml
+++ b/tex/context/interface/mkii/keys-it.xml
@@ -838,6 +838,7 @@
<cd:constant name='exitoffset' value='exitoffset'/>
<cd:constant name='expansion' value='espansione'/>
<cd:constant name='export' value='export'/>
+ <cd:constant name='extradata' value='extradata'/>
<cd:constant name='extras' value='extras'/>
<cd:constant name='factor' value='fattore'/>
<cd:constant name='fallback' value='fallback'/>
@@ -961,6 +962,7 @@
<cd:constant name='lastpage' value='ultimapagina'/>
<cd:constant name='lastpagesep' value='lastpagesep'/>
<cd:constant name='lastpubsep' value='lastpubsep'/>
+ <cd:constant name='lasttextseparator' value='lasttextseparator'/>
<cd:constant name='layout' value='layout'/>
<cd:constant name='left' value='sinistra'/>
<cd:constant name='leftclass' value='leftclass'/>
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index 614793314..e885a56ed 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 2023-03-10 12:15
+-- merge date : 2023-03-20 15:42
do -- begin closure to overcome local limits and interference
diff --git a/web2c/contextcnf.lua b/web2c/contextcnf.lua
index 5ad9ea6d8..3c27eda19 100644
--- a/web2c/contextcnf.lua
+++ b/web2c/contextcnf.lua
@@ -45,9 +45,9 @@ return {
-- but there can be more readable paths.
-- standalone:
-
+
TEXMFCACHE = "$SELFAUTOPARENT/texmf-cache",
-
+
-- texlive
-- TEXMFVAR = "home:" .. hiddentexlivepath .. "/texmf-var",
@@ -63,21 +63,21 @@ return {
-- tex root relocatable.
TEXMFOS = "selfautodir:",
-
- -- standalone:
-
+
+ -- standalone:
+
TEXMFSYSTEM = "selfautoparent:texmf-$SELFAUTOSYSTEM",
TEXMFMAIN = "selfautoparent:texmf",
TEXMFCONTEXT = "selfautoparent:texmf-context",
TEXMFMODULES = "selfautoparent:texmf-modules",
-
+
-- texlive:
-
+
-- TEXMFDIST = "selfautoparent:texmf-dist",
-- TEXMFSYSCONFIG = "selfautoparent:texmf-config",
-
+
-- The texmf-local path is only used for (maybe) some additional configuration file.
-
+
TEXMFLOCAL = "selfautoparent:texmf-local",
TEXMFFONTS = "selfautoparent:texmf-fonts",
TEXMFPROJECT = "selfautoparent:texmf-project",
@@ -91,9 +91,9 @@ return {
-- standalone:
TEXMF = "{$TEXMFHOME,!!$TEXMFPROJECT,!!$TEXMFFONTS,!!$TEXMFLOCAL,!!$TEXMFMODULES,!!$TEXMFCONTEXT,!!$TEXMFSYSTEM,!!$TEXMFMAIN}",
-
+
-- texlive:
-
+
-- TEXMF = "{$TEXMFCONFIG,$TEXMFHOME,!!$TEXMFSYSCONFIG,!!$TEXMFSYSVAR,!!$TEXMFPROJECT,!!$TEXMFFONTS,!!$TEXMFLOCAL,!!$TEXMFDIST}",
TEXFONTMAPS = ".;$TEXMF/fonts/data//;$TEXMF/fonts/map/{pdftex,dvips}//",
@@ -127,19 +127,23 @@ return {
BIBINPUTS = ".;$TEXMF/bibtex/bib//;$TEXMF/tex/context//",
BSTINPUTS = ".;$TEXMF/bibtex/bst//;$TEXMF/tex/context//",
- -- Experimental
+ -- standalone
ICCPROFILES = ".;$TEXMF/colors/icc/{context,profiles}//;$OSCOLORDIR",
+ -- texlive
+
+ -- ICCPROFILES = ".;$TEXMF/tex/context/colors/{icc,profiles}//;$OSCOLORDIR",
+
-- A few special ones that will change some day.
FONTCONFIG_FILE = "fonts.conf",
-- standalone
-
+
FONTCONFIG_PATH = "$TEXMFSYSTEM/fonts/conf",
-
- --texlive
+
+ --texlive
-- FONTCONFIG_PATH = "$TEXMFSYSVAR/fonts/conf",
diff --git a/web2c/texlivecnf.lua b/web2c/texlivecnf.lua
index e14d5cbfc..3dca87fc5 100644
--- a/web2c/texlivecnf.lua
+++ b/web2c/texlivecnf.lua
@@ -127,19 +127,23 @@ return {
BIBINPUTS = ".;$TEXMF/bibtex/bib//;$TEXMF/tex/context//",
BSTINPUTS = ".;$TEXMF/bibtex/bst//;$TEXMF/tex/context//",
- -- Experimental
+ -- standalone
+
+ -- ICCPROFILES = ".;$TEXMF/colors/icc/{context,profiles}//;$OSCOLORDIR",
+
+ -- texlive
- ICCPROFILES = ".;$TEXMF/colors/icc/{context,profiles}//;$OSCOLORDIR",
+ ICCPROFILES = ".;$TEXMF/tex/context/colors/{icc,profiles}//;$OSCOLORDIR",
-- A few special ones that will change some day.
FONTCONFIG_FILE = "fonts.conf",
-- standalone
-
+
-- FONTCONFIG_PATH = "$TEXMFSYSTEM/fonts/conf",
-
- --texlive
+
+ --texlive
FONTCONFIG_PATH = "$TEXMFSYSVAR/fonts/conf",