From 1873d112b56f49e40ece29916ede51933412bca8 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Wed, 31 Jul 2019 18:26:52 +0200 Subject: 2019-07-31 18:13:00 --- tex/context/base/mkii/cont-new.mkii | 2 +- tex/context/base/mkii/context.mkii | 2 +- tex/context/base/mkii/mult-it.mkii | 5 + tex/context/base/mkiv/back-ini.mkiv | 35 +- tex/context/base/mkiv/back-ini.mkxl | 81 + tex/context/base/mkiv/back-lua.mkiv | 18 - tex/context/base/mkiv/back-lua.mkxl | 18 + tex/context/base/mkiv/back-mps.mkiv | 18 - tex/context/base/mkiv/back-mps.mkxl | 18 + tex/context/base/mkiv/back-out.lua | 4 - tex/context/base/mkiv/back-out.mkiv | 25 - tex/context/base/mkiv/back-out.mkxl | 23 + tex/context/base/mkiv/back-pdf.mkiv | 24 +- tex/context/base/mkiv/back-pdf.mkxl | 148 + tex/context/base/mkiv/buff-ver.mkiv | 184 +- tex/context/base/mkiv/buff-ver.mkxl | 1005 +++ tex/context/base/mkiv/cldf-ini.lua | 2 +- tex/context/base/mkiv/colo-ini.mkiv | 151 +- tex/context/base/mkiv/colo-ini.mkxl | 1399 +++++ tex/context/base/mkiv/cont-cs.mkxl | 21 + tex/context/base/mkiv/cont-de.mkxl | 21 + tex/context/base/mkiv/cont-en.mkxl | 21 + tex/context/base/mkiv/cont-fr.mkxl | 21 + tex/context/base/mkiv/cont-gb.mkxl | 21 + tex/context/base/mkiv/cont-it.mkxl | 21 + tex/context/base/mkiv/cont-new.mkiv | 2 +- tex/context/base/mkiv/cont-nl.mkxl | 21 + tex/context/base/mkiv/cont-pe.mkxl | 22 + tex/context/base/mkiv/cont-ro.mkxl | 21 + tex/context/base/mkiv/context.mkiv | 11 +- tex/context/base/mkiv/context.mkxl | 625 ++ tex/context/base/mkiv/core-lmt.mkiv | 32 - tex/context/base/mkiv/core-lmt.mkxl | 31 + tex/context/base/mkiv/data-tmp.lua | 9 +- tex/context/base/mkiv/driv-ini.mkiv | 21 +- tex/context/base/mkiv/driv-ini.mkxl | 20 + tex/context/base/mkiv/driv-shp.mkiv | 24 - tex/context/base/mkiv/driv-shp.mkxl | 18 + tex/context/base/mkiv/file-job.lua | 4 +- tex/context/base/mkiv/file-mod.lua | 17 +- tex/context/base/mkiv/font-emp.mklx | 256 + tex/context/base/mkiv/font-emp.mkvi | 29 +- tex/context/base/mkiv/font-fil.mklx | 422 ++ tex/context/base/mkiv/font-fil.mkvi | 20 +- tex/context/base/mkiv/font-ini.mklx | 2563 ++++++++ tex/context/base/mkiv/font-ini.mkvi | 435 +- tex/context/base/mkiv/font-mat.mklx | 500 ++ tex/context/base/mkiv/font-otr.lua | 33 +- tex/context/base/mkiv/font-pre.mkiv | 2 + tex/context/base/mkiv/font-shp.lua | 20 +- tex/context/base/mkiv/font-sty.mklx | 449 ++ tex/context/base/mkiv/font-sym.mklx | 245 + tex/context/base/mkiv/font-sym.mkvi | 31 +- tex/context/base/mkiv/lang-ini.mkxl | 730 +++ tex/context/base/mkiv/lang-lab.mkiv | 45 +- tex/context/base/mkiv/lang-lab.mkxl | 390 ++ tex/context/base/mkiv/lpdf-eng.lua | 4 - tex/context/base/mkiv/lpdf-lmt.lua | 4 - tex/context/base/mkiv/lpdf-nod.lua | 4 - tex/context/base/mkiv/luat-env.lua | 11 + tex/context/base/mkiv/luat-fmt.lua | 12 +- tex/context/base/mkiv/luat-lib.mkiv | 9 - tex/context/base/mkiv/luat-mac.lua | 4 +- tex/context/base/mkiv/meta-imp-dum.mkiv | 127 +- tex/context/base/mkiv/meta-mac.mkxl | 66 + tex/context/base/mkiv/mlib-ctx.mkiv | 69 - tex/context/base/mkiv/mlib-ctx.mkxl | 27 + tex/context/base/mkiv/mlib-lua.lua | 4 + tex/context/base/mkiv/mlib-mat.lua | 133 + tex/context/base/mkiv/mlib-run.lua | 7 +- tex/context/base/mkiv/mlib-scn.lua | 529 ++ tex/context/base/mkiv/mult-aux.mkiv | 197 +- tex/context/base/mkiv/mult-aux.mkxl | 1154 ++++ tex/context/base/mkiv/mult-def.lua | 4 + tex/context/base/mkiv/mult-low.lua | 2 +- tex/context/base/mkiv/mult-prm.lua | 9 +- tex/context/base/mkiv/mult-sys.mkiv | 1 + tex/context/base/mkiv/node-nut.lua | 298 +- tex/context/base/mkiv/node-rul.lua | 9 +- tex/context/base/mkiv/pack-rul.mkiv | 165 - tex/context/base/mkiv/pack-rul.mkxl | 3049 +++++++++ tex/context/base/mkiv/page-imp.mkiv | 10 +- tex/context/base/mkiv/scrn-wid.mkvi | 2 + tex/context/base/mkiv/spac-ver.mkiv | 39 +- tex/context/base/mkiv/spac-ver.mkxl | 2597 ++++++++ tex/context/base/mkiv/status-files.pdf | Bin 26920 -> 26567 bytes tex/context/base/mkiv/status-lua.pdf | Bin 254119 -> 268461 bytes tex/context/base/mkiv/strc-itm.mklx | 1854 ++++++ tex/context/base/mkiv/strc-itm.mkvi | 16 +- tex/context/base/mkiv/supp-box.mkiv | 431 +- tex/context/base/mkiv/supp-box.mkxl | 2930 +++++++++ tex/context/base/mkiv/syst-aux.mkiv | 2467 +++----- tex/context/base/mkiv/syst-aux.mkxl | 6558 ++++++++++++++++++++ tex/context/base/mkiv/syst-ini.mkiv | 4 +- tex/context/base/mkiv/syst-ini.mkxl | 1075 ++++ tex/context/base/mkiv/tabl-ntb.mkiv | 143 +- tex/context/base/mkiv/tabl-ntb.mkxl | 2138 +++++++ tex/context/base/mkiv/tabl-tbl.mkxl | 3022 +++++++++ tex/context/base/mkiv/type-ini.mklx | 618 ++ tex/context/base/mkiv/type-ini.mkvi | 20 +- tex/context/base/mkiv/util-sci.lua | 2 +- tex/context/base/mkiv/util-str.lua | 27 +- tex/context/base/mkiv/util-tab.lua | 32 +- tex/context/interface/mkii/keys-it.xml | 5 + tex/context/interface/mkiv/context-en.xml | 2144 ++++++- tex/context/interface/mkiv/i-attachment.xml | 3 + tex/context/interface/mkiv/i-boxes.xml | 101 +- tex/context/interface/mkiv/i-capitals.xml | 18 + tex/context/interface/mkiv/i-chart.xml | 2 +- tex/context/interface/mkiv/i-columns.xml | 10 +- tex/context/interface/mkiv/i-common-argument.xml | 24 +- tex/context/interface/mkiv/i-common-instance.xml | 1 + tex/context/interface/mkiv/i-common-string.xml | 22 + tex/context/interface/mkiv/i-common-value.xml | 127 + tex/context/interface/mkiv/i-context.pdf | Bin 967152 -> 890332 bytes tex/context/interface/mkiv/i-context.xml | 2 +- tex/context/interface/mkiv/i-conversion.xml | 9 +- tex/context/interface/mkiv/i-direction.xml | 18 - tex/context/interface/mkiv/i-fittingpage.xml | 62 +- tex/context/interface/mkiv/i-graphics.xml | 2 +- tex/context/interface/mkiv/i-interactionscreen.xml | 2 + tex/context/interface/mkiv/i-itemgroup.xml | 730 ++- tex/context/interface/mkiv/i-math.xml | 56 + tex/context/interface/mkiv/i-mathfence.xml | 51 +- tex/context/interface/mkiv/i-mixedcolumns.xml | 10 +- tex/context/interface/mkiv/i-note.xml | 51 + tex/context/interface/mkiv/i-pagegrid.xml | 24 +- tex/context/interface/mkiv/i-pagenumber.xml | 34 +- tex/context/interface/mkiv/i-paragraphs.xml | 1 + tex/context/interface/mkiv/i-readme.pdf | Bin 27517 -> 61165 bytes tex/context/interface/mkiv/i-register.xml | 605 +- tex/context/interface/mkiv/i-section.xml | 28 + tex/context/interface/mkiv/i-simplecolumns.xml | 34 + tex/context/interface/mkiv/i-symbol.xml | 13 +- tex/context/interface/mkiv/i-texts.xml | 331 +- tex/context/interface/mkiv/i-vspace.xml | 6 + tex/context/modules/mkiv/m-scite.mkiv | 3 +- tex/context/modules/mkiv/s-fonts-system.lua | 2 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 42 +- 139 files changed, 40105 insertions(+), 4687 deletions(-) create mode 100644 tex/context/base/mkiv/back-ini.mkxl delete mode 100644 tex/context/base/mkiv/back-lua.mkiv create mode 100644 tex/context/base/mkiv/back-lua.mkxl delete mode 100644 tex/context/base/mkiv/back-mps.mkiv create mode 100644 tex/context/base/mkiv/back-mps.mkxl delete mode 100644 tex/context/base/mkiv/back-out.mkiv create mode 100644 tex/context/base/mkiv/back-out.mkxl create mode 100644 tex/context/base/mkiv/back-pdf.mkxl create mode 100644 tex/context/base/mkiv/buff-ver.mkxl create mode 100644 tex/context/base/mkiv/colo-ini.mkxl create mode 100644 tex/context/base/mkiv/cont-cs.mkxl create mode 100644 tex/context/base/mkiv/cont-de.mkxl create mode 100644 tex/context/base/mkiv/cont-en.mkxl create mode 100644 tex/context/base/mkiv/cont-fr.mkxl create mode 100644 tex/context/base/mkiv/cont-gb.mkxl create mode 100644 tex/context/base/mkiv/cont-it.mkxl create mode 100644 tex/context/base/mkiv/cont-nl.mkxl create mode 100644 tex/context/base/mkiv/cont-pe.mkxl create mode 100644 tex/context/base/mkiv/cont-ro.mkxl create mode 100644 tex/context/base/mkiv/context.mkxl delete mode 100644 tex/context/base/mkiv/core-lmt.mkiv create mode 100644 tex/context/base/mkiv/core-lmt.mkxl create mode 100644 tex/context/base/mkiv/driv-ini.mkxl delete mode 100644 tex/context/base/mkiv/driv-shp.mkiv create mode 100644 tex/context/base/mkiv/driv-shp.mkxl create mode 100644 tex/context/base/mkiv/font-emp.mklx create mode 100644 tex/context/base/mkiv/font-fil.mklx create mode 100644 tex/context/base/mkiv/font-ini.mklx create mode 100644 tex/context/base/mkiv/font-mat.mklx create mode 100644 tex/context/base/mkiv/font-sty.mklx create mode 100644 tex/context/base/mkiv/font-sym.mklx create mode 100644 tex/context/base/mkiv/lang-ini.mkxl create mode 100644 tex/context/base/mkiv/lang-lab.mkxl create mode 100644 tex/context/base/mkiv/meta-mac.mkxl create mode 100644 tex/context/base/mkiv/mlib-ctx.mkxl create mode 100644 tex/context/base/mkiv/mlib-mat.lua create mode 100644 tex/context/base/mkiv/mlib-scn.lua create mode 100644 tex/context/base/mkiv/mult-aux.mkxl create mode 100644 tex/context/base/mkiv/pack-rul.mkxl create mode 100644 tex/context/base/mkiv/spac-ver.mkxl create mode 100644 tex/context/base/mkiv/strc-itm.mklx create mode 100644 tex/context/base/mkiv/supp-box.mkxl create mode 100644 tex/context/base/mkiv/syst-aux.mkxl create mode 100644 tex/context/base/mkiv/syst-ini.mkxl create mode 100644 tex/context/base/mkiv/tabl-ntb.mkxl create mode 100644 tex/context/base/mkiv/tabl-tbl.mkxl create mode 100644 tex/context/base/mkiv/type-ini.mklx create mode 100644 tex/context/interface/mkiv/i-simplecolumns.xml (limited to 'tex') diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index db052cd5e..9387a9475 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{2019.07.24 11:17} +\newcontextversion{2019.07.31 18:05} %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 6c59c6cfa..0c0370cd4 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{2019.07.24 11:17} +\edef\contextversion{2019.07.31 18:05} %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 2bbf93141..432917617 100644 --- a/tex/context/base/mkii/mult-it.mkii +++ b/tex/context/base/mkii/mult-it.mkii @@ -147,6 +147,7 @@ \setinterfacevariable{comment}{commento} \setinterfacevariable{component}{componente} \setinterfacevariable{compressseparator}{compressseparator} +\setinterfacevariable{compressstopper}{compressstopper} \setinterfacevariable{concept}{concetto} \setinterfacevariable{construction}{construction} \setinterfacevariable{content}{indice} @@ -477,6 +478,7 @@ \setinterfacevariable{sectionnumber}{numerosezione} \setinterfacevariable{see}{vedi} \setinterfacevariable{selectfont}{selectfont} +\setinterfacevariable{separator}{separator} \setinterfacevariable{september}{settembre} \setinterfacevariable{serif}{serif} \setinterfacevariable{serifbold}{serifbold} @@ -635,6 +637,7 @@ \setinterfaceconstant{aligntitle}{allineatitolo} \setinterfaceconstant{alternative}{alternativa} \setinterfaceconstant{anchor}{anchor} +\setinterfaceconstant{anchoring}{anchoring} \setinterfaceconstant{andtext}{andtext} \setinterfaceconstant{apa}{apa} \setinterfaceconstant{arguments}{arguments} @@ -732,7 +735,9 @@ \setinterfaceconstant{compoundhyphen}{compoundhyphen} \setinterfaceconstant{compress}{compress} \setinterfaceconstant{compressdistance}{compressdistance} +\setinterfaceconstant{compressmethod}{compressmethod} \setinterfaceconstant{compressseparator}{compressseparator} +\setinterfaceconstant{compressstopper}{compressstopper} \setinterfaceconstant{concerns}{concerns} \setinterfaceconstant{connector}{connector} \setinterfaceconstant{continue}{continua} diff --git a/tex/context/base/mkiv/back-ini.mkiv b/tex/context/base/mkiv/back-ini.mkiv index 007f80d1a..43fe48ee0 100644 --- a/tex/context/base/mkiv/back-ini.mkiv +++ b/tex/context/base/mkiv/back-ini.mkiv @@ -30,13 +30,11 @@ %D therefore dropped support for this format. Future versions might support more %D backends again, but this has a low priority. -\ifdefined\outputmode - \outputmode\plusone - \let\outputmode\relax - \newcount\outputmode - \outputmode\plusone - \let\normaloutputmode\outputmode -\fi +\outputmode\plusone +\let\outputmode\relax +\newcount\outputmode +\outputmode\plusone +\let\normaloutputmode\outputmode %D The exact page model depends on the backend so we just define some variables that %D are used. A helper at the \LUA\ end will synchronize with the internal variables. @@ -46,6 +44,9 @@ \ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi \ifdefined\everybackendlastinshipout \else \newtoks\everybackendlastinshipout \fi +%D In \MKIV\ there is just one backend, \PDF, plus an additional export. We never +%D came to seperate them, but \LMTX\ might do that. + \installcorenamespace{backend} \installsetuponlycommandhandler \??backend {backend} @@ -64,27 +65,7 @@ \fi \to \everysetupbackend -%D For the moment this is an experiment (defauls is pdf, but we also -%D have lua, json and mps). -%D -%D \starttyping -%D % \setupoutput[lua] -%D % \setupoutput[json] -%D % \setupoutput[mps] -%D % \setupoutput[none] % for testing only -%D % \setupoutput[empty] % for testing only -%D -%D \starttext -%D \dorecurse{1000}{ -%D {\tf \red \samplefile{tufte}} \par -%D {\bf \green \samplefile {ward}} \par -%D {\sl \blue \samplefile{davis}} \par -%D } -%D \stoptext -%D \stoptyping - \unexpanded\def\setupoutput[#1]% {\clf_enabledriver{#1}} - \protect \endinput diff --git a/tex/context/base/mkiv/back-ini.mkxl b/tex/context/base/mkiv/back-ini.mkxl new file mode 100644 index 000000000..4e2fa351e --- /dev/null +++ b/tex/context/base/mkiv/back-ini.mkxl @@ -0,0 +1,81 @@ +%D \module +%D [ file=back-ini, +%D version=2009.04.15, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Backend Macros / Initialization} + +\registerctxluafile{back-ini}{} + +\unprotect + +%D Right from the start \CONTEXT\ had a backend system based on runtime pluggable +%D code. As most backend issues involved specials and since postprocessors had not +%D that much in common, we ended up with a system where we could switch backend as +%D well as output code for multiple backends at the same time. +%D +%D Because \LUATEX\ has the backend built in, and since some backend issues have +%D been moved to the frontend I decided to provide new backend code for \MKIV, +%D starting with what was actually used. +%D +%D At this moment \DVI\ is no longer used for advanced document output and we +%D therefore dropped support for this format. Future versions might support more +%D backends again, but this has a low priority. + +%D The exact page model depends on the backend so we just define some variables that +%D are used. A helper at the \LUA\ end will synchronize with the internal variables. +%D We store these in the format. + +\ifdefined\everybackendshipout \else \newtoks\everybackendshipout \fi +\ifdefined\everylastbackendshipout \else \newtoks\everylastbackendshipout \fi +\ifdefined\everybackendlastinshipout \else \newtoks\everybackendlastinshipout \fi + +\installcorenamespace{backend} + +\installsetuponlycommandhandler \??backend {backend} + +%D \starttyping +%D \setupbackend[space=yes] +%D \stoptyping + +\appendtoks + \clf_setrealspaces{\backendparameter\c!space}% +\to \everysetupbackend + +\appendtoks + \ifdefined\clf_resetmapfile + \clf_resetmapfile + \fi +\to \everysetupbackend + +%D For the moment this is an experiment (defauls is pdf, but we also +%D have lua, json and mps). +%D +%D \starttyping +%D % \setupoutput[lua] +%D % \setupoutput[json] +%D % \setupoutput[mps] +%D % \setupoutput[none] % for testing only +%D % \setupoutput[empty] % for testing only +%D +%D \starttext +%D \dorecurse{1000}{ +%D {\tf \red \samplefile{tufte}} \par +%D {\bf \green \samplefile {ward}} \par +%D {\sl \blue \samplefile{davis}} \par +%D } +%D \stoptext +%D \stoptyping + +\unexpanded\def\setupoutput[#1]% + {\clf_enabledriver{#1}} + +\protect \endinput diff --git a/tex/context/base/mkiv/back-lua.mkiv b/tex/context/base/mkiv/back-lua.mkiv deleted file mode 100644 index 82ba8f9f1..000000000 --- a/tex/context/base/mkiv/back-lua.mkiv +++ /dev/null @@ -1,18 +0,0 @@ -%D \module -%D [ file=back-lua, -%D version=2018.07.26, -%D title=\CONTEXT\ Backend Macros, -%D subtitle=\LUA, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\ifcase\contextlmtxmode \else - \registerctxluafile{back-lua}{optimize} -\fi - -\endinput diff --git a/tex/context/base/mkiv/back-lua.mkxl b/tex/context/base/mkiv/back-lua.mkxl new file mode 100644 index 000000000..82ba8f9f1 --- /dev/null +++ b/tex/context/base/mkiv/back-lua.mkxl @@ -0,0 +1,18 @@ +%D \module +%D [ file=back-lua, +%D version=2018.07.26, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=\LUA, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\ifcase\contextlmtxmode \else + \registerctxluafile{back-lua}{optimize} +\fi + +\endinput diff --git a/tex/context/base/mkiv/back-mps.mkiv b/tex/context/base/mkiv/back-mps.mkiv deleted file mode 100644 index 0a6640614..000000000 --- a/tex/context/base/mkiv/back-mps.mkiv +++ /dev/null @@ -1,18 +0,0 @@ -%D \module -%D [ file=back-mps, -%D version=2018.07.26, -%D title=\CONTEXT\ Backend Macros, -%D subtitle=\METAPOST, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\ifcase\contextlmtxmode \else - \registerctxluafile{back-mps}{optimize} -\fi - -\endinput diff --git a/tex/context/base/mkiv/back-mps.mkxl b/tex/context/base/mkiv/back-mps.mkxl new file mode 100644 index 000000000..0a6640614 --- /dev/null +++ b/tex/context/base/mkiv/back-mps.mkxl @@ -0,0 +1,18 @@ +%D \module +%D [ file=back-mps, +%D version=2018.07.26, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=\METAPOST, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\ifcase\contextlmtxmode \else + \registerctxluafile{back-mps}{optimize} +\fi + +\endinput diff --git a/tex/context/base/mkiv/back-out.lua b/tex/context/base/mkiv/back-out.lua index 8fc2a048f..9934f7847 100644 --- a/tex/context/base/mkiv/back-out.lua +++ b/tex/context/base/mkiv/back-out.lua @@ -6,10 +6,6 @@ if not modules then modules = { } end modules ['back-out'] = { license = "see context related readme files" } -if CONTEXTLMTXMODE == 0 then - return -end - local type = type local loadstring = loadstring diff --git a/tex/context/base/mkiv/back-out.mkiv b/tex/context/base/mkiv/back-out.mkiv deleted file mode 100644 index 492af2463..000000000 --- a/tex/context/base/mkiv/back-out.mkiv +++ /dev/null @@ -1,25 +0,0 @@ -%D \module -%D [ file=back-out, -%D version=2019.02.08, -%D title=\CONTEXT\ Backend Macros, -%D subtitle=Output, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\ifcase\contextlmtxmode\endinput\fi - -\registerctxluafile{back-out}{} - -\let\normalimmediate\immediate -\let\normalopenout \openout -\let\normalwrite \write -\let\normalcloseout \closeout -\let\normallatelua \latelua -\let\normalspecial \special - -\endinput diff --git a/tex/context/base/mkiv/back-out.mkxl b/tex/context/base/mkiv/back-out.mkxl new file mode 100644 index 000000000..26548a0a4 --- /dev/null +++ b/tex/context/base/mkiv/back-out.mkxl @@ -0,0 +1,23 @@ +%D \module +%D [ file=back-out, +%D version=2019.02.08, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=Output, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\registerctxluafile{back-out}{} + +\let\normalimmediate\immediate +\let\normalopenout \openout +\let\normalwrite \write +\let\normalcloseout \closeout +\let\normallatelua \latelua +\let\normalspecial \special + +\endinput diff --git a/tex/context/base/mkiv/back-pdf.mkiv b/tex/context/base/mkiv/back-pdf.mkiv index 80130577c..2541755a6 100644 --- a/tex/context/base/mkiv/back-pdf.mkiv +++ b/tex/context/base/mkiv/back-pdf.mkiv @@ -18,18 +18,8 @@ \writestatus{loading}{ConTeXt Backend Macros / PDF} \registerctxluafile{lpdf-ini}{optimize} - -\ifcase\contextlmtxmode\relax - % \doifelsefile {lpdf-nod-test.lua} { - % \registerctxluafile{lpdf-nod-test}{} - % } { - \registerctxluafile{lpdf-nod}{} - % } - \registerctxluafile{lpdf-eng}{optimize} -\else - \registerctxluafile{lpdf-lmt}{optimize} -\fi - +\registerctxluafile{lpdf-nod}{} +\registerctxluafile{lpdf-eng}{optimize} \registerctxluafile{lpdf-col}{} \registerctxluafile{lpdf-xmp}{} \registerctxluafile{lpdf-ano}{} @@ -45,17 +35,7 @@ \registerctxluafile{lpdf-tag}{} \registerctxluafile{lpdf-fmt}{} \registerctxluafile{lpdf-pde}{} - -\ifcase\contextlmtxmode\else - \registerctxluafile{lpdf-img}{optimize} -\fi - \registerctxluafile{lpdf-epa}{} - -\ifcase\contextlmtxmode\else - \registerctxluafile{lpdf-emb}{optimize} -\fi - \registerctxluafile{lpdf-fnt}{} \registerctxluafile{back-pdp}{} diff --git a/tex/context/base/mkiv/back-pdf.mkxl b/tex/context/base/mkiv/back-pdf.mkxl new file mode 100644 index 000000000..2b0c4d0b7 --- /dev/null +++ b/tex/context/base/mkiv/back-pdf.mkxl @@ -0,0 +1,148 @@ +%D \module +%D [ file=back-pdf, +%D version=2009.04.15, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=\PDF, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D The less there is here, the better. After a decade it is time to remove the \type +%D {\pdf*} ones completely. For the moment I keep them commented but even that will +%D go away. + +\writestatus{loading}{ConTeXt Backend Macros / PDF} + +\registerctxluafile{lpdf-ini}{optimize} +\registerctxluafile{lpdf-lmt}{optimize} + +\registerctxluafile{lpdf-col}{} +\registerctxluafile{lpdf-xmp}{} +\registerctxluafile{lpdf-ano}{} +\registerctxluafile{lpdf-res}{} +\registerctxluafile{lpdf-mis}{} +\registerctxluafile{lpdf-ren}{} +\registerctxluafile{lpdf-grp}{} +\registerctxluafile{lpdf-wid}{} +\registerctxluafile{lpdf-fld}{} +\registerctxluafile{lpdf-mov}{} +\registerctxluafile{lpdf-u3d}{} % this will become a module +\registerctxluafile{lpdf-swf}{} % this will become a module +\registerctxluafile{lpdf-tag}{} +\registerctxluafile{lpdf-fmt}{} +\registerctxluafile{lpdf-pde}{} +\registerctxluafile{lpdf-img}{optimize} +\registerctxluafile{lpdf-epa}{} +\registerctxluafile{lpdf-emb}{optimize} +\registerctxluafile{lpdf-fnt}{} + +\registerctxluafile{back-pdp}{} +\registerctxluafile{back-pdf}{} % some code will move to lpdf-* + +\loadmarkfile{back-u3d} % this will become a module +\loadmarkfile{back-swf} % this will become a module + +\unprotect + +%D We will minimize the number of calls to \PDF\ specific primitives and delegate +%D all management and injection of code to the backend. +%D +%D Because we do a lot in \LUA\ and don't want interferences, we nil most of the +%D \PDFTEX\ primitives. Of course one can always use the \type {\pdfvariable}, +%D \type {\pdfextension} and \type {\pdffeedback} primitives but it will probably +%D have bad side effects. + +\unexpanded\def\pdfextension{\clf_pdfextension} + \def\pdffeedback {\clf_pdffeedback} + +%D For the moment we keep this for tikz but hopefully it will at some point use +%D the proper ones. Consider them obsolete: + +\unexpanded\def\pdfliteral {\clf_pdfliteral} +\unexpanded\def\pdfobj {\clf_pdfobj}% +\unexpanded\def\pdflastobj {\numexpr\clf_pdflastobj\relax} +\unexpanded\def\pdfrefobj {\clf_pdfrefobj } + +\unexpanded\def\pdfrestore {\clf_restore} +\unexpanded\def\pdfsave {\clf_save} +\unexpanded\def\pdfsetmatrix{\clf_setmatrix} + + \let\pdfxform \saveboxresource + \let\pdflastxform \lastsavedboxresourceindex + \let\pdfrefxform \useboxresource + +%D Here are quick and dirty compression flippers, mostly used when testing something +%D as one can best stick to the defaults that also adapt to specific standards. + +\unexpanded\def\nopdfcompression {\clf_setpdfcompression\zerocount\zerocount} +\unexpanded\def\onlypdfobjectcompression{\clf_setpdfcompression\zerocount\plusthree} +\unexpanded\def\maximumpdfcompression {\clf_setpdfcompression\plusnine \plusnine } +\unexpanded\def\normalpdfcompression {\clf_setpdfcompression\plusthree\plusthree} + +%D PDF/X (maybe combine the two lua calls) + +\setupbackend + [xmpfile=] + +\appendtoks + \edef\p_file{\backendparameter{xmpfile}}% + \ifx\p_file\empty\else + \clf_setxmpfile{\p_file}% + \fi +\to \everysetupbackend + +%D This will change: + +\appendtoks + \clf_setformat + format {\backendparameter\c!format}% + level {\backendparameter\c!level}% + option {\backendparameter\c!option}% + profile {\backendparameter\c!profile}% + intent {\backendparameter\c!intent}% + file {\backendparameter\c!file}% + \relax +\to \everysetupbackend + +%D These are the only official methods to add stuff to the resources. If more is +%D needed for third party low level code, it can be added. + +\unexpanded\def\pdfbackendsetcatalog #1#2{\clf_lpdf_addtocatalog{#1}{#2}} +\unexpanded\def\pdfbackendsetinfo #1#2{\clf_lpdf_addtoinfo{#1}{#2}} +\unexpanded\def\pdfbackendsetname #1#2{\clf_lpdf_addtonames{#1}{#2}} + +\unexpanded\def\pdfbackendsetpageattribute #1#2{\clf_lpdf_addtopageattributes{#1}{#2}} +\unexpanded\def\pdfbackendsetpagesattribute#1#2{\clf_lpdf_addtopagesattributes{#1}{#2}} +\unexpanded\def\pdfbackendsetpageresource #1#2{\clf_lpdf_addtopageresources{#1}{#2}} + +\unexpanded\def\pdfbackendsetextgstate #1#2{\clf_lpdf_adddocumentextgstate{#1}{#2}} +\unexpanded\def\pdfbackendsetcolorspace #1#2{\clf_lpdf_adddocumentcolorspace{#1}{#2}} +\unexpanded\def\pdfbackendsetpattern #1#2{\clf_lpdf_adddocumentpattern{#1}{#2}} +\unexpanded\def\pdfbackendsetshade #1#2{\clf_lpdf_adddocumentshade{#1}{#2}} + + \def\pdfbackendcurrentresources {\clf_lpdf_collectedresources} + \def\pdfcolor #1{\clf_lpdf_color\numexpr\thecolorattribute{#1}\relax} + +%D This is a temporary hack mthat will be removed, improved or somehow can become +%D default. + +\def\TransparencyHack{\setupcolors[\c!pagecolormodel=\v!auto]} + +%D Just in case one needs this \unknown: +%D +%D \starttyping +%D text \pdfbackendactualtext{Meier}{Müller} text +%D \stoptyping + +\unexpanded\def\pdfbackendactualtext#1#2% not interfaced + {\clf_startactualtext{#2}% + #1% + \clf_stopactualtext} + +\let\pdfactualtext\pdfbackendactualtext + +\protect \endinput diff --git a/tex/context/base/mkiv/buff-ver.mkiv b/tex/context/base/mkiv/buff-ver.mkiv index 91778bc4a..75ee992e4 100644 --- a/tex/context/base/mkiv/buff-ver.mkiv +++ b/tex/context/base/mkiv/buff-ver.mkiv @@ -140,8 +140,7 @@ %D \macros %D {definetype,setuptype} %D -%D Specific inline verbatim commands can be defined with the -%D following command. +%D Specific inline verbatim commands can be defined with the following command. \installcorenamespace{type} @@ -158,9 +157,8 @@ %D \macros %D {definetyping,setuptyping} %D -%D For most users the standard \type{\start}||\type{\stop}||pair -%D will suffice, but for documentation purposes the next -%D definition command can be of use: +%D For most users the standard \type {\start}||\type {\stop}||pair will suffice, but +%D for documentation purposes the next definition command can be of use: %D %D \starttyping %D \definetyping[extratyping][margin=3em] @@ -198,31 +196,27 @@ \let\doifvisualizerelse\doifelsevisualizer -%D Verbatim command are very sensitive to argument processing, -%D which is a direct result of the \CATCODES\ being fixed at -%D reading time. +%D Verbatim command are very sensitive to argument processing, which is a direct +%D result of the \CATCODES\ being fixed at reading time. %D -%D Typesetting inline verbatim can be accomplished by -%D \type{\type}, which in this sentence was typeset by saying -%D just \type{\type{\type}}, which in turn was typeset by -%D \unknown. Using the normal grouping characters \type{{}} is -%D the most natural way of using this command. +%D Typesetting inline verbatim can be accomplished by \type {\type}, which in this +%D sentence was typeset by saying just \type {\type {\type}}, which in turn was +%D typeset by \unknown. Using the normal grouping characters \type {{}} is the most +%D natural way of using this command. %D -%D A second, more or less redundant, alternative is delimiting -%D the argument with an own character. This method was -%D implemented in the context of a publication in the \MAPS, -%D where this way of delimiting is recognized by \LATEX\ users. +%D A second, more or less redundant, alternative is delimiting the argument with an +%D own character. This method was implemented in the context of a publication in the +%D \MAPS, where this way of delimiting is recognized by \LATEX\ users. +%D +%D The third, more original alternative, is the one using \type {<<} and \type {>>} +%D as delimiters. This alternative can be used in situations where slanted +%D typeseting is needed. %D -%D The third, more original alternative, is the one using -%D \type{<<} and \type{>>} as delimiters. This alternative can -%D be used in situations where slanted typeseting is needed. - %D \macros %D {type} %D -%D We define \type{\type} as a protected command. This command -%D has several invocations: grouped, wirt boundary characters, -%D and with font switches. +%D We define \type {\type} as a protected command. This command has several +%D invocations: grouped, wirt boundary characters, and with font switches. %D %D \starttyping %D normal: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par @@ -234,17 +228,14 @@ %D none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par %D \stoptyping %D -%D When writing the manual to \CONTEXT\ and documenting this -%D source we needed to typeset \type{<<} and \type{>>}. Because -%D we wanted to do this in the natural way, we've adapted the -%D original definition a bit. This implementation went through -%D several live cycles. The final implementation looks a bit -%D further and treats the lone \type{<<} and \type{>>} a bit -%D different. The \type {\null} prevents ligatures, which -%D unfortunately turn up in Lucida fonts. +%D When writing the manual to \CONTEXT\ and documenting this source we needed to +%D typeset \type {<<} and \type {>>}. Because we wanted to do this in the natural +%D way, we've adapted the original definition a bit. This implementation went +%D through several live cycles. The final implementation looks a bit further and +%D treats the lone \type {<<} and \type {>>} a bit different. The \type {\null} +%D prevents ligatures, which unfortunately turn up in Lucida fonts. %D -%D The following lines show what happens when we set -%D \type {option=commands}. +%D The following lines show what happens when we set \type {option=commands}. %D %D \startbuffer %D \starttyping @@ -261,9 +252,8 @@ %D %D \typebuffer -% Beware, the command is supposed to do something like \framed and not -% manipulate content i.e. it gets no argument but something b/egrouped -% instead: +% Beware, the command is supposed to do something like \framed and not manipulate +% content i.e. it gets no argument but something b/egrouped instead: \def\buff_verbatim_left_of_type {\typeparameter\c!left @@ -294,38 +284,21 @@ \let\specialobeyedspace\specialstretchedspace \doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop} -\startmkivmode - - \def\buff_verbatim_type_nop - {\buff_verbatim_left_of_type - \futurelet\next\buff_verbatim_type_one} - - \def\buff_verbatim_type_one - {\ifx\next\bgroup - \expandafter\buff_verbatim_type_a - \else - \expandafter\buff_verbatim_type_two - \fi} - - \def\buff_verbatim_type_two - {\catcode`<=\othercatcode % old precaution - \catcode`>=\othercatcode % old precaution - \futurelet\next\buff_verbatim_type_three} +\def\buff_verbatim_type_nop + {\buff_verbatim_left_of_type + \futurelet\next\buff_verbatim_type_one} -\stopmkivmode - -\startlmtxmode - - \def\buff_verbatim_type_nop - {\buff_verbatim_left_of_type - \futureexpand\bgroup\buff_verbatim_type_a\buff_verbatim_type_one} - - \def\buff_verbatim_type_one - {\catcode`<=\othercatcode % old precaution - \catcode`>=\othercatcode % old precaution - \futureexpandis<\buff_verbatim_type_b\buff_verbatim_type_c} +\def\buff_verbatim_type_one + {\ifx\next\bgroup + \expandafter\buff_verbatim_type_a + \else + \expandafter\buff_verbatim_type_two + \fi} -\stoplmtxmode +\def\buff_verbatim_type_two + {\catcode`<=\othercatcode % old precaution + \catcode`>=\othercatcode % old precaution + \futurelet\next\buff_verbatim_type_three} \def\buff_verbatim_type_three {\if\next<% @@ -396,12 +369,11 @@ %D \macros %D {obeyhyphens,obeybreakpoints} %D -%D Although it's not clear from the macros, one character -%D trait of this macros, which are build on top of the support -%D module, is that they don't hyphenate. We therefore offer -%D the alternative \type{\typ}. The current implementation -%D works all right, but a decent hyphenation support of -%D \type{\tt} text will be implemented soon. +%D Although it's not clear from the macros, one character trait of this macros, +%D which are build on top of the support module, is that they don't hyphenate. We +%D therefore offer the alternative \type{\typ}. The current implementation works all +%D right, but a decent hyphenation support of \type{\tt} text will be implemented +%D soon. \unexpanded\def\specialfixedspace {\kern\interwordspace\relax} \unexpanded\def\specialobeyedspace {\hskip\interwordspace\relax} % better than spaceskip @@ -435,13 +407,11 @@ %D \macros %D {tex,arg,mat,dis,astype} %D -%D Sometimes, for instance when we pass verbatim text as an -%D argument, the fixed \CATCODES\ interfere with our wishes. An -%D experimental implementation of character by character -%D processing of verbatim text did overcome this limitation, -%D but we've decided not to use that slow and sometimes -%D troublesome solution. Instead we stick to some 'old' -%D \CONTEXT\ macros for typesetting typical \TEX\ characters. +%D Sometimes, for instance when we pass verbatim text as an argument, the fixed +%D \CATCODES\ interfere with our wishes. An experimental implementation of character +%D by character processing of verbatim text did overcome this limitation, but we've +%D decided not to use that slow and sometimes troublesome solution. Instead we stick +%D to some 'old' \CONTEXT\ macros for typesetting typical \TEX\ characters. \def\lesscharacter {<} % obsolete \def\morecharacter {>} % obsolete @@ -490,32 +460,18 @@ \let\beginofverbatimlines\relax % hooks \let\endofverbatimlines \relax % hooks -\startmkivmode - - \unexpanded\def\buff_verbatim_typing_start#1% tricky non standard lookahead - {\begingroup - \edef\currenttyping{#1}% - \obeylines - \futurelet\nexttoken\buff_verbatim_typing_start_indeed} - - \def\buff_verbatim_typing_start_indeed - {\ifx\nexttoken[% - \expandafter\buff_verbatim_typing_start_yes - \else - \expandafter\buff_verbatim_typing_start_nop - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\buff_verbatim_typing_start#1% tricky non standard lookahead - {\begingroup - \edef\currenttyping{#1}% - \obeylines - \futureexpandis[\buff_verbatim_typing_start_yes\buff_verbatim_typing_start_nop} +\unexpanded\def\buff_verbatim_typing_start#1% tricky non standard lookahead + {\begingroup + \edef\currenttyping{#1}% + \obeylines + \futurelet\nexttoken\buff_verbatim_typing_start_indeed} -\stoplmtxmode +\def\buff_verbatim_typing_start_indeed + {\ifx\nexttoken[% + \expandafter\buff_verbatim_typing_start_yes + \else + \expandafter\buff_verbatim_typing_start_nop + \fi} \unexpanded\def\buff_verbatim_setup_keep_together {\edef\p_keeptogether{\typingparameter\c!keeptogether}% @@ -593,8 +549,8 @@ \endgroup \dorechecknextindentation} -%D Line numbering for files is combined with filtering, while -%D display verbatim has the ability to continue. +%D Line numbering for files is combined with filtering, while display verbatim has +%D the ability to continue. %D %D \starttyping %D \typefile[numbering=file,start=10,stop=12]{test.tex} @@ -640,10 +596,9 @@ %D \macros %D {typefile} %D -%D Typesetting files verbatim (for the moment) only supports -%D colorization of \TEX\ sources as valid option. The other -%D setup values are inherited from display verbatim. -%D The implementation of \type{\typefile} is straightforward: +%D Typesetting files verbatim (for the moment) only supports colorization of \TEX\ +%D sources as valid option. The other setup values are inherited from display +%D verbatim. The implementation of \type {\typefile} is straightforward: % [category] [settings] {name} % for historic reasons, all filenames are {} @@ -784,10 +739,9 @@ \unexpanded\def\verbatim#1{\detokenize{#1}} -%D The setups for display verbatim and file verbatim are -%D shared. One can adapt the extra defined typing environments, -%D but they also default to the values below. Watch the -%D alternative escape character. +%D The setups for display verbatim and file verbatim are shared. One can adapt the +%D extra defined typing environments, but they also default to the values below. +%D Watch the alternative escape character. % \tttf gives problems with {\tx \type...} % \tt\tf does not adapt to e.g. \bf diff --git a/tex/context/base/mkiv/buff-ver.mkxl b/tex/context/base/mkiv/buff-ver.mkxl new file mode 100644 index 000000000..dec4dfb4a --- /dev/null +++ b/tex/context/base/mkiv/buff-ver.mkxl @@ -0,0 +1,1005 @@ +%D \module +%D [ file=buff-ver, % was core-ver +%D version=2000.05.09, +%D title=\CONTEXT\ Buffer Macros, +%D subtitle=Verbatim, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% check after-first and before-last breaks + +\writestatus{loading}{ConTeXt Buffer Macros / Verbatim} + +\registerctxluafile{buff-ver}{} + +\unprotect + +\startcontextdefinitioncode + +\definesystemattribute[verbatimline][public] + +\appendtoksonce + \attribute\verbatimlineattribute\attributeunsetvalue +\to \everyforgetall + +%D Initializations. + +\installcorenamespace{typinglines} +\installcorenamespace{typingspace} +\installcorenamespace{typingblank} % needs checking ... used? + +\newtoks\everyinitializeverbatim + +\appendtoks + \the\everyresettypesetting + \resetfontfeature + \resetcharacterspacing +\to \everyinitializeverbatim + +\unexpanded\def\setverbatimspaceskip % to be checked: must happen after font switch + {\spaceskip\fontcharwd\font`x\relax + \xspaceskip\spaceskip} + +\setvalue{\??typinglines\v!no }{\buff_verbatim_ignore_hyphens} +\setvalue{\??typinglines\v!normal }{\buff_verbatim_ignore_hyphens} +\setvalue{\??typinglines\v!yes }{\buff_verbatim_obey_breakpoints} +\setvalue{\??typinglines\v!hyphenated}{\buff_verbatim_obey_hyphens} + +\setvalue{\??typingspace\v!on }{\let\obeyedspace\specialcontrolspace} +\setvalue{\??typingspace\v!stretch }{\let\obeyedspace\specialstretchedspace} +\setvalue{\??typingspace\v!normal }{} +\setvalue{\??typingspace\v!fixed }{\let\obeyedspace\specialfixedspace} + +\setvalue{\??typingblank\v!standard }{\s_spac_whitespace_parskip} +\setvalue{\??typingblank\v!small }{\smallskipamount} +\setvalue{\??typingblank\v!medium }{\medskipamount} +\setvalue{\??typingblank\v!big }{\bigskipamount} +\setvalue{\??typingblank\v!halfline }{.5\baselineskip} +\setvalue{\??typingblank\v!line }{\baselineskip} +\setvalue{\??typingblank\v!none }{\zeropoint} + +\unexpanded\def\buff_verbatim_obey_hyphens + {} + +\unexpanded\def\buff_verbatim_obey_breakpoints + {\language\minusone % tricky as this affects the pagebuilder + \veryraggedright} + +\unexpanded\def\buff_verbatim_ignore_hyphens + {\language\minusone} % tricky as this affects the pagebuilder + +\def\buff_verbatim_initialize_type_one + {\let\obeylines\ignorelines + \edef\p_buff_option{\typeparameter\c!option}% + \ifx\p_buff_option\v!none + \usetypestyleandcolor\c!style\c!color + \orelse\ifx\p_buff_option\empty + \usetypestyleandcolor\c!style\c!color + \else + \usetypestyleparameter\c!style % no color + \fi + \setcatcodetable\vrbcatcodes} + +\def\buff_verbatim_initialize_type_two + {\spaceskip.5\emwidth\relax + \let\obeyedspace\specialobeyedspace + \let\controlspace\specialcontrolspace + \edef\p_buff_lines{\typeparameter\c!lines}% + \begincsname\??typinglines\p_buff_lines\endcsname + \edef\p_buff_space{\typeparameter\c!space}% + \begincsname\??typingspace\p_buff_space\endcsname + \relax\the\everyinitializeverbatim\relax} + +\unexpanded\def\doinitializeverbatim % for use elsewhere .. temp hack (see lxml-ini) + {\buff_verbatim_initialize_type_one + \buff_verbatim_initialize_type_two} + +\let\buff_verbatim_set_line_margin\relax + +\def\buff_verbatim_set_line_margin_indeed + {\hskip\doifelseoddpage{\typingparameter\c!oddmargin}{\typingparameter\c!evenmargin}\relax} + +\def\buff_verbatim_initialize_typing_one + {\usebodyfontparameter\typingparameter + \scratchskip\typingparameter\c!oddmargin\relax + \ifzeropt\scratchskip \else + \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed + \fi + \scratchskip\typingparameter\c!evenmargin\relax + \ifzeropt\scratchskip \else + \let\buff_verbatim_set_line_margin\buff_verbatim_set_line_margin_indeed + \fi + \ifx\buff_verbatim_set_line_margin\relax + \doadaptleftskip{\typingparameter\c!margin}% + \fi + \edef\p_buff_option{\typingparameter\c!option}% + \ifx\p_buff_option\v!none + \usetypingstyleandcolor\c!style\c!color + \orelse\ifx\p_buff_option\empty + \usetypingstyleandcolor\c!style\c!color + \else + \usetypingstyleparameter\c!style % no color ! + \fi + \usealignparameter\typingparameter} + +\def\buff_verbatim_initialize_typing_two + {\spaceskip.5\emwidth\relax + \let\obeyedspace\specialobeyedspace + \let\controlspace\specialcontrolspace + \edef\p_buff_lines{\typingparameter\c!lines}% + \begincsname\??typinglines\p_buff_lines\endcsname + \edef\p_buff_space{\typingparameter\c!space}% + \begincsname\??typingspace\p_buff_space\endcsname + \relax\the\everyinitializeverbatim\relax} + +%D \macros +%D {definetype,setuptype} +%D +%D Specific inline verbatim commands can be defined with the following command. + +\installcorenamespace{type} + +\installcommandhandler \??type {type} \??type + +\appendtoks + \setuevalue{\currenttype}{\buff_verbatim_type{\currenttype}}% +\to \everydefinetype + +\appendtoks + \buff_verbatim_initialize_visualizer{\typeparameter\c!option}% +\to \everysetuptype + +%D \macros +%D {definetyping,setuptyping} +%D +%D For most users the standard \type {\start}||\type {\stop}||pair will suffice, but +%D for documentation purposes the next definition command can be of use: +%D +%D \starttyping +%D \definetyping[extratyping][margin=3em] +%D +%D \startextratyping +%D these extra ones are indented by 1 em +%D \stopextratyping +%D \stoptyping +%D +%D The definitions default to the standard typing values. + +\installcorenamespace{typing} + +\installcommandhandler \??typing {typing} \??typing + +\appendtoks + \setuevalue{\e!start\currenttyping}{\buff_verbatim_typing_start{\currenttyping}}% + \setuevalue{\e!stop \currenttyping}{\buff_verbatim_typing_stop {\currenttyping}}% + \ifx\currenttypingparent\empty + \normalexpanded{\definelinenumbering[\currenttyping]}% + \else + \normalexpanded{\definelinenumbering[\currenttyping][\currenttypingparent]}% + \fi +\to \everydefinetyping + +\appendtoks + \buff_verbatim_initialize_visualizer{\typingparameter\c!option}% we can check at the tex end +\to \everysetuptyping + +\def\buff_verbatim_initialize_visualizer#1% + {\ifproductionrun\clf_loadvisualizer{#1}\fi} + +\unexpanded\def\doifelsevisualizer#1% + {\clf_doifelsevisualizer{#1}} + +\let\doifvisualizerelse\doifelsevisualizer + +%D Verbatim command are very sensitive to argument processing, which is a direct +%D result of the \CATCODES\ being fixed at reading time. +%D +%D Typesetting inline verbatim can be accomplished by \type {\type}, which in this +%D sentence was typeset by saying just \type {\type {\type}}, which in turn was +%D typeset by \unknown. Using the normal grouping characters \type {{}} is the most +%D natural way of using this command. +%D +%D A second, more or less redundant, alternative is delimiting the argument with an +%D own character. This method was implemented in the context of a publication in the +%D \MAPS, where this way of delimiting is recognized by \LATEX\ users. +%D +%D The third, more original alternative, is the one using \type {<<} and \type {>>} +%D as delimiters. This alternative can be used in situations where slanted +%D typeseting is needed. +%D +%D \macros +%D {type} +%D +%D We define \type {\type} as a protected command. This command has several +%D invocations: grouped, wirt boundary characters, and with font switches. +%D +%D \starttyping +%D normal: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par +%D normal: \par \type{xx<..xx.. >..>xx} \par \type{<....>} \par \type{<....>} +%D \setuptype[option=slanted] +%D slanted: \par \type{xx<<..sl..<> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<>..>> \par +%D slanted: \par \type{xx<<..sl.. xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<....>> \par +%D \setuptype[option=none] +%D none: \par \type{xx<<..xx..<> >>..>>xx} \par \type<<....>> \par \type<<..<>..>> \par +%D \stoptyping +%D +%D When writing the manual to \CONTEXT\ and documenting this source we needed to +%D typeset \type {<<} and \type {>>}. Because we wanted to do this in the natural +%D way, we've adapted the original definition a bit. This implementation went +%D through several live cycles. The final implementation looks a bit further and +%D treats the lone \type {<<} and \type {>>} a bit different. The \type {\null} +%D prevents ligatures, which unfortunately turn up in Lucida fonts. +%D +%D The following lines show what happens when we set \type {option=commands}. +%D +%D \startbuffer +%D \starttyping +%D test//test test/BTEX \footnote{test test test}/ETEX test +%D test//test test/BTEX \footnote{test test test}/ETEX test +%D test test test/BTEX \bf(nota bene)/ETEX test +%D test test test /BTEX \bf(nota bene)/ETEX test +%D \stoptyping +%D \stopbuffer +%D +%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup +%D +%D this was keyed in as: +%D +%D \typebuffer + +% Beware, the command is supposed to do something like \framed and not manipulate +% content i.e. it gets no argument but something b/egrouped instead: + +\def\buff_verbatim_left_of_type + {\typeparameter\c!left + \typeparameter\c!command\bgroup} + +\def\buff_verbatim_right_of_type + {\egroup + \typeparameter\c!right} + +\unexpanded\def\type{\buff_verbatim_type\empty} +\unexpanded\def\typ {\buff_verbatim_typ \empty} + +\unexpanded\def\buff_verbatim_type#1% + {\dontleavehmode + \bgroup + \edef\currenttype{#1}% + \doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop} + +\def\buff_verbatim_type_yes[#1]% + {\setupcurrenttype[#1]% + \buff_verbatim_type_nop} + +\def\buff_verbatim_typ#1% + {\dontleavehmode + \bgroup + \edef\currenttype{#1}% + \lettypeparameter\c!lines\v!hyphenated + \let\specialobeyedspace\specialstretchedspace + \doifelsenextoptionalcs\buff_verbatim_type_yes\buff_verbatim_type_nop} + +\def\buff_verbatim_type_nop + {\buff_verbatim_left_of_type + \futureexpand\bgroup\buff_verbatim_type_a\buff_verbatim_type_one} + +\def\buff_verbatim_type_one + {\catcode`<=\othercatcode % old precaution + \catcode`>=\othercatcode % old precaution + \futureexpandis<\buff_verbatim_type_b\buff_verbatim_type_c} + +\def\buff_verbatim_type_three + {\if\next<% + \expandafter\buff_verbatim_type_b + \else + \expandafter\buff_verbatim_type_c + \fi} + +\def\buff_verbatim_type_a + {\buff_verbatim_initialize_type_one + \setcatcodetable\tpacatcodes + \buff_verbatim_type_normal} + +\def\buff_verbatim_type_b#1% + {\buff_verbatim_initialize_type_one + \setcatcodetable\tpbcatcodes + \buff_verbatim_type_nested} + +\def\buff_verbatim_type_c#1% + {\buff_verbatim_initialize_type_one + \setcatcodetable\vrbcatcodes + \def\next##1#1{\buff_verbatim_type_normal{##1}}% + \next} + +\def\buff_verbatim_type_normal#1% + {\buff_verbatim_initialize_type_two + \dostarttaggedchained\t!verbatim\currenttype\??type + \clf_type + data {\detokenize{#1}}% + tab {\typeparameter\c!tab}% + method {\p_buff_option}% + compact {\typeparameter\c!compact}% % none | all | last (all needed in tabulate etc for manuals) + escape {\typeparameter\c!escape}% % new but rather useless imo (escaping in general is not used much) + % nature {inline}% is default + \relax + \dostoptagged + \buff_verbatim_right_of_type + \egroup} + +\def\buff_verbatim_type_nested#1% + {\buff_verbatim_initialize_type_two + \dostarttaggedchained\t!verbatim\currenttype\??type + \clf_type + data {\detokenize{#1}}% + tab {\typeparameter\c!tab}% + method {\p_buff_option}% % extra visualizer (maybe: nested,\typeparameter\c!option) + escape {\typeparameter\c!escape}% % new but rather useless imo (escaping in general is not used much) + % nature {inline}% is default + method {nested}% + \relax + \dostoptagged + \buff_verbatim_right_of_type + \egroup + \gobbleoneargument} % grab last > + +%D The \type {compact} option can come in handy in the case of inline argument passing +%D +%D \starttyping +%D \definetype[TeXcodeA][option=TEX] +%D \definetype[TeXcodeB][option=TEX,compact=all] +%D \definetype[TeXcodeC][option=TEX,compact=absolute] +%D +%D \def\argA#1{\TeXcodeA{{#1}}} +%D \def\argB#1{\TeXcodeB{{#1}}} +%D \def\argC#1{\TeXcodeC{{#1}}} +%D \stoptyping + +%D \macros +%D {obeyhyphens,obeybreakpoints} +%D +%D Although it's not clear from the macros, one character trait of this macros, +%D which are build on top of the support module, is that they don't hyphenate. We +%D therefore offer the alternative \type{\typ}. The current implementation works all +%D right, but a decent hyphenation support of \type{\tt} text will be implemented +%D soon. + +\unexpanded\def\specialfixedspace {\kern\interwordspace\relax} +\unexpanded\def\specialobeyedspace {\hskip\interwordspace\relax} % better than spaceskip +\unexpanded\def\specialstretchedspace {\hskip.5\interwordspace\s!plus.125\interwordspace\relax} % \interwordstretch can be zero +\unexpanded\def\specialcontrolspace {\normalcontrolspace\allowbreak} % uses fallback + +\unexpanded\def\explicitfixedspace {\asciispacechar} +\unexpanded\def\explicitobeyedspace {\asciispacechar\allowbreak} +\unexpanded\def\explicitstretchedspace{\asciispacechar\hskip\zeropoint\s!plus.125\interwordspace\relax}% +\unexpanded\def\explicitcontrolspace {\optionalcontrolspace\allowbreak} % uses asciispace + +\appendtoks + \unexpanded\def\obeyedspace{\hskip\zeropoint\asciispacechar\hskip\zeropoint}% +\to \everyenableelements + +\unexpanded\def\obeyhyphens + {\let\obeyedspace \specialobeyedspace % maybe \specialstretchedspace + \let\controlspace\specialcontrolspace + \spaceskip.25\emwidth\relax} % hm a bit of stretch ! + +\unexpanded\def\obeybreakpoints + {\ignorehyphens + \veryraggedright} + +\unexpanded\def\ignorehyphens + {\language\minusone % extra bonus, the \null should do the job too + \let\obeyedspace \specialobeyedspace + \let\controlspace\specialcontrolspace + \spaceskip.5\emwidth\relax} + +%D \macros +%D {tex,arg,mat,dis,astype} +%D +%D Sometimes, for instance when we pass verbatim text as an argument, the fixed +%D \CATCODES\ interfere with our wishes. An experimental implementation of character +%D by character processing of verbatim text did overcome this limitation, but we've +%D decided not to use that slow and sometimes troublesome solution. Instead we stick +%D to some 'old' \CONTEXT\ macros for typesetting typical \TEX\ characters. + +\def\lesscharacter {<} % obsolete +\def\morecharacter {>} % obsolete + +\let\texescape \textbackslash +\let\leftargument \textbraceleft +\let\rightargument \textbraceright +\let\inlinemathmarker \textdollar +\def\displaymathmarker{\textdollar\textdollar} + +\def\buff_verbatim_special_type#1#2#% # gobbles spaces + {\dontleavehmode\bgroup + \buff_verbatim_initialize_type_one + \catcode\leftbraceasciicode \begingroupcatcode + \catcode\rightbraceasciicode\endgroupcatcode + #1% + \bgroup % else wrong font for #2 + \aftergroup#2% + \aftergroup\egroup + \let\nexttoken} + +\unexpanded\def\tex{\buff_verbatim_special_type\texescape \relax} +\unexpanded\def\arg{\buff_verbatim_special_type\leftargument \rightargument} +\unexpanded\def\mat{\buff_verbatim_special_type\inlinemathmarker \inlinemathmarker} +\unexpanded\def\dis{\buff_verbatim_special_type\displaymathmarker\displaymathmarker} + +\let\normaltexttex\tex +\let\normaltextarg\arg +\let\normaltextmat\mat +\let\normaltextdis\dis + +\unexpanded\def\astype + {\dontleavehmode + \bgroup\usetypestyleandcolor\c!style\c!color\let\nexttoken} + +\unexpanded\def\asciistr#1% used in some old styles + {\dontleavehmode\begingroup + \dostarttagged\t!verbatim\empty + \usetypestyleandcolor\c!style\c!color\detokenize{#1}% + \dostoptagged + \endgroup} + +%D The basic display verbatim commands are defined in an indirect way. As we +%D will see, they are a specific case of a more general mechanism. + +\let\beginofverbatimlines\relax % hooks +\let\endofverbatimlines \relax % hooks + +\unexpanded\def\buff_verbatim_typing_start#1% tricky non standard lookahead + {\begingroup + \edef\currenttyping{#1}% + \obeylines + \futureexpandis[\buff_verbatim_typing_start_yes\buff_verbatim_typing_start_nop} + +\unexpanded\def\buff_verbatim_setup_keep_together + {\edef\p_keeptogether{\typingparameter\c!keeptogether}% + \ifx\p_keeptogether\v!yes + \settrue \c_buff_optimize_linebreaks + \else + \setfalse\c_buff_optimize_linebreaks + \fi} + +\def\buff_verbatim_typing_start_nop + {\typingparameter\c!before + \startpacked[\v!blank]% + \buff_verbatim_setup_line_numbering + \buff_verbatim_initialize_typing_one + \buff_verbatim_setup_keep_together + \normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}} + +\def\buff_verbatim_typing_start_yes[#1]% + {\typingparameter\c!before + \startpacked[\v!blank]% + \ifcondition\validassignment{#1}% + \setupcurrenttyping[#1]% + \else + \doif\v!continue{#1}{\lettypingparameter\c!continue\v!yes}% + \fi + \buff_verbatim_setup_line_numbering + \buff_verbatim_initialize_typing_one + \buff_verbatim_setup_keep_together + \normalexpanded{\buff_verbatim_type_block{\e!start\currenttyping}{\e!stop\currenttyping}}} + +\unexpanded\def\buff_verbatim_type_block#1#2% + {\edef\p_strip{\typingparameter\c!strip}% + \normalexpanded{\buff_pickup + {_typing_}% + {#1}% + {#2}% + {}% + {\buff_verbatim_type_block_verbatim_indeed{#1}{#2}}% + \ifx\p_strip\v!no\zerocount\else\plusone\fi}} + +\unexpanded\def\buff_verbatim_type_block_verbatim_indeed#1#2% + {\buff_verbatim_initialize_typing_two + \dostarttaggedchained\t!verbatimblock\currenttyping\??typing + \beginofverbatimlines + \dostarttagged\t!verbatimlines\empty + \clf_typebuffer + name {_typing_}% + strip {\typingparameter\c!strip}% + range {\typingparameter\c!range}% + tab {\typingparameter\c!tab}% + method {\p_buff_option}% + escape {\typingparameter\c!escape}% + nature {display}% + \relax + \dostoptagged + \endofverbatimlines + \dostoptagged + \begincsname#2\endcsname} + +\unexpanded\def\buff_verbatim_typing_stop#1% hm, currenttyping + {\stoppacked + \typingparameter\c!after + \useindentnextparameter\typingparameter + \endgroup + \dorechecknextindentation} + +%D Line numbering for files is combined with filtering, while display verbatim has +%D the ability to continue. +%D +%D \starttyping +%D \typefile[numbering=file,start=10,stop=12]{test.tex} +%D +%D \definetyping[code][numbering=line] +%D +%D \starttext +%D \startcode +%D ... +%D ... +%D \stopcode +%D +%D \startcode[start=continue] +%D ... +%D ... +%D \stopcode +%D +%D \startcode[start=10] +%D ... +%D \stopcode +%D \stoptyping + +%D Ranges: +%D +%D \starttyping +%D % label:start:one +%D +%D \def\MyMacro +%D {just an example} +%D +%D % label:stop:one +%D +%D \starttext +%D +%D % \typefile[file][range={3,6}] {whatever.tex} +%D % \typefile[file][range={3,+2}]{whatever.tex} +%D +%D \typefile[file][range={label:start:one,label:stop:one}]{whatever.tex} +%D +%D \stoptext +%D \stoptyping + +%D \macros +%D {typefile} +%D +%D Typesetting files verbatim (for the moment) only supports colorization of \TEX\ +%D sources as valid option. The other setup values are inherited from display +%D verbatim. The implementation of \type {\typefile} is straightforward: + +% [category] [settings] {name} % for historic reasons, all filenames are {} + +\unexpanded\def\typefile + {\dodoubleempty\buff_verbatim_type_file} + +\appendtoks + \setuevalue{\e!type\currenttyping\v!file}{\typefile[\currenttyping]}% +\to \everydefinetyping + +\def\buff_verbatim_type_file[#1][#2]#3% + {\begingroup + \ifsecondargument + \setuptyping[#1][#2]% + \buff_verbatim_type_file_checked{#1}{#3}% + \orelse\iffirstargument + \ifcondition\validassignment{#1}% + \setuptyping[\v!file][#1]% + \buff_verbatim_type_file_checked\v!file{#3}% + \else + \buff_verbatim_type_file_checked{#1}{#3}% + \fi + \else + \buff_verbatim_type_file_checked\v!file{#3}% + \fi + \useindentnextparameter\typingparameter % needs checking + \endgroup + \dorechecknextindentation} % needs checking + +\def\buff_verbatim_type_file_checked#1#2% + {\doifelsetypingfile{#2} + {\buff_verbatim_type_file_indeed{#1}\askedtypingfile} + {\showmessage\m!verbatims1{#2}}} + +\unexpanded\def\doifelsetypingfile#1% + {\edef\askedtypingfile{\locfilename{#1}}% + \ifx\askedtypingfile\empty + \edef\askedtypingfile{\locfilename{#1.tex}}% downward compatible + \fi + \ifx\askedtypingfile\empty + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\let\doiftypingfileelse\doifelsetypingfile + +\def\buff_verbatim_type_file_indeed#1#2% category name + {\edef\currenttyping{#1}% + \typingparameter\c!before + \startpacked[\v!blank] + \buff_verbatim_setup_line_numbering + \buff_verbatim_initialize_typing_one + \buff_verbatim_initialize_typing_two + \dostarttaggedchained\t!verbatimblock\currenttyping\??typing + \beginofverbatimlines + \dostarttagged\t!verbatimlines\empty + \clf_typefile + name {#2}% + strip {\typingparameter\c!strip}% + range {\typingparameter\c!range}% + regime {\currentregime}% + tab {\typingparameter\c!tab}% + method {\p_buff_option}% + nature {display}% + \relax + \dostoptagged + \endofverbatimlines + \dostoptagged + \stoppacked + \typingparameter\c!after} + +%D Line numbering: + +\newconditional\verbatimnumberinglines + +\def\beginofverbatimlinenumbering + {\startlinenumbering + [\currenttyping]% + [\c!continue=\typingparameter\c!continue, + \c!method=\v!type, + \c!start=\typingparameter\c!start, + \c!stop=\typingparameter\c!stop, % ? + \c!step=\typingparameter\c!step]} + +\def\endofverbatimlinenumbering + {\stoplinenumbering} + +\def\buff_verbatim_setup_line_numbering + {\ifdefined\startlinenumbering + \edef\currenttypingnumbering{\typingparameter\c!numbering}% + \ifx\currenttypingnumbering\v!file + \setuplinenumbering[\currenttyping][\c!method=\v!file]% + \settrue\verbatimnumberinglines + \orelse\ifx\currenttypingnumbering\v!line + \settrue\verbatimnumberinglines + \else + \setfalse\verbatimnumberinglines + \fi + \ifconditional\verbatimnumberinglines + \let\beginofverbatimlines\beginofverbatimlinenumbering + \let\endofverbatimlines \endofverbatimlinenumbering + \fi + \fi} + +%D \macros +%D {filename} +%D +%D Typesetting filenames in monospaced fonts is possible with +%D +%D \starttyping +%D \filename{here/there/filename.suffix} +%D \stoptyping +%D +%D The definition is not that spectacular. + +\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}} + +%D \macros +%D {verbatim} +%d +%D And a bonus macro, an unexpanded detokenize: + +\unexpanded\def\verbatim#1{\detokenize{#1}} + +%D The setups for display verbatim and file verbatim are shared. One can adapt the +%D extra defined typing environments, but they also default to the values below. +%D Watch the alternative escape character. + +% \tttf gives problems with {\tx \type...} +% \tt\tf does not adapt to e.g. \bf + +\setuptyping + [\c!before=\blank, + \c!after=\blank, + %\c!keeptogether=yes, % this will become default (when tested enough) + %\c!bodyfont=, + %\c!color=, + \c!space=\v!off, + \c!lines=\v!no, + \c!page=\v!no, + \c!tab=\v!yes, % what is this: \s!ascii ? + \c!option=\v!none, + \c!text=\v!no, + \c!style=\tt, + \c!indentnext=\v!yes, + \c!margin=\zeropoint, + \c!evenmargin=\zeropoint, + \c!oddmargin=\zeropoint, + \c!blank=\v!line, + %\c!escape=, % yes | no | {START,STOP} | default when yes: {BTEX,ETEX} + \c!numbering=\v!no, + %\c!range=, + \c!start=1, + %\c!stop=, + \c!step=1, + %\c!continue=, + \c!strip=\v!no] % auto or number + +\definetyping[\v!typing] + +% the \zeropoint forces the number to the margin but also works ok in text + +\setuplinenumbering[\v!typing][\c!location=\v!left,\c!width=\zeropoint] + +\setuptyping [\v!file] [\s!parent=\??typing \v!typing] % we don't want \start..\stop overload +\setuplinenumbering[\v!file] [\s!parent=\??linenumbering\v!typing] + +\setuptyping [\v!buffer][\s!parent=\??typing \v!file] % we don't want \start..\stop overload +\setuplinenumbering[\v!buffer][\s!parent=\??linenumbering\v!file] + +%D The setups for inline verbatim default to: + +\setuptype + [\c!space=\v!off, + \c!lines=\v!no, + %\c!color=, + \c!style=\tt, + %\c!option=\v!normal, + \c!page=\v!no, + \c!tab=\v!yes, + \c!compact=\v!all] + +%D Buffers + +% [name] [settings] | [name] | [settings] + +% \unexpanded\def\typebuffer +% {\dodoubleempty\buff_verbatim_type_buffer} + +\unexpanded\def\typebuffer + {\begingroup + \let\currenttyping\v!buffer + \dodoubleempty\buff_verbatim_type_buffer} + +\unexpanded\def\buff_verbatim_type_defined_buffer + {\dotripleempty\buff_verbatim_type_defined_buffer_indeed} + +\unexpanded\def\typedefinedbuffer[#1]% + {\buff_verbatim_type_defined_buffer[\v!buffer][\thedefinedbuffer{#1}]}% + +\appendtoks + \setuevalue{\e!type\currentbuffer}{\buff_verbatim_type_defined_buffer[\v!buffer][\currentdefinedbuffer]}% +\to \everydefinebuffer + +\appendtoks % \e!buffer + \setuevalue{\e!type\currenttyping\v!buffer}{\buff_verbatim_type_buffer_class{\currenttyping}}% +\to \everydefinetyping + +\unexpanded\def\buff_verbatim_type_buffer[#1][#2]% + {\ifsecondargument + \setupcurrenttyping[#2]% + \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name] [settings] + \orelse\iffirstargument + \ifcondition\validassignment{#1}% + \setupcurrenttyping[#1]% + \buff_verbatim_type_buffer_indeed\currenttyping\empty% [settings] + \else + \processcommalist[#1]{\buff_verbatim_type_buffer_indeed\currenttyping}% [name] + \fi + \else + \buff_verbatim_type_buffer_indeed\currenttyping\empty% [] + \fi + \endgroup + \dorechecknextindentation} + +\unexpanded\def\buff_verbatim_type_buffer_class#1% + {\begingroup + \edef\currenttyping{#1}% + \dodoubleempty\buff_verbatim_type_buffer} + +\unexpanded\def\buff_verbatim_type_defined_buffer_indeed[#1][#2][#3]% category name settings + {\begingroup + \ifthirdargument + \setuptyping[#1][#3]% + \fi + \buff_verbatim_type_buffer_indeed{#1}{#2}% + \endgroup} + +\unexpanded\def\buff_verbatim_type_buffer_indeed#1#2% category name + {\edef\currenttyping{#1}% + \typingparameter\c!before + \startpacked[\v!blank] + \buff_verbatim_setup_line_numbering + \buff_verbatim_initialize_typing_one + \buff_verbatim_initialize_typing_two + \dostarttaggedchained\t!verbatimblock{#1}\??typing + \beginofverbatimlines + \dostarttagged\t!verbatimlines\empty + \clf_typebuffer + name {#2}% + strip {\typingparameter\c!strip}% + range {\typingparameter\c!range}% + regime {\currentregime}% + tab {\typingparameter\c!tab}% + method {\p_buff_option}% + escape {\typingparameter\c!escape}% + nature {display}% + \relax + \dostoptagged + \endofverbatimlines + \dostoptagged + \stoppacked + \typingparameter\c!after + \dorechecknextindentation} + +\unexpanded\def\typeinlinebuffer + {\dontleavehmode + \begingroup + \let\buff_verbatim_type_buffer_indeed\buff_verbatim_type_buffer_indeed_inline + \let\setupcurrenttyping\setupcurrenttype % a terrible hack but it saves code + \let\currenttype\empty + \dodoubleempty\buff_verbatim_type_buffer} + +\unexpanded\def\buff_verbatim_type_buffer_indeed_inline#1#2% category name + {\edef\currenttype{#1}% + \buff_verbatim_initialize_type_one + \dostarttaggedchained\t!verbatim\currenttype\??type + \clf_typebuffer + name {#2}% + strip {\v!yes}% + regime {\currentregime}% + method {\p_buff_option}% + nature {inline}% is default anyway + \relax + \dostoptagged} + +% get : before/after of buffer +% typing : before/after of typing +% process : no before/after (special case anyway) + +% the next one is obsolete (bad name and used nowhere) so if it stays +% the name will change + +\unexpanded\def\processbuffer + {\writestatus{nota bene}{\string\processbuffer\space is obsolete}% + \dodoubleempty\buff_verbatim_process} + +\def\buff_verbatim_process[#1][#2]% + {\begingroup + \ifsecondargument + \setuptyping[\v!buffer][#2]% + \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name] [settings] + \orelse\iffirstargument + \ifcondition\validassignment{#1}% + \setuptyping[\v!buffer][#1]% + \buff_verbatim_process_indeed\v!buffer\empty% [settings] + \else + \processcommalist[#1]{\buff_verbatim_process_indeed\v!buffer}% [name] + \fi + \else + \buff_verbatim_process_indeed\v!buffer\empty% [] + \fi + \endgroup} + +\def\buff_verbatim_process_indeed#1#2% + {\edef\currenttyping{#1}% + \clf_processbuffer + name {#2}% + strip {\typingparameter\c!strip}% + tab {\typingparameter\c!tab}% + % method {\p_buff_option}% + nature {direct}% + \relax} + +% so far for obsolete + +% line numbering, keep broken lines together + +\newcount\nofverbatimlines + +\unexpanded\def\buff_verbatim_begin_of_line + {\ifconditional\verbatimnumberinglines + \global\advance\nofverbatimlines\plusone + \attribute\verbatimlineattribute\nofverbatimlines + \fi + \noindent + \buff_verbatim_set_line_margin + \the\everyline % maybe also after starttagged + \strut % after starttagged, else break ! + \dostarttagged\t!verbatimline\empty + } + +\unexpanded\def\buff_verbatim_end_of_line + {\dostoptagged + \obeyedline % still needed? + \par + \ifconditional\verbatimnumberinglines + \attribute\verbatimlineattribute\attributeunsetvalue + \fi} + +\unexpanded\def\buff_verbatim_empty_line + {\dostoptagged + \ifconditional\verbatimnumberinglines + \par\strut\par % this will be an option where we use a signal instead of a strut + \else + \blank[\typingparameter\c!blank]% + \fi + \dostarttagged\t!verbatimlines\empty} + +% hooks: + +\newcount \c_buff_verbatim_noflines +\newcount \c_buff_verbatim_current +\newconditional\c_buff_optimize_linebreaks + + \def\doverbatimspace {\obeyedspace} + +\unexpanded\def\doinlineverbatimstart {} +\unexpanded\def\doinlineverbatimstop {} +\unexpanded\def\doinlineverbatimbeginline {} +\unexpanded\def\doinlineverbatimnewline {\obeyedspace} +\unexpanded\def\doinlineverbatimemptyline {\obeyedspace} + +\unexpanded\def\dodisplayverbatimstart {\advance\c_buff_verbatim_current\plusone + \buff_verbatim_begin_of_line} +\unexpanded\def\dodisplayverbatimstop {\buff_verbatim_end_of_line} +\unexpanded\def\dodisplayverbatimbeginline{\advance\c_buff_verbatim_current\plusone + \buff_verbatim_begin_of_line} +\unexpanded\def\dodisplayverbatimnewline {\buff_verbatim_end_of_line + \par + \ifconditional\c_buff_optimize_linebreaks + \buff_verbatim_inject_breaks + \fi} +\unexpanded\def\dodisplayverbatimemptyline{\buff_verbatim_empty_line} + +\unexpanded\def\buff_verbatim_inject_breaks + {\ifnum\c_buff_verbatim_current=\plusone + \nobreak + \orelse\ifnum\c_buff_verbatim_noflines=\plusthree + \nobreak + \orelse\ifnum\c_buff_verbatim_current=\numexpr\c_buff_verbatim_noflines-\plusone\relax + \nobreak + \fi} + +\unexpanded\def\dodisplayverbatiminitialize#1% + {\forgetparindent % maybe more + \c_buff_verbatim_noflines#1\relax + \c_buff_verbatim_current\zerocount} + +\loadmarkfile{buff-imp-default} % preloaded as otherwise spurious spaces inline due to loading +\loadmarkfile{buff-imp-nested} % preloaded as otherwise spurious spaces inline due to loading +\loadmarkfile{buff-imp-escaped} % for completeness + +%D To be considered: + +% \installcorenamespace{visualizer} +% +% \installcommandhandler \??visualizer {visualizer} \??visualizer +% +% \appendtoks +% \setuevalue{\currentvisualizer}{\buff_verbatim_visualize{\currentvisualizer}}% +% \to \everydefinevisualizer +% +% \unexpanded\def\buff_verbatim_visualize#1% +% {\bgroup +% \def\currentvisualizer{#1}% +% \usevisualizerstyleandcolor\c!style\c!color +% \let\next} + +\appendtoks + %def\type#1{\letterbackslash\checkedstrippedcsname#1}% or maybe detokenize + \def\type#1{\detokenize\expandafter{\csstring#1}}% or maybe detokenize + \def\tex #1{\letterbackslash#1}% +\to \everysimplifycommands + +\stopcontextdefinitioncode + +\protect \endinput diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index ff4f5e3b1..026d78c0d 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -746,7 +746,7 @@ local s_cldl_argument_e = "}" -- local s_cldl_argument_b = "{" -- local s_cldl_argument_f = "{ " -local t_cldl_luafunction = createtoken("luafunctioncall") +local t_cldl_luafunction = newtoken("luafunctioncall",0) local lua_expandable_call_token_code = token.command_id and token.command_id("lua_expandable_call") local function writer(parent,command,...) -- already optimized before call diff --git a/tex/context/base/mkiv/colo-ini.mkiv b/tex/context/base/mkiv/colo-ini.mkiv index c5639f44a..7e78f0e01 100644 --- a/tex/context/base/mkiv/colo-ini.mkiv +++ b/tex/context/base/mkiv/colo-ini.mkiv @@ -37,16 +37,15 @@ \unprotect -%D In \MKIV\ we have independent color, colorspace and transparency -%D but I'm still not sure if I keep it that way as it's probably more -%D efficient to combine them (less attributes and finalizing). If -%D it becomes a bottleneck we can set up a more complex system -%D with one shared attribute for colorspace, color and transparency. +%D In \MKIV\ we have independent color, colorspace and transparency but I'm still +%D not sure if I keep it that way as it's probably more efficient to combine them +%D (less attributes and finalizing). If it becomes a bottleneck we can set up a more +%D complex system with one shared attribute for colorspace, color and transparency. %D -%D When typesetting for paper, we prefer using the \CMYK\ color space, -%D but for on||screen viewing we prefer \RGB\ (the previous -%D implementation supported only this scheme). Independant of such -%D specifications, we support some automatic conversions: +%D When typesetting for paper, we prefer using the \CMYK\ color space, but for +%D on||screen viewing we prefer \RGB\ (the previous implementation supported only +%D this scheme). Independant of such specifications, we support some automatic +%D conversions: %D %D \startitemize[packed] %D \item convert all colors to \RGB @@ -111,8 +110,7 @@ %D \macros %D {startcolor,stopcolor,color,graycolor} %D -%D The local and global commands are here just for compatibility -%D with \MKII. +%D The local and global commands are here just for compatibility with \MKII. %D %D \showsetup{startcolor} %D @@ -274,11 +272,11 @@ %D %D \showsetup{usecolors} %D -%D Some default colors are specified in \type {colo-imp-rgb}, -%D which is loaded into the format by default. +%D Some default colors are specified in \type {colo-imp-rgb}, which is loaded into +%D the format by default. %D -%D Some demo palets and groups are defined in \type {colo-imp-dem} -%D which can be loaded with: +%D Some demo palets and groups are defined in \type {colo-imp-dem} which can be +%D loaded with: %D %D \starttyping %D \usecolors[dem] @@ -371,33 +369,27 @@ {\attribute\colorattribute \c_colo_saved_attribute_color \attribute\transparencyattribute\c_colo_saved_attribute_transparency} -%D In this documentation we will not go into too much details -%D on palets. Curious users can find more information on this -%D topic in \from[use of color]. +%D In this documentation we will not go into too much details on palets. Curious +%D users can find more information on this topic in \from[use of color]. %D -%D At the moment we implemented color in \CONTEXT\ color -%D printing was not yet on the desktop. In spite of this lack our -%D graphics designer made colorfull illustrations. When printed -%D on a black and white printer, distinctive colors can come -%D out equally gray. We therefore decided to use only colors -%D that were distinctive in colors as well as in black and -%D white print. +%D At the moment we implemented color in \CONTEXT\ color printing was not yet on the +%D desktop. In spite of this lack our graphics designer made colorfull +%D illustrations. When printed on a black and white printer, distinctive colors can +%D come out equally gray. We therefore decided to use only colors that were +%D distinctive in colors as well as in black and white print. %D -%D Although none of the graphic packages we used supported -%D logical colors and global color redefition, we build this -%D support into \CONTEXT. This enabled us to experiment and -%D also prepared us for the future. +%D Although none of the graphic packages we used supported logical colors and global +%D color redefition, we build this support into \CONTEXT. This enabled us to +%D experiment and also prepared us for the future. %D \macros %D {definepalet} %D -%D Colors are grouped in palets. The colors in such a palet can -%D have colorful names, but best is to use names that specify -%D their use, like {\em important} or {\em danger}. As a sort -%D of example \CONTEXT\ has some palets predefined, -%D like:\footnote{At the time I wrote the palet support, I was -%D reading 'A hort history of time' of S.~Hawkins, so that's -%D why we stuck to quarks.} +%D Colors are grouped in palets. The colors in such a palet can have colorful names, +%D but best is to use names that specify their use, like {\em important} or {\em +%D danger}. As a sort of example \CONTEXT\ has some palets predefined, +%D like:\footnote{At the time I wrote the palet support, I was reading 'A hort +%D history of time' of S.~Hawkins, so that's why we stuck to quarks.} %D %D \starttyping %D \definepalet @@ -424,8 +416,8 @@ %D \getbuffer[palet] %D \stoplinecorrection %D -%D This bar shows both the color and gray alternatives of the -%D palet components (not visible in black and white print). +%D This bar shows both the color and gray alternatives of the palet components (not +%D visible in black and white print). %D %D When needed, one can copy a palet by saying: %D @@ -433,8 +425,8 @@ %D \definepalet [TEXcolorpretty] [colorpretty] %D \stoptyping %D -%D This saves us some typing in for instance the modules that -%D deal with pretty verbatim typesetting. +%D This saves us some typing in for instance the modules that deal with pretty +%D verbatim typesetting. \installcorenamespace{paletlist} \installcorenamespace{paletsize} @@ -538,8 +530,7 @@ \processcommacommand[\lastnamedcs]{\colo_palets_define_one{#1}}% \fi} -%D Instead of refering to colors, one can also directly specify -%D a color: +%D Instead of refering to colors, one can also directly specify a color: %D %D \starttyping %D \definepalet[test][xx=green] @@ -549,8 +540,8 @@ %D \macros %D {setuppalet} %D -%D Colors are taken from the current palet, if defined. -%D Setting the current palet is done by: +%D Colors are taken from the current palet, if defined. Setting the current palet is +%D done by: %D %D \showsetup{setuppalet} @@ -642,8 +633,8 @@ %D \macros %D {showcolor} %D -%D But let's not forget that we also have the more traditional -%D non||related colors. These show up after: +%D But let's not forget that we also have the more traditional non||related colors. +%D These show up after: %D %D \starttyping %D \showcolor [name] @@ -655,8 +646,8 @@ \fetchruntimecommand \showcolor \f!colo_run -%D It would make sense to put the following code in \type -%D {colo-mps}, but it it rather low level. +%D It would make sense to put the following code in \type {colo-mps}, but it it +%D rather low level. %D \macros %D {negatecolorcomponent,negatedcolorcomponent} @@ -687,8 +678,8 @@ %D \macros %D {MPcolor} %D -%D A very special macro is \type{\MPcolor}. This one can be -%D used to pass a \CONTEXT\ color to \METAPOST. +%D A very special macro is \type{\MPcolor}. This one can be used to pass a \CONTEXT\ +%D color to \METAPOST. %D %D \starttyping %D \MPcolor{my own red} @@ -697,15 +688,13 @@ %D This macro returns \METAPOST\ code that represents the %D color. %D -%D For the moment we keep the next downward compatibility -%D switch, i.e.\ expanded colors. However, predefined colors -%D and palets are no longer expanded (which is what I wanted -%D in the first place). +%D For the moment we keep the next downward compatibility switch, i.e.\ expanded +%D colors. However, predefined colors and palets are no longer expanded (which is +%D what I wanted in the first place). %D -%D In \MKIV\ we don't support color separation as we might now -%D assume that printing houses have the right programs to do -%D it themselves. If it's ever needed in \MKIV\ It is relatively -%D easy to support it in the backend code. +%D In \MKIV\ we don't support color separation as we might now assume that printing +%D houses have the right programs to do it themselves. If it's ever needed in \MKIV\ +%D It is relatively easy to support it in the backend code. % todo: palets in definecolor % todo: {\red xx} vs \red{xx} @@ -755,12 +744,12 @@ \fi \fi} -% Currently in mkiv transparency is implemented independent of color. This costs -% a bit more processing time but gives the possibility to apply transparency -% independently in the future. Is this useful? If not we may as well combine them -% again in the future. By coupling we are downward compatible. When we decouple we -% need to do more tricky housekeeping (e.g. persist color independent transparencies -% when color bound ones are nil. +%D Currently in mkiv transparency is implemented independent of color. This costs a +%D bit more processing time but gives the possibility to apply transparency +%D independently in the future. Is this useful? If not we may as well combine them +%D again in the future. By coupling we are downward compatible. When we decouple we +%D need to do more tricky housekeeping (e.g. persist color independent +%D transparencies when color bound ones are nil. % Since we couple definitions, we could stick to one test. Todo. Same for mpcolor. @@ -953,10 +942,9 @@ \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}% \fi} -% Spotcolors used setxvalue but that messes up currentcolor -% and probably no global is needed either but they are global -% at the lua end (true argument) so we keep that if only because -% spot colors often are a document wide property +%D Spotcolors used setxvalue but that messes up currentcolor and probably no global +%D is needed either but they are global at the lua end (true argument) so we keep +%D that if only because spot colors often are a document wide property \def\colo_basics_define_spot[#1][#2][#3]% {\clf_definespotcolorglobal{#1}{#2}{#3}% @@ -1008,8 +996,8 @@ % % \definecolor[one][two] % -% only color one is actually defined and two is not seen at the -% \LUA\ end. This means that this doesn't work: +% Only color one is actually defined and two is not seen at the \LUA\ end. This +% means that this doesn't work: % % \definecolor[ColorA][red] % \definecolor[ColorB][.5(ColorA)] @@ -1093,9 +1081,8 @@ %D \macros %D {doifcolorelse, doifcolor} %D -%D Switching to a color is done by means of the following -%D command. Later on we will explain the use of palets. We -%D define ourselves a color conditional first. +%D Switching to a color is done by means of the following command. Later on we will +%D explain the use of palets. We define ourselves a color conditional first. \def\doifelsecolor#1% {\ifcsname\??colorattribute\currentcolorprefix#1\endcsname @@ -1120,13 +1107,11 @@ %D \macros %D {startregistercolor,stopregistercolor,permitcolormode} %D -%D If you only want to register a color, the switch \type -%D {\ifpermitcolormode} can be used. That way the nested -%D colors know where to go back to. +%D If you only want to register a color, the switch \type {\ifpermitcolormode} can +%D be used. That way the nested colors know where to go back to. %D -%D We use these macros for implementing text colors -%D (actually, the first application was in foreground -%D colors). +%D We use these macros for implementing text colors (actually, the first application +%D was in foreground colors). %D %D \starttyping %D \starttextcolor[red] @@ -1292,8 +1277,8 @@ %D \macros %D {colorvalue, grayvalue} %D -%D We can typeset the color components using \type{\colorvalue} and -%D \type{\grayvalue}. The commands: +%D We can typeset the color components using \type {\colorvalue} and \type +%D {\grayvalue}. The commands: %D %D \startbuffer %D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf @@ -1370,8 +1355,8 @@ %D \macros %D {forcecolorhack} %D -%D We can out this in front of (for instance) a special and so force color -%D to be applied (only glyphs, rules and leaders are handled). +%D We can out this in front of (for instance) a special and so force color to be +%D applied (only glyphs, rules and leaders are handled). %D %D \startbuffer %D \framed diff --git a/tex/context/base/mkiv/colo-ini.mkxl b/tex/context/base/mkiv/colo-ini.mkxl new file mode 100644 index 000000000..53d45f943 --- /dev/null +++ b/tex/context/base/mkiv/colo-ini.mkxl @@ -0,0 +1,1399 @@ +%D \module +%D [ file=colo-ini, +%D version=2007.08.08, +%D title=\CONTEXT\ Color Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D We need to clean this up further but first we have to make sure that mkiv +%D code works ok. + +\writestatus{loading}{ConTeXt Color Macros / Initialization} + +%D Todo: move color space in color attribute (last two bits) + +%D This module implements color. Since \MKII\ and \MKIV\ use a completely +%D different approach, this module only implements a few generic mechanisms. + +\installcorenamespace{color} +\installcorenamespace{colorattribute} +\installcorenamespace{transparencyattribute} +\installcorenamespace{colorsetter} +\installcorenamespace{transparencysetter} +\installcorenamespace{colorpaletspecification} +\installcorenamespace{colorpalet} +\installcorenamespace{colorstack} +\installcorenamespace{colorconversions} +\installcorenamespace{colornumber} + +\registerctxluafile{colo-ini}{} +\registerctxluafile{colo-icc}{} + +\unprotect + +%D In \MKIV\ we have independent color, colorspace and transparency but I'm still +%D not sure if I keep it that way as it's probably more efficient to combine them +%D (less attributes and finalizing). If it becomes a bottleneck we can set up a more +%D complex system with one shared attribute for colorspace, color and transparency. +%D +%D When typesetting for paper, we prefer using the \CMYK\ color space, but for +%D on||screen viewing we prefer \RGB\ (the previous implementation supported only +%D this scheme). Independant of such specifications, we support some automatic +%D conversions: +%D +%D \startitemize[packed] +%D \item convert all colors to \RGB +%D \item convert all colors to \CMYK +%D \item convert all colors to gray scales +%D \stopitemize +%D +%D These options are communicated by means of: + +\newconditional\c_colo_rgb_supported +\newconditional\c_colo_cmyk_supported +\newconditional\c_colo_spot_supported % backend driven +\newconditional\c_colo_convert_gray \settrue\c_colo_convert_gray +\newconditional\c_colo_enabled +\newconditional\c_colo_expanded + +\let\m_colo_weight_gray\v!yes + +\let\currentcolormodel \empty +\let\currentcolorname \empty +\let\currentcolorpalet \empty +\let\currentcolorprefix\empty % \currentcolorpalet: + +%D \macros +%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor, +%D definetransparency} +%D +%D \starttyping +%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m +%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m +%D +%D \definespotcolor [blue-100] [blue] [p=1] +%D \definespotcolor [yellow-100] [yellow] [p=1] +%D +%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1] +%D +%D \defineprocesscolor[myred][r=.5] +%D \defineprocesscolor[myredish][red][a=1,t=.5] +%D +%D \blackrule[color=myred,width=\hsize,height=1cm] \par +%D \blackrule[color=myredish,width=\hsize,height=1cm] +%D +%D \useexternalfigure[demofig][mill.png][object=no] +%D +%D \startcombination[4*1] +%D {\externalfigure[demofig]} {no color} +%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone} +%D {\externalfigure[demofig][color=blue-100]} {spot color} +%D {\externalfigure[demofig][color=yellow-100]} {spot color} +%D \stopcombination +%D \stoptyping + +\unexpanded\def\definecolor {\dodoubleargument\colo_basics_define} +\unexpanded\def\defineglobalcolor {\dodoubleargument\colo_basics_define_global} +\unexpanded\def\defineprocesscolor {\dotripleargument\colo_basics_define_process} +\unexpanded\def\definenamedcolor {\dodoubleargument\colo_basics_define_named} +\unexpanded\def\definespotcolor {\dotripleargument\colo_basics_define_spot} +\unexpanded\def\definemultitonecolor {\doquadrupleempty\colo_basics_define_multitone} +\unexpanded\def\definetransparency {\dodoubleargument\colo_basics_define_transpancy} +\unexpanded\def\defineglobaltransparency{\dodoubleargument\colo_basics_define_transpancy_global} + +%D \macros +%D {startcolor,stopcolor,color,graycolor} +%D +%D The local and global commands are here just for compatibility with \MKII. +%D +%D \showsetup{startcolor} +%D +%D The simple color commands are: +%D +%D \showsetup{color} +%D \showsetup{graycolor} + +%D We expect sane behaviour in \MKIV\ so we don't used grouped command any +%D longer. + +% \testfeatureonce{100000}{\color[red]{}} % 1.046 => 0.541 + +\let\g_color\empty +\let\g_style\empty + +\unexpanded\def\switchtocolor[#1]{\begincsname#1\endcsname} + +% transparency + +\unexpanded\def\transparent[#1]% + {\bgroup + \edef\currenttransparencyname{#1}% + % the \relax catches a non existent csname + \ifx\currenttransparencyname\v!reset + \attribute\transparencyattribute\attributeunsetvalue + \else + \begincsname\??transparencysetter\currenttransparencyname\endcsname\relax + \fi + \let\nexttoken} + +\unexpanded\def\starttransparent[#1]%$ + {\begingroup + \edef\currenttransparencyname{#1}% + \ifx\currenttransparencyname\v!reset + \attribute\transparencyattribute\attributeunsetvalue + \else + \begincsname\??transparencysetter\currenttransparencyname\endcsname\relax + \fi} + +\unexpanded\def\stoptransparent + {\endgroup} + +% color + +\unexpanded\def\coloronly[#1]% + {\bgroup + \edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop_only + \else + \colo_helpers_activate_yes_only + \fi + \let\nexttoken} + +\unexpanded\def\startcoloronly[#1]%$ + {\begingroup + \edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop_only + \else + \colo_helpers_activate_yes_only + \fi} + +\unexpanded\def\stopcoloronly + {\endgroup} + +% color + transparency + +\unexpanded\def\color[#1]% + {\bgroup + \edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop + \else + \colo_helpers_activate_yes + \fi + \let\nexttoken} + +\unexpanded\def\graycolor[#1]% + {\bgroup + \colo_helpers_set_model\s!gray\colo_helpers_activate{#1}% + \let\nexttoken} + +\unexpanded\def\startcolor[#1]%$ + {\begingroup + \edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop + \else + \colo_helpers_activate_yes + \fi} + +\unexpanded\def\stopcolor + {\endgroup} + +\unexpanded\def\colored[#1]% + {\bgroup + \colo_basics_defined_and_activated{#1}% + \let\nexttoken} + +\unexpanded\def\fastcolored[#1]#2% + {\begingroup % is this command still needed? + \colo_basics_defined_and_activated{#1}% + #2% + \endgroup} + +\unexpanded\def\directcolored[#1]% + {\colo_basics_defined_and_activated{#1}} + +\unexpanded\def\fastcolor [#1]#2% + {\begingroup % is this command still needed? + \edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop + \else + \colo_helpers_activate_yes + \fi + #2% + \endgroup} + +\unexpanded\def\directcolor[#1]% + {\edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \colo_helpers_activate_nop + \else + \colo_helpers_activate_yes + \fi} + +%D The following command is obsolete: + +\unexpanded\def\startcolorpage {\startcolor[\ifx\maintextcolor\empty\defaulttextcolor\else\maintextcolor\fi]} +\unexpanded\def\stopcolorpage {\stopcolor} + +\unexpanded\def\getcolorattributevalue#1#2% obsolete, use \thecolorattribute instead ... + {\begingroup + \colo_helpers_activate{#1}% + \normalexpanded{\endgroup\edef\noexpand#2% + {\ifnum\attribute\colorattribute=\attributeunsetvalue\else\number\attribute\colorattribute\fi}}} + +\let\grey\graycolor % these macros are only used in tracing + +%D \macros +%D {startcurrentcolor,stopcurrentcolor} + +\unexpanded\def\startcurrentcolor{\startcolor[\outercolorname]} +\unexpanded\def\stopcurrentcolor {\stopcolor} + +%D \macros +%D {setupcolor} +%D +%D Color definitions can be grouped in files with the name: +%D +%D \starttyping +%D colo-imp-tag.tex +%D \stoptyping +%D +%D Loading such a file is done by: +%D +%D \showsetup{usecolors} +%D +%D Some default colors are specified in \type {colo-imp-rgb}, which is loaded into +%D the format by default. +%D +%D Some demo palets and groups are defined in \type {colo-imp-dem} which can be +%D loaded with: +%D +%D \starttyping +%D \usecolors[dem] +%D \stoptyping + +\unexpanded\def\startcolorset[#1]{\clf_startcolorset{#1}} +\unexpanded\def\stopcolorset {\clf_stopcolorset} +\unexpanded\def\usecolors [#1]{\clf_usecolors{#1}} + +\let\setupcolor\usecolors + +\installsetuponlycommandhandler \??color {colors} + +\let\colo_helpers_show_message\gobblethreearguments + +% \newtoks\everysetupcolors + +\let\v_colo_freeze_state\s!false + +\setvalue{\??colorconversions\v!yes}% + {\settrue \c_colo_convert_gray} + +\setvalue{\??colorconversions\v!always}% + {\settrue \c_colo_convert_gray + \setfalse\c_colo_rgb_supported + \setfalse\c_colo_cmyk_supported} + +\appendtoks + % + \doifelse{\directcolorsparameter\c!spot }\v!yes \settrue \setfalse\c_colo_spot_supported + \doifelse{\directcolorsparameter\c!expansion}\v!yes \settrue \setfalse\c_colo_expanded + \doifelse{\directcolorsparameter\c!rgb }\v!yes \settrue \setfalse\c_colo_rgb_supported + \doifelse{\directcolorsparameter\c!cmyk }\v!yes \settrue \setfalse\c_colo_cmyk_supported + \doifelse{\directcolorsparameter\c!state }\v!start\settrue \setfalse\c_colo_enabled + % + \edef\m_colo_weight_gray{\directcolorsparameter\c!factor}% + % + \ifconditional\c_colo_expanded + \let\v_colo_freeze_state\s!true + \else + \let\v_colo_freeze_state\s!false + \fi + % + \setfalse\c_colo_convert_gray + \begincsname\??colorconversions\directcolorsparameter\c!conversion\endcsname + % too often: + \ifconditional\c_colo_rgb_supported \colo_helpers_show_message\m!colors{10}\v!rgb \fi + \ifconditional\c_colo_cmyk_supported\colo_helpers_show_message\m!colors{10}\v!cmyk\fi + \colo_helpers_set_current_model + \ifproductionrun + \edef\p_pagecolormodel{\directcolorsparameter\c!pagecolormodel}% + \clf_setpagecolormodel{\ifx\p_pagecolormodel\v!auto\currentcolormodel\else\p_pagecolormodel\fi}% + \fi +\to \everysetupcolors + +\appendtoks + \setupcolors[\c!state=\v!start]% + \clf_enablecolor % this can as well happen when + \clf_enabletransparency % the handler is defined in lua + \let\colo_helpers_show_message\showmessage +\to \everyjob + +%D We provide stacking independent of grouping. + +\newcount\c_colo_nesting + +\unexpanded\def\pushcolor[#1]% + {\global\advance\c_colo_nesting\plusone + \expandafter\edef\csname\??colorstack\number\c_colo_nesting\endcsname + {\attribute\colormodelattribute \the\attribute\colormodelattribute + \attribute\colorattribute \the\attribute\colorattribute + \attribute\transparencyattribute\the\attribute\transparencyattribute + \relax}% stack + \colo_helpers_activate{#1}} + +\unexpanded\def\popcolor + {\csname\??colorstack\number\c_colo_nesting\endcsname + \global\advance\c_colo_nesting\minusone} + +% a simple one: assumes grouping + +\newcount\c_colo_saved_attribute_color +\newcount\c_colo_saved_attribute_transparency + +\unexpanded\def\savecolor + {\c_colo_saved_attribute_color \attribute\colorattribute + \c_colo_saved_attribute_transparency\attribute\transparencyattribute} + +\unexpanded\def\restorecolor + {\attribute\colorattribute \c_colo_saved_attribute_color + \attribute\transparencyattribute\c_colo_saved_attribute_transparency} + +%D In this documentation we will not go into too much details on palets. Curious +%D users can find more information on this topic in \from[use of color]. +%D +%D At the moment we implemented color in \CONTEXT\ color printing was not yet on the +%D desktop. In spite of this lack our graphics designer made colorfull +%D illustrations. When printed on a black and white printer, distinctive colors can +%D come out equally gray. We therefore decided to use only colors that were +%D distinctive in colors as well as in black and white print. +%D +%D Although none of the graphic packages we used supported logical colors and global +%D color redefition, we build this support into \CONTEXT. This enabled us to +%D experiment and also prepared us for the future. + +%D \macros +%D {definepalet} +%D +%D Colors are grouped in palets. The colors in such a palet can have colorful names, +%D but best is to use names that specify their use, like {\em important} or {\em +%D danger}. As a sort of example \CONTEXT\ has some palets predefined, +%D like:\footnote{At the time I wrote the palet support, I was reading 'A hort +%D history of time' of S.~Hawkins, so that's why we stuck to quarks.} +%D +%D \starttyping +%D \definepalet +%D [alfa] +%D [ top=rood:7, +%D bottom=groen:6, +%D up=blauw:5, +%D down=cyaan:4, +%D strange=magenta:3, +%D charm=geel:2] +%D \stoptyping +%D +%D It's formal definition is: +%D +%D \showsetup{definepalet} +%D +%D Visualized, such a palet looks like: +%D +%D \startbuffer[palet] +%D \showpalet [alfa] [horizontal,name,number,value] +%D \stopbuffer +%D +%D \startlinecorrection +%D \getbuffer[palet] +%D \stoplinecorrection +%D +%D This bar shows both the color and gray alternatives of the palet components (not +%D visible in black and white print). +%D +%D When needed, one can copy a palet by saying: +%D +%D \starttyping +%D \definepalet [TEXcolorpretty] [colorpretty] +%D \stoptyping +%D +%D This saves us some typing in for instance the modules that deal with pretty +%D verbatim typesetting. + +\installcorenamespace{paletlist} +\installcorenamespace{paletsize} + +\let\m_colo_palet\relax +\let\c_colo_palet\relax + +\def\colo_palet_allocate#1% + {\expandafter\let \csname\??paletlist#1\endcsname\empty + \expandafter\newcount\csname\??paletsize#1\endcsname} + +\def\colo_palet_prepare#1% + {\edef\colo_palet_name{#1}% + \ifcsname\??paletlist\colo_palet_name\endcsname + \csname\??paletsize\colo_palet_name\endcsname\zerocount + \else + \colo_palet_allocate\colo_palet_name + \fi + \edef\m_colo_palet{\begincsname\??paletlist\colo_palet_name\endcsname}% + \expandafter\let\expandafter\c_colo_palet\csname\??paletsize\colo_palet_name\endcsname} + +\def\colo_palet_extend#1% + {\addtocommalist{#1}\m_colo_palet + \expandafter\let\csname\??paletlist\colo_palet_name\endcsname\m_colo_palet + \advance\c_colo_palet\plusone} + +\unexpanded\def\doifelsecolorpalet#1% + {\ifcsname\??paletlist#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\paletlist\empty +\let\paletsize\!!zerocount + +\unexpanded\def\getpaletlist[#1]% + {\edef\paletlist{\begincsname\??paletlist#1\endcsname}} + +\unexpanded\def\getpaletsize[#1]% + {\ifcsname\??paletsize#1\endcsname + \edef\paletsize{\the\lastnamedcs}% + \else + \let\paletsize\!!zerocount + \fi} + +\unexpanded\def\definepalet + {\dotripleempty\colo_palets_define} + +\def\colo_palets_define + {\ifthirdargument + \expandafter\colo_palets_define_b + \else + \expandafter\colo_palets_define_a + \fi} + +\unexpanded\def\colo_palets_define_a[#1][#2][#3]% + {\colo_palet_prepare{#1}% + \ifcondition\validassignment{#2}% + \setevalue{\??colorpaletspecification#1}{#2}% + \processcommalist[#2]{\colo_palets_define_one{#1}}% + \orelse\ifcsname\??colorpaletspecification#2\endcsname + \normalexpanded{\colo_palets_define[#1][\lastnamedcs]}% + \fi} + +\unexpanded\def\colo_palets_define_b[#1][#2][#3]% + {\colo_palet_prepare{#1}% + \setevalue{\??colorpaletspecification#1}{#2}% + \colo_palet_extend{#2}% + \colo_palets_define_assign{#1}{#2}{#3}} + +\def\colo_palets_define_one#1#2% get rid of { } + {\ifcondition\validassignment{#2}% catch empty entries + \colo_palets_define_two{#1}[#2]% + \else + \colo_palets_define_three{#1}{#2}% + \fi} + +\def\colo_palets_define_two#1[#2=#3]% + {\colo_palet_extend{#2}% + \colo_palets_define_set{#1}{#2}{#3}}% + +\def\colo_palets_define_three#1#2% + {\ifcsname\??colorpaletspecification#2\endcsname + \processcommacommand[\lastnamedcs]{\colo_palets_define_one{#1}}% + \fi} + +%D Instead of refering to colors, one can also directly specify a color: +%D +%D \starttyping +%D \definepalet[test][xx=green] +%D \definepalet[test][xx={y=.4}] +%D \stoptyping + +%D \macros +%D {setuppalet} +%D +%D Colors are taken from the current palet, if defined. Setting the current palet is +%D done by: +%D +%D \showsetup{setuppalet} + +\newtoks\everysetuppalet + +\unexpanded\def\setuppalet + {\dosingleempty\colo_palets_setup} + +% \newtoks\t_colo_prefix % used in mp interface + +\def\colo_palets_setup[#1]% + {\edef\currentcolorpalet{#1}% + \ifx\currentcolorpalet\empty + % seems to be a reset + \let\currentcolorprefix\empty + %\t_colo_prefix\emptytoks + \orelse\ifcsname\??paletlist\currentcolorpalet\endcsname + \edef\currentcolorprefix{#1:}% + %\t_colo_prefix\expandafter{\currentcolorprefix}% + \else + \colo_helpers_show_message\m!colors7\currentcolorpalet + \let\currentcolorpalet\empty + \let\currentcolorprefix\empty + %\t_colo_prefix\emptytoks + \fi + \the\everysetuppalet + \colo_helpers_initialize_maintextcolor} + +%D \macros +%D {showpalet} +%D +%D The previous visualization was typeset with: +%D +%D \typebuffer[palet] +%D +%D This commands is defined as: +%D +%D \showsetup{showpalet} + +\fetchruntimecommand \showpalet \f!colo_run + +%D \macros +%D {showcolorcomponents} +%D +%D \starttyping +%D \showcolorcomponents[color-1,color-2] +%D \stoptyping + +\fetchruntimecommand \showcolorcomponents \f!colo_run + +%D \macros +%D {comparepalet} +%D +%D There are some more testing macros available: +%D +%D \startbuffer +%D \comparepalet [alfa] +%D \stopbuffer +%D +%D \typebuffer +%D +%D shows the palet colors against a background: +%D +%D \startlinecorrection +%D \getbuffer +%D \stoplinecorrection +%D +%D The formal definition is: +%D +%D \showsetup{comparepalet} + +\fetchruntimecommand \comparepalet \f!colo_run + +%D \macros +%D {showcolor} +%D +%D But let's not forget that we also have the more traditional non||related colors. +%D These show up after: +%D +%D \starttyping +%D \showcolor [name] +%D \stoptyping +%D +%D Where \type{name} for instance can be \type{rgb}. +%D +%D \showsetup{showcolor} + +\fetchruntimecommand \showcolor \f!colo_run + +%D It would make sense to put the following code in \type {colo-mps}, but it it +%D rather low level. + +%D \macros +%D {negatecolorcomponent,negatedcolorcomponent} +%D +%D These speak for themselves. See \type {colo-ext} for usage. + +\unexpanded\def\negatecolorcomponent#1% #1 = \macro + {\edef#1{\clf_negatecolorcomponent{#1}}} + +\def\negatedcolorcomponent#1% + {\clf_negatecolorcomponent{#1}} + +%D \macros +%D {MPcolor} +%D +%D A very special macro is \type{\MPcolor}. This one can be used to pass a \CONTEXT\ +%D color to \METAPOST. +%D +%D \starttyping +%D \MPcolor{my own red} +%D \stoptyping +%D +%D This macro returns \METAPOST\ code that represents the +%D color. +%D +%D For the moment we keep the next downward compatibility switch, i.e.\ expanded +%D colors. However, predefined colors and palets are no longer expanded (which is +%D what I wanted in the first place). +%D +%D In \MKIV\ we don't support color separation as we might now assume that printing +%D houses have the right programs to do it themselves. If it's ever needed in \MKIV\ +%D It is relatively easy to support it in the backend code. + +% todo: palets in definecolor +% todo: {\red xx} vs \red{xx} + +% \def\mptexcolor#1{"\dogetattributeid\s!color \somecolorattribute{#1} A"} +% +% \startMPpage +% fill fullcircle scaled 10cm ; +% fill fullcircle scaled 5cm withprescript \mptexcolor{red} withpostscript \mptexcolor{black} ; +% fill fullcircle scaled 3cm ; +% draw btex test etex withprescript \mptexcolor{blue} ; +% \stopMPpage + +\unexpanded\def\setcolormodel[#1]% % beware, \setupcolors will overload this, so this one is + {\colo_helpers_set_model{#1}} % only for local usage + +\def\colo_helpers_set_model#1% direct + {\edef\currentcolormodel{#1}% + \clf_setcolormodel{\currentcolormodel}{\m_colo_weight_gray}} % sets attribute at lua end + +\colo_helpers_set_model\s!all + +\def\colo_helpers_set_current_model + {\ifconditional\c_colo_enabled + \ifconditional\c_colo_rgb_supported + \ifconditional\c_colo_cmyk_supported + \colo_helpers_set_model\s!all + \else + \colo_helpers_set_model\s!rgb + \fi + \else + \ifconditional\c_colo_cmyk_supported + \colo_helpers_set_model\s!cmyk + \else + \ifconditional\c_colo_convert_gray + \colo_helpers_set_model\s!gray + \else + \colo_helpers_set_model\s!none + \fi + \fi + \fi + \else + \ifconditional\c_colo_convert_gray + \colo_helpers_set_model\s!gray + \else + \colo_helpers_set_model\s!none + \fi + \fi} + +%D Currently in mkiv transparency is implemented independent of color. This costs a +%D bit more processing time but gives the possibility to apply transparency +%D independently in the future. Is this useful? If not we may as well combine them +%D again in the future. By coupling we are downward compatible. When we decouple we +%D need to do more tricky housekeeping (e.g. persist color independent +%D transparencies when color bound ones are nil. + +% Since we couple definitions, we could stick to one test. Todo. Same for mpcolor. + +\def\v_colo_dummy_name{c_o_l_o_r} + +\letvalue{\??colorattribute \v_colo_dummy_name}\empty +\letvalue{\??transparencyattribute\v_colo_dummy_name}\empty +\letvalue{\??colorsetter \v_colo_dummy_name}\empty +\letvalue{\??transparencysetter \v_colo_dummy_name}\empty + +\letvalue{\??colorsetter -}\empty % used? +\letvalue{\??transparencysetter-}\empty % used? + +% new: expandable (see tbl) + +\def\colo_helpers_fast_activate + {\ifx\currentcolorprefix\empty + \expandafter\colo_helpers_fast_activate_nop + \else + \expandafter\colo_helpers_fast_activate_yes + \fi} + +\def\colo_helpers_fast_activate_yes#1% + {\ifcsname\??colorsetter\currentcolorprefix#1\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorprefix#1\endcsname + \orelse\ifcsname\??colorsetter#1\endcsname + \lastnamedcs + \begincsname\??transparencysetter#1\endcsname + \fi} + +\def\colo_helpers_fast_activate_nop#1% + {\ifcsname\??colorsetter#1\endcsname + \lastnamedcs + \begincsname\??transparencysetter#1\endcsname + \fi} + +\def\colo_helpers_activate_dummy + {\begincsname\??colorsetter \v_colo_dummy_name\endcsname + \begincsname\??transparencysetter\v_colo_dummy_name\endcsname} + +\let\dofastcoloractivation\colo_helpers_fast_activate + +% so far + +\def\colo_helpers_activate#1% two-step is not that much faster but less tracing + {\edef\currentcolorname{#1}% + \ifx\currentcolorprefix\empty + \expandafter\colo_helpers_activate_nop + \else + \expandafter\colo_helpers_activate_yes + \fi} + +\def\colo_helpers_activate_yes + {\ifcsname\??colorsetter\currentcolorprefix\currentcolorname\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorprefix\currentcolorname\endcsname + \orelse\ifcsname\??colorsetter\currentcolorname\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorname\endcsname + \fi} + +\def\colo_helpers_activate_nop + {\ifcsname\??colorsetter\currentcolorname\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorname\endcsname + \fi} + +\def\colo_helpers_activate_yes_only + {\ifcsname\??colorsetter\currentcolorprefix\currentcolorname\endcsname + \lastnamedcs + \orelse\ifcsname\??colorsetter\currentcolorname\endcsname + \lastnamedcs + \fi} + +\def\colo_helpers_activate_nop_only + {\ifcsname\??colorsetter\currentcolorname\endcsname + \lastnamedcs + \fi} + +\let\dousecolorparameter\colo_helpers_activate + +\unexpanded\def\dousecolorhashparameter#1#2% + {\ifcsname#1#2\endcsname + \expandafter\dousecolorparameter\csname#1#2\endcsname + \fi} + +\unexpanded\def\dousecurrentcolorparameter + {\let\currentcolorname\currentcolorparameter % maybe only when success + \ifcsname\??colorsetter\currentcolorprefix\currentcolorparameter\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorprefix\currentcolorparameter\endcsname + \orelse\ifcsname\??colorsetter\currentcolorparameter\endcsname + \lastnamedcs + \begincsname\??transparencysetter\currentcolorparameter\endcsname + \fi} + +\let\dosetcolorattribute\dousecolorhashparameter % for a while + +\unexpanded\def\deactivatecolor % sort of public but a bad name + {\let\currentcolorname\s!black + \attribute\colorattribute\attributeunsetvalue + \attribute\transparencyattribute\attributeunsetvalue} + +% todo: check if color is overloading a non-color command + +% \let\colo_basics_synchronize\gobbleoneargument % used in mp interface +% \let\colo_basics_inherit \gobbletwoarguments % used in mp interface + +\def\colo_basics_allocate#1% + {\expandafter\newcount\csname\??colornumber#1\endcsname + \clf_synccolorcount{#1}\c_syst_last_allocated_count} + +\def\colo_basics_synchronize#1% + {\ifcsname\??colornumber#1\endcsname\else + \colo_basics_allocate{#1}% + \fi + \clf_synccolor{#1}% + %\csname\??colornumber#1\endcsname\csname\??colorattribute#1\endcsname + \lastnamedcs\csname\??colorattribute#1\endcsname} + +\let\colo_basics_inherit\clf_synccolorclone + +\newcount\c_colo_protection + +\unexpanded\def\startprotectedcolors + {\advance\c_colo_protection\plusone} + +\unexpanded\def\stopprotectedcolors + {\advance\c_colo_protection\minusone} + +\def\colo_basics_define[#1][#2]% + {\edef\m_colo_old{#1}% + \edef\m_colo_new{#2}% + \ifx\m_colo_old\m_colo_new + % maybe a warning + \else + \clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}% + \fi + \fi} + +\def\colo_basics_define_global[#1][#2]% + {\edef\m_colo_old{#1}% + \edef\m_colo_new{#2}% + \ifx\m_colo_old\m_colo_new + % maybe a warning + \else + \clf_defineprocesscolorglobal{#1}{#2}\v_colo_freeze_state\relax + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}% + \fi + \fi} + +\let\colo_basics_define_named\colo_basics_define + +\def\dodefinefastcolor[#1][#2]% still not fast but ok (might change) + {\clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}% + \fi} + +\def\colo_basics_defined_and_activated#1% + {\clf_defineprocesscolordummy{#1}% we could pass dummy here too + \colo_basics_synchronize{\v_colo_dummy_name}% + \colo_helpers_activate_dummy} + +\def\colo_basics_define_process + {\ifthirdargument + \expandafter\colo_basics_define_process_yes + \else + \expandafter\colo_basics_define_process_nop + \fi} + +\def\colo_basics_define_process_yes[#1][#2][#3]% + {\clf_defineprocesscolorlocal{#1}{\processcolorcomponents{#2},#3}\v_colo_freeze_state\relax + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}% + \fi} + +\def\colo_basics_define_process_nop[#1][#2][#3]% + {\clf_defineprocesscolorlocal{#1}{#2}\v_colo_freeze_state\relax + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}% + \fi} + +%D Spotcolors used setxvalue but that messes up currentcolor and probably no global +%D is needed either but they are global at the lua end (true argument) so we keep +%D that if only because spot colors often are a document wide property + +\def\colo_basics_define_spot[#1][#2][#3]% + {\clf_definespotcolorglobal{#1}{#2}{#3}% + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}% + \fi} + +\def\colo_basics_define_multitone[#1][#2][#3][#4]% + {\clf_definemultitonecolorglobal{#1}{#2}{#3}{#4}% + \colo_basics_synchronize{#1}% + \ifcase\c_colo_protection + \unexpanded\setgvalue{#1}{\colo_helpers_activate{#1}}% + \fi} + +%D Transparencies (only): + +\def\colo_basics_define_transpancy[#1][#2]% + {\clf_definetransparency{#1}{#2}} + +\def\colo_basics_define_transpancy_global[#1][#2]% + {\clf_definetransparencyglobal{#1}{#2}} + +% A goodie that replaces the startMPcolor hackery + +% \definecolor[red-t] [r=1,t=0.5,a=1] +% \definecolor[green-t][g=1,t=0.5,a=1] +% +% \defineintermediatecolor[mycolora][0.5,red,green] +% \defineintermediatecolor[mycolorb][0.5,red-t,green-t] +% +% \definecolor[mycolorc][.5(blue,red)] +% \definecolor[mycolord][.5(blue)] +% \definecolor[mycolord][-.5(blue,red)] % complement +% \definecolor[mycolord][-(blue)] % complement +% +% \enabledirectives[colors.pgf] +% \definecolor[mycolorx][magenta!50!yellow] +% +% \starttext +% test {\mycolora OEPS} test +% test {\mycolorb OEPS} test +% test {\mycolorc OEPS} test +% test {\mycolord OEPS} test +% test {\mycolorx OEPS} test +% \stoptext +% +% Beware: if we say: +% +% \definecolor[one][two] +% +% Only color one is actually defined and two is not seen at the \LUA\ end. This +% means that this doesn't work: +% +% \definecolor[ColorA][red] +% \definecolor[ColorB][.5(ColorA)] +% \definecolor[ColorC][.5(ColorB,white)] +% +% But this does work: +% +% \definecolor[ColorA][1.0(red)] +% \definecolor[ColorB][0.5(ColorA)] +% \definecolor[ColorC][0.5(ColorB,white)] +% +% because the fractional definition results in a new definition. + +\unexpanded\def\defineintermediatecolor + {\dotripleempty\colo_basics_define_intermediate} + +\def\colo_basics_define_intermediate[#1][#2][#3]% \dotripleempty adds {} inside [] + {\colo_basics_define_intermediate_indeed[#1][#2][#3]} + +\def\colo_basics_define_intermediate_indeed[#1][#2,#3,#4][#5]% + {\clf_defineintermediatecolor % not global + {#1}% + {#2}% + \rawcolorattribute{#3} % + \rawcolorattribute{#4} % + \rawtransparencyattribute{#3} % + \rawtransparencyattribute{#4} % + {#5}% + \v_colo_freeze_state + \relax + \colo_basics_synchronize{#1}% + \unexpanded\setvalue{#1}{\colo_helpers_activate{#1}}} + +%D Here is a more efficient helper for pgf: +%D +%D \starttyping +%D \startluacode +%D function commands.pgfxcolorspec(ca) -- {}{}{colorspace}{list} +%D local cv = attributes.colors.values[ca] +%D if cv then +%D local model = cv[1] +%D if model == 2 then +%D context("{}{}{gray}{%1.3f}",cv[2]) +%D elseif model == 3 then +%D context("{}{}{rgb}{%1.3f,%1.3f,%1.3f}",cv[3],cv[4],cv[5]) +%D elseif model == 4 then +%D context("{}{}{cmyk}{%1.3f,%1.3f,%1.3f,%1.3f}",cv[6],cv[7],cv[8],cv[9]) +%D else +%D context("{}{}{gray}{%1.3f}",cv[2]) +%D end +%D else +%D context("{}{}{gray}{0}") +%D end +%D end +%D \stopluacode +%D +%D \def\pgfutil@registercolor#1% +%D {\setevalue{\string\color@#1}{\noexpand\xcolor@\ctxcommand{pgfxcolorspec(\thecolorattribute{#1})}}} +%D +%D \definecolor [darkblue] [r=0,g=0,b=0.5] +%D +%D \starttikzpicture +%D \fill [blue] (0,0) circle(1); +%D \fill [darkblue] (0,0) circle(1); +%D \stoptikzpicture +%D \stoptyping +%D +%D \stopmode + +\def\pgf@context@registercolor#1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\zerocount\thecolorattribute{#1}}} +\def\pgf@context@registergray #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plustwo \thecolorattribute{#1}}} +\def\pgf@context@registerrgb #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plusthree\thecolorattribute{#1}}} +\def\pgf@context@registercmyk #1{\setevalue{\string\color@#1}{\noexpand\xcolor@{}{}\clf_pgfxcolorspec\plusfour \thecolorattribute{#1}}} + +%D \starttyping +%D \ifdefined\pgf@context@registercolor +%D \let\pgfutil@registercolor\pgf@context@registercolor +%D \fi +%D \stoptyping + +%D \macros +%D {doifcolorelse, doifcolor} +%D +%D Switching to a color is done by means of the following command. Later on we will +%D explain the use of palets. We define ourselves a color conditional first. + +\def\doifelsecolor#1% + {\ifcsname\??colorattribute\currentcolorprefix#1\endcsname + \expandafter\firstoftwoarguments + \orelse\ifcsname\??colorattribute#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifcolorelse\doifelsecolor + +\def\doifcolor#1% + {\ifcsname\??colorattribute\currentcolorprefix#1\endcsname + \expandafter\firstofoneargument + \orelse\ifcsname\??colorattribute#1\endcsname + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +%D \macros +%D {startregistercolor,stopregistercolor,permitcolormode} +%D +%D If you only want to register a color, the switch \type {\ifpermitcolormode} can +%D be used. That way the nested colors know where to go back to. +%D +%D We use these macros for implementing text colors (actually, the first application +%D was in foreground colors). +%D +%D \starttyping +%D \starttextcolor[red] +%D \dorecurse{10}{\input tufte \color[green]{oeps} \par} +%D \stoptextcolor +%D \stoptyping +%D +%D This is more efficient than the alternative: +%D +%D \starttyping +%D \setupbackgrounds[text][foregroundcolor=red] +%D \startregistercolor[red] +%D \dorecurse{10}{\input tufte \color[green]{oeps} \par} +%D \stopregistercolor +%D \stoptyping + +\let\maintextcolor \empty +\def\defaulttextcolor {black} +\def\s!themaintextcolor{themaintextcolor} + +\unexpanded\def\inheritmaintextcolor + {\ifx\maintextcolor\empty\else\colo_helpers_activate\maintextcolor\fi} + +\unexpanded\def\onlyinheritmaintextcolor + {\ifx\maintextcolor\empty + \deactivatecolor + \else + \colo_helpers_activate\maintextcolor + \fi} + +\appendtoks + \deactivatecolor % public? + \inheritmaintextcolor +\to \everybeforeoutput + +\def\colo_helpers_switch_to_maintextcolor#1% + {\let\maintextcolor\s!themaintextcolor + \definecolor[\maintextcolor][#1]% can be fast one + \colo_helpers_activate\maintextcolor + \clf_registermaintextcolor\thecolorattribute\maintextcolor\relax} + +\unexpanded\def\starttextcolor[#1]% + {\doifsomething{#1} + {\colo_helpers_switch_to_maintextcolor{#1}}} + +\let\stoptextcolor\relax + +\let\p_colo_textcolor\empty + +\def\colo_helpers_initialize_maintextcolor + {\edef\p_colo_textcolor{\directcolorsparameter\c!textcolor}% + \ifx\p_colo_textcolor\empty + \colo_helpers_switch_to_maintextcolor\defaulttextcolor + \else + \colo_helpers_switch_to_maintextcolor\p_colo_textcolor + \fi} + +\appendtoks \colo_helpers_initialize_maintextcolor \to \everyjob +\appendtoks \colo_helpers_initialize_maintextcolor \to \everysetupcolors + +\letvalue{\??colorsetter }\empty \letvalue{\??colorattribute }\!!zerocount +\letvalue{\??transparencysetter}\empty \letvalue{\??transparencyattribute}\!!zerocount + +\def\colo_helpers_inherited_direct_cs#1{\ifcsname\??colorsetter #1\endcsname\lastnamedcs\fi} +\def\colo_helpers_inherited_direct_ca#1{\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\!!zerocount\fi} +\def\colo_helpers_inherited_direct_ts#1{\ifcsname\??transparencysetter #1\endcsname\lastnamedcs\fi} +\def\colo_helpers_inherited_direct_ta#1{\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\!!zerocount\fi} + +% %def\colo_helpers_inherited_palet_cs#1#2{\csname\??colorsetter \ifcsname\??colorsetter \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname} +% %def\colo_helpers_inherited_palet_ca#1#2{\csname\??colorattribute \ifcsname\??colorattribute \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname} +% %def\colo_helpers_inherited_palet_ts#1#2{\csname\??transparencysetter \ifcsname\??transparencysetter \??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname} +% %def\colo_helpers_inherited_palet_ta#1#2{\csname\??transparencyattribute\ifcsname\??transparencyattribute\??colorpalet#1:#2\endcsname\??colorpalet#1:#2\fi\endcsname} +% +% \def\colo_helpers_inherited_palet_cs#1#2{\ifcsname\??colorsetter \??colorpalet#1:#2\endcsname\lastnamedcs\fi} +% \def\colo_helpers_inherited_palet_ca#1#2{\ifcsname\??colorattribute \??colorpalet#1:#2\endcsname\lastnamedcs\else\!!zerocount\fi} +% \def\colo_helpers_inherited_palet_ts#1#2{\ifcsname\??transparencysetter \??colorpalet#1:#2\endcsname\lastnamedcs} +% \def\colo_helpers_inherited_palet_ta#1#2{\ifcsname\??transparencyattribute\??colorpalet#1:#2\endcsname\lastnamedcs\else\!!zerocount\fi} + +\let\colo_helpers_set_value\setvalue + +\appendtoks + \ifconditional\c_colo_expanded + \let\colo_helpers_set_value\setevalue + \else + \let\colo_helpers_set_value\setvalue + \fi +\to \everysetupcolors + +\def\colo_palets_define_set#1#2#3% + {\ifcondition\validassignment{#3}% \definepalet[test][xx={y=.4}] + \expandafter\colo_palets_define_assign + \orelse\ifcsname\??colorsetter#3\endcsname + % \definepalet[test][xx=green] + \expandafter\colo_palets_define_inherit + \else + % not entered when making format + \expandafter\colo_palets_define_undefine + \fi + {#1}{#2}{#3}} + +\def\colo_palets_define_inherit#1#2#3% + {\colo_basics_inherit{#1:#2}{#3}% + \colo_helpers_set_value{\??colorsetter #1:#2}{\colo_helpers_inherited_direct_cs{#3}}% + \colo_helpers_set_value{\??colorattribute #1:#2}{\colo_helpers_inherited_direct_ca{#3}}% + \colo_helpers_set_value{\??transparencysetter #1:#2}{\colo_helpers_inherited_direct_ts{#3}}% + \colo_helpers_set_value{\??transparencyattribute#1:#2}{\colo_helpers_inherited_direct_ta{#3}}} + +\def\colo_palets_define_undefine#1#2#3% + {\localundefine{\??colorsetter #1:#2}% + \localundefine{\??colorattribute #1:#2}% + \localundefine{\??transparencysetter #1:#2}% + \localundefine{\??transparencyattribute#1:#2}} + +\def\colo_palets_define_assign#1#2#3% + {\definecolor[\??colorpalet#1:#2][#3]% + \colo_helpers_set_value{\??colorsetter #1:#2}{\colo_helpers_inherited_direct_cs{\??colorpalet#1:#2}}% + \colo_helpers_set_value{\??colorattribute #1:#2}{\colo_helpers_inherited_direct_ca{\??colorpalet#1:#2}}% + \colo_helpers_set_value{\??transparencysetter #1:#2}{\colo_helpers_inherited_direct_ts{\??colorpalet#1:#2}}% + \colo_helpers_set_value{\??transparencyattribute#1:#2}{\colo_helpers_inherited_direct_ta{\??colorpalet#1:#2}}} + +\setvalue{\??colorattribute currentcolor}{\the\attribute\colorattribute} % for mpcolor +\setvalue{\??transparencyattribute currentcolor}{\the\attribute\transparencyattribute} % for mpcolor + +%def\colo_helpers_inherited_current_ca#1{\csname\??colorattribute \ifcsname\??colorattribute \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorattribute #1\endcsname#1\fi\fi\endcsname} +%def\colo_helpers_inherited_current_cs#1{\csname\??colorsetter \ifcsname\??colorsetter \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorsetter #1\endcsname#1\fi\fi\endcsname} +%def\colo_helpers_inherited_current_ta#1{\csname\??transparencyattribute\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencyattribute#1\endcsname#1\fi\fi\endcsname} +%def\colo_helpers_inherited_current_ts#1{\csname\??transparencysetter \ifcsname\??transparencysetter \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencysetter #1\endcsname#1\fi\fi\endcsname} + +\def\colo_helpers_inherited_current_ca#1{\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\!!zerocount\fi\fi} +\def\colo_helpers_inherited_current_cs#1{\ifcsname\??colorsetter \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??colorsetter #1\endcsname\lastnamedcs\else\fi\fi} +\def\colo_helpers_inherited_current_ta#1{\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\!!zerocount\fi\fi} +\def\colo_helpers_inherited_current_ts#1{\ifcsname\??transparencysetter \currentcolorprefix#1\endcsname\lastnamedcs\else\ifcsname\??transparencysetter #1\endcsname\lastnamedcs\else\fi\fi} + +%D Low level defs: + +\unexpanded\def\colordefalc#1#2{\setevalue{\??colorattribute #1}{#2}\setvalue {\??colorsetter #1}{\attribute\colorattribute #2 }} +\unexpanded\def\colordefagc#1#2{\setxvalue{\??colorattribute #1}{#2}\setgvalue{\??colorsetter #1}{\attribute\colorattribute #2 }} % was not g +\unexpanded\def\colordefalt#1#2{\setevalue{\??transparencyattribute#1}{#2}\setvalue {\??transparencysetter#1}{\attribute\transparencyattribute#2 }} +\unexpanded\def\colordefagt#1#2{\setxvalue{\??transparencyattribute#1}{#2}\setgvalue{\??transparencysetter#1}{\attribute\transparencyattribute#2 }} + +\unexpanded\def\colordefflc#1#2{\setvalue {\??colorattribute #1}{\colo_helpers_inherited_current_ca{#2}}\setvalue {\??colorsetter #1}{\colo_helpers_inherited_current_cs{#2}}} +\unexpanded\def\colordeffgc#1#2{\setgvalue{\??colorattribute #1}{\colo_helpers_inherited_current_ca{#2}}\setvalue {\??colorsetter #1}{\colo_helpers_inherited_current_cs{#2}}} +\unexpanded\def\colordefflt#1#2{\setvalue {\??transparencyattribute#1}{\colo_helpers_inherited_current_ta{#2}}\setvalue {\??transparencysetter#1}{\colo_helpers_inherited_current_ts{#2}}} +\unexpanded\def\colordeffgt#1#2{\setgvalue{\??transparencyattribute#1}{\colo_helpers_inherited_current_ta{#2}}\setgvalue{\??transparencysetter#1}{\colo_helpers_inherited_current_ts{#2}}} + +\unexpanded\def\colordefrlc #1{\localundefine {\??colorattribute #1}\localundefine {\??colorsetter #1}} +\unexpanded\def\colordefrgc #1{\globalundefine{\??colorattribute #1}\globalundefine{\??colorsetter #1}} +\unexpanded\def\colordefrlt #1{\localundefine {\??transparencyattribute#1}\localundefine {\??transparencysetter#1}} +\unexpanded\def\colordefrgt #1{\globalundefine{\??transparencyattribute#1}\globalundefine{\??transparencysetter#1}} + +%D \macros +%D {colorvalue, grayvalue} +%D +%D We can typeset the color components using \type {\colorvalue} and \type +%D {\grayvalue}. The commands: +%D +%D \startbuffer +%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf +%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed} +%D \stopbuffer +%D +%D \typebuffer +%D +%D show us: +%D +%D \startexample +%D \getbuffer +%D \stopexample + +\let\currentcolorname\s!black % todo +\let\outercolorname \s!black % todo + +\let\colorformatseparator\space + +\def\MPcolor#1% + {\clf_mpcolor + \attribute\colormodelattribute + \colo_helpers_inherited_current_ca{#1} % + \colo_helpers_inherited_current_ta{#1} } + +\def\MPcoloronly#1% + {\clf_mpcolor + \attribute\colormodelattribute + \colo_helpers_inherited_current_ca{#1} % + \zerocount} + +\def\MPtransparency#1% + {\clf_mpcolor + \zerocount + \zerocount + \colo_helpers_inherited_current_ta{#1} } + +\def\MPoptions#1% + {\clf_mpoptions + \attribute\colormodelattribute + \colo_helpers_inherited_current_ca{#1} % + \colo_helpers_inherited_current_ta{#1} } + +\def\thecolormodelattribute {\the\attribute\colormodelattribute} + +%def\thecolorattribute #1{\number\csname\??colorattribute \ifcsname\??colorattribute \currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??colorattribute #1\endcsname#1\fi\fi\endcsname} +%def\thetransparencyattribute#1{\number\csname\??transparencyattribute\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\currentcolorprefix#1\else\ifcsname\??transparencyattribute#1\endcsname#1\fi\fi\endcsname} + +\def\rawcolorattribute #1{\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\zerocount\fi} +\def\rawtransparencyattribute#1{\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\zerocount\fi} + +\def\thecolorattribute #1{\number\ifcsname\??colorattribute \currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??colorattribute #1\endcsname\lastnamedcs\else\zerocount\fi} +\def\thetransparencyattribute#1{\number\ifcsname\??transparencyattribute\currentcolorprefix#1\endcsname\lastnamedcs\orelse\ifcsname\??transparencyattribute#1\endcsname\lastnamedcs\else\zerocount\fi} +\def\internalspotcolorname #1{\clf_spotcolorname \thecolorattribute{#1} } +\def\internalspotcolorparent #1{\clf_spotcolorparent\thecolorattribute{#1} } +\def\internalspotcolorsize #1{\clf_spotcolorvalue \thecolorattribute{#1} } + +\def\colorcomponents #1{\clf_colorcomponents \thecolorattribute {#1} } +\def\transparencycomponents #1{\clf_transparencycomponents\thetransparencyattribute{#1} } +\def\processcolorcomponents #1{\clf_processcolorcomponents\thecolorattribute {#1} } + +\def\colorvalue #1{\clf_formatcolor\thecolorattribute{#1}{\colorformatseparator}} +\def\grayvalue #1{\clf_formatgray \thecolorattribute{#1}{\colorformatseparator}} + +\def\doifelseblack #1{\clf_doifelseblack\thecolorattribute{#1} } +\def\doifelsedrawingblack {\clf_doifelsedrawingblack} + +\let\doifblackelse \doifelseblack +\let\doifdrawingblackelse \doifelsedrawingblack + +\let\doifblackelse \doifelseblack +\let\doifdrawingblackelse\doifelsedrawingblack + +%D \macros +%D {forcecolorhack} +%D +%D We can out this in front of (for instance) a special and so force color to be +%D applied (only glyphs, rules and leaders are handled). +%D +%D \startbuffer +%D \framed +%D [background=color,backgroundcolor=yellow,framecolor=red,corner=round] +%D {test} +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +% ignores in attribute handler +% +% \def\forcecolorhack{\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint} + +% \normal added else fails in metafun manual (leaders do a hard scan) + +\unexpanded\def\forcecolorhack{\leaders\hrule\hskip\zeropoint\relax} % relax is needed ! + +%D We default to the colors defined in \type {colo-imp-rgb} and +%D support both \RGB\ and \CMYK\ output. Transparencies are defined +%D here: + +\definecolor[black][s=0] +\definecolor[white][s=1] + +\definetransparency [none] [0] +\definetransparency [normal] [1] +\definetransparency [multiply] [2] +\definetransparency [screen] [3] +\definetransparency [overlay] [4] +\definetransparency [softlight] [5] +\definetransparency [hardlight] [6] +\definetransparency [colordodge] [7] +\definetransparency [colorburn] [8] +\definetransparency [darken] [9] +\definetransparency [lighten] [10] +\definetransparency [difference] [11] +\definetransparency [exclusion] [12] +\definetransparency [hue] [13] +\definetransparency [saturation] [14] +\definetransparency [color] [15] +\definetransparency [luminosity] [16] + +%D Some common ones: + +\definecolor[trace:0][s=.4] +\definecolor[trace:1][r=.6] +\definecolor[trace:2][g=.6] +\definecolor[trace:3][b=.6] +\definecolor[trace:4][r=.6,g=.6] +\definecolor[trace:5][r=.6,b=.6] +\definecolor[trace:6][g=.6,b=.6] +\definecolor[trace:7][r=.8,g=.4] +\definecolor[trace:8][r=.8,b=.4] +\definecolor[trace:9][g=.4,b=.8] + +\definecolor[trace:w][s=1] +\definecolor[trace:r][r=.75,t=.5,a=1] +\definecolor[trace:g][g=.75,t=.5,a=1] +\definecolor[trace:b][b=.75,t=.5,a=1] +%definecolor[trace:c][c=.75,t=.5,a=1] +\definecolor[trace:c][g=.75,b=.75,t=.5,a=1] +%definecolor[trace:m][m=.75,t=.5,a=1] +\definecolor[trace:m][r=.75,b=.75,t=.5,a=1] +%definecolor[trace:y][y=.75,t=.5,a=1] +\definecolor[trace:y][r=.75,g=.75,t=.5,a=1] +\definecolor[trace:s][s=.75,t=.5,a=1] +\definecolor[trace:d][s=.25,t=.5,a=1] +\definecolor[trace:o][r=1,g=.6,b=.1,t=.5,a=1] + +\definecolor[trace:dw][s=1] +\definecolor[trace:dr][r=.75,t=.75,a=1] +\definecolor[trace:dg][g=.75,t=.75,a=1] +\definecolor[trace:db][b=.75,t=.75,a=1] +%definecolor[trace:dc][c=.75,t=.75,a=1] +\definecolor[trace:dc][g=.75,b=.75,t=.75,a=1] +%definecolor[trace:dm][m=.75,t=.75,a=1] +\definecolor[trace:dm][r=.75,b=.75,t=.75,a=1] +%definecolor[trace:dy][y=.75,t=.75,a=1] +\definecolor[trace:y][r=.75,g=.75,t=.75,a=1] +\definecolor[trace:ds][s=.75,t=.75,a=1] +\definecolor[trace:dd][s=.25,t=.75,a=1] +\definecolor[trace:do][r=1,g=.6,b=.1,t=.75,a=1] + +\setupcolors + [\c!state=\v!stop, % color will be enabled later on + \c!conversion=\v!yes, + \c!rgb=\v!yes, + \c!cmyk=\v!yes, + \c!spot=\v!yes, + \c!pagecolormodel=\v!none, + \c!expansion=\v!no, + \c!textcolor=, + \c!factor=\v!yes] + +\setupcolor + [\v!rgb] + +\protect \endinput diff --git a/tex/context/base/mkiv/cont-cs.mkxl b/tex/context/base/mkiv/cont-cs.mkxl new file mode 100644 index 000000000..8e5ae567c --- /dev/null +++ b/tex/context/base/mkiv/cont-cs.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-cs, +%D version=1998.12.02, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ Czech Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {czech} +\def\defaultlanguagetag{cs} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-de.mkxl b/tex/context/base/mkiv/cont-de.mkxl new file mode 100644 index 000000000..579cc88c3 --- /dev/null +++ b/tex/context/base/mkiv/cont-de.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-de, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ German Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {german} +\def\defaultlanguagetag{de} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-en.mkxl b/tex/context/base/mkiv/cont-en.mkxl new file mode 100644 index 000000000..bfb17ffb3 --- /dev/null +++ b/tex/context/base/mkiv/cont-en.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-en, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ English Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {english} +\def\defaultlanguagetag{en} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-fr.mkxl b/tex/context/base/mkiv/cont-fr.mkxl new file mode 100644 index 000000000..bedae536b --- /dev/null +++ b/tex/context/base/mkiv/cont-fr.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-de, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ French Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {french} +\def\defaultlanguagetag{fr} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-gb.mkxl b/tex/context/base/mkiv/cont-gb.mkxl new file mode 100644 index 000000000..464b237da --- /dev/null +++ b/tex/context/base/mkiv/cont-gb.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-uk, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ English Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {english} +\def\defaultlanguagetag{gb} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-it.mkxl b/tex/context/base/mkiv/cont-it.mkxl new file mode 100644 index 000000000..1702a872f --- /dev/null +++ b/tex/context/base/mkiv/cont-it.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-it, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ Italian Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {italian} +\def\defaultlanguagetag{it} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 102438f7a..08abe123a 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{2019.07.24 11:17} +\newcontextversion{2019.07.31 18:05} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/cont-nl.mkxl b/tex/context/base/mkiv/cont-nl.mkxl new file mode 100644 index 000000000..1f00e7e89 --- /dev/null +++ b/tex/context/base/mkiv/cont-nl.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-nl, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ Dutch Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {dutch} +\def\defaultlanguagetag{nl} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-pe.mkxl b/tex/context/base/mkiv/cont-pe.mkxl new file mode 100644 index 000000000..82bf73721 --- /dev/null +++ b/tex/context/base/mkiv/cont-pe.mkxl @@ -0,0 +1,22 @@ +%D \module +%D [ file=cont-en, +%D version=1997.08.19, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ English Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {persian} +\def\messageinterface {english} +\def\defaultlanguagetag{pe} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/cont-ro.mkxl b/tex/context/base/mkiv/cont-ro.mkxl new file mode 100644 index 000000000..6d636c7dc --- /dev/null +++ b/tex/context/base/mkiv/cont-ro.mkxl @@ -0,0 +1,21 @@ +%D \module +%D [ file=cont-ro, +%D version=2000.01.09, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ Romanian Format Generation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\catcode`\{=1 \catcode`\}=2 + +\def\defaultinterface {romanian} +\def\defaultlanguagetag{ro} + +\input context.mkxl + +\endinput diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index fe13d5930..497bfdc08 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -45,7 +45,7 @@ %D {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2019.07.24 11:17} +\edef\contextversion{2019.07.31 18:05} \edef\contextkind {beta} %D Kind of special: @@ -137,8 +137,6 @@ \loadmkvifile{file-res} \loadmkvifile{file-lib} -\loadmarkfile{core-lmt} % lmtx - %D This needs more checking for clashes: %D %D \starttyping @@ -188,7 +186,6 @@ \loadmarkfile{back-ini} \loadmarkfile{back-res} \loadmarkfile{back-trf} -\loadmarkfile{back-out} \loadmarkfile{attr-col} \loadmarkfile{attr-lay} @@ -586,8 +583,6 @@ \loadmarkfile{back-exp} \loadmarkfile{back-pdf} -\loadmarkfile{back-mps} -\loadmarkfile{back-lua} \loadmarkfile{mlib-pdf} \loadmarkfile{mlib-pps} @@ -604,7 +599,9 @@ \loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv) -\loadmarkfile{driv-shp} +\appendtoks + \setupoutput[pdf] +\to \everyjob \setupcurrentlanguage[\defaultlanguagetag] diff --git a/tex/context/base/mkiv/context.mkxl b/tex/context/base/mkiv/context.mkxl new file mode 100644 index 000000000..f3373a1f7 --- /dev/null +++ b/tex/context/base/mkiv/context.mkxl @@ -0,0 +1,625 @@ +%D \module +%D [ file=context, +%D version=2019.07.24, % 2008.28.10, % 1995.10.10, +%D title=\CONTEXT, +%D subtitle=\CONTEXT\ Format Generation, +%D author=Hans Hagen, % ɦɑns ɦɑˈχən +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% http://build.contextgarden.net/waterfall?tag=c/lua(meta)tex + +%D Welcome to context, pronounced as kontekst (rather dutch) and not as conτεχt. + +\catcode`\{=1 \catcode`\}=2 \catcode`\#=6 + +%D From the next string (which is set by the script that assembles the distribution) +%D later on we will calculate a number that can be used by use modules to identify +%D the feature level. Starting with version 2004.8.30 the low level interface is +%D english. Watch out and adapt your styles an modules. + +% \everypar{\writestatus{!!!!}{some spurious input in line \the\inputlineno}\wait} + +%D The order of loading will change when all modules have been cleaned up and the +%D dependencies are more consistent. Beware, the version number has to match \type +%D {YYYY.MM.DD HH:MM} format. + +\edef\contextformat {\jobname} +\edef\contextversion{2019.07.31 18:05} +\edef\contextkind {beta} + +%D Kind of special: + +\chardef\contextlmtxmode\directlua{tex.print(CONTEXTLMTXMODE or 0)}\relax + +%D For those who want to use this: + +\let\fmtname \contextformat +\let\fmtversion\contextversion + +%D Loading: + +\edef\mksuffix {mkiv} +\edef\contextmark{MKIV} + +\ifx\normalinput\undefined \let\normalinput\input \fi + +\def\loadmarkfile#1{\normalinput{#1.\mksuffix}} +\def\loadmkivfile#1{\normalinput{#1.mkiv}} +\def\loadmkvifile#1{\normalinput{#1.mkvi}} +\def\loadmkxlfile#1{\normalinput{#1.mkxl}} +\def\loadmklxfile#1{\normalinput{#1.mklx}} + +% \def\loadmkxlfile#1{\normalinput{#1.mkiv}} +% \def\loadmklxfile#1{\normalinput{#1.mkvi}} + +%D First we load the system modules. These implement a lot of manipulation macros. +%D We start with setting up some basic \TEX\ machinery. + +\loadmkxlfile{syst-ini} + +%D We just quit if new functionality is expected. + +\ifnum\luatexversion<200 % also change message + \writestatus{!!!!}{Your luametatex binary is too old, you need at least version 2.00!} + \expandafter\end +\fi + +%D Some checking (more primitives are now defined): + +\ifdefined\defaultinterface \else \def\defaultinterface {english} \fi +%ifdefined\messageinterface \else \let\messageinterface \defaultinterface \fi +\ifdefined\defaultlanguagetag \else \def\defaultlanguagetag{en} \fi + +%D There is only this way to pass the version info to \LUA\ (currently). Hm, we could +%D now put it into the environment. + +\newtoks\contextversiontoks \contextversiontoks\expandafter{\contextversion} +\newtoks\contextkindtoks \contextkindtoks \expandafter{\contextkind} + +% \normaleverypar{\wait} % uncomment for test of funny injections + +%D Now the more fundamental code gets defined. + +\loadmarkfile{norm-ctx} +\loadmarkfile{syst-pln} +\loadmarkfile{syst-mes} + +\loadmarkfile{luat-cod} +\loadmarkfile{luat-bas} +\loadmarkfile{luat-lib} +\loadmarkfile{luat-soc} + +\loadmarkfile{catc-ini} +\loadmarkfile{catc-act} +\loadmarkfile{catc-def} +\loadmarkfile{catc-ctx} +\loadmarkfile{catc-sym} + +\loadmarkfile{toks-ini} +\loadmarkfile{cldf-ini} + +% \tracecatcodetables + +%D From here on we have \unexpanded being \normalprotected, as we already had +%D \type {\unexpanded} long before etex came around. + +\loadmarkfile{luat-ini} +\loadmarkfile{toks-scn} + +\loadmkxlfile{syst-aux} % LMTX +\loadmarkfile{syst-lua} +\loadmarkfile{syst-con} + +\loadmarkfile{syst-fnt} +\loadmarkfile{syst-rtp} + +\loadmarkfile{luat-usr} + +\loadmkvifile{file-ini} +\loadmkvifile{file-res} +\loadmkvifile{file-lib} + +\loadmkxlfile{core-lmt} % LMTX + +%D This needs more checking for clashes: +%D +%D \starttyping +%D \doifelsefileexists{l-macro-imp-codes.lua}{\registerctxluafile{l-macro-imp-codes}{}}{} +%D \stoptyping + +\loadmarkfile{supp-dir} + +\loadmarkfile{char-utf} % generic code (i.e. not much tex) ... could become unic-ini +\loadmarkfile{char-ini} % tex / context specific +\loadmarkfile{char-act} % even more specific + +\loadmarkfile{mult-ini} +\loadmarkfile{mult-sys} +\loadmkxlfile{mult-aux} % LMTX +\loadmarkfile{mult-def} +\loadmarkfile{mult-chk} +\loadmkvifile{mult-dim} + +\loadmarkfile{cldf-int} % interface + +\loadmarkfile{trac-ctx} % maybe move up + +% \loadmarkfile{luat-ini} + +\loadmarkfile{toks-tra} +\loadmarkfile{toks-aux} +%loadmarkfile{toks-map} % obsolete, never used + +\loadmarkfile{attr-ini} + +\loadmarkfile{core-ini} +\loadmarkfile{core-env} + +\loadmarkfile{layo-ini} + +\loadmarkfile{node-ini} + +\loadmarkfile{cldf-bas} % basics / depends on nodes + +\loadmkivfile{node-fin} +\loadmarkfile{node-mig} +%loadmarkfile{node-pag} + +\loadmkxlfile{driv-ini} % LMTX + +\loadmkxlfile{back-ini} +\loadmarkfile{back-res} +\loadmarkfile{back-trf} +\loadmkxlfile{back-out} + +\loadmarkfile{attr-col} +\loadmarkfile{attr-lay} +\loadmarkfile{attr-neg} +\loadmarkfile{attr-eff} +\loadmarkfile{attr-mkr} + +\loadmarkfile{trac-tex} +\loadmarkfile{trac-deb} % will move up + +%loadmarkfile{blob-ini} % not to be used, we only use a helper + +\loadmkxlfile{supp-box} % LMTX + +\loadmarkfile{supp-ran} +\loadmarkfile{supp-mat} + +\loadmarkfile{core-uti} +\loadmkvifile{file-job} + +\loadmarkfile{anch-pos} + +\loadmarkfile{typo-ini} +\loadmarkfile{typo-lin} +\loadmarkfile{typo-bld} % par builders + +\loadmarkfile{typo-inj} + +\loadmkvifile{file-syn} +\loadmkvifile{file-mod} + +\loadmarkfile{core-sys} +\loadmarkfile{core-con} + +\loadmarkfile{cont-fil} + +\loadmarkfile{regi-ini} +\loadmarkfile{enco-ini} +\loadmarkfile{hand-ini} + +\loadmkxlfile{lang-ini} % LMTX +\loadmarkfile{lang-hyp} % also loads dis +\loadmkxlfile{lang-lab} % LMTX + +\loadmarkfile{unic-ini} + +% \loadmarkfile{core-uti} +\loadmarkfile{core-two} +\loadmarkfile{core-dat} + +\loadmkxlfile{colo-ini} % LMTX +\loadmarkfile{colo-grp} % optional +\loadmarkfile{colo-ext} + +\loadmarkfile{node-bck} % overloads anch-pgr (experimental and undocumented) + +\loadmarkfile{pack-cut} + +\loadmarkfile{lang-mis} +\loadmarkfile{lang-url} +\loadmarkfile{lang-def} + +% \loadmkvifile{file-job} % why so late? + +\loadmarkfile{symb-ini} % brrr depends on fonts + +\loadmarkfile{sort-ini} + +\loadmkvifile{pack-mis} +\loadmkxlfile{pack-rul} % LMTX +\loadmarkfile{pack-mrl} +\loadmkvifile{pack-bck} +\loadmarkfile{pack-fen} + +\loadmarkfile{lxml-ini} +\loadmarkfile{lxml-sor} + +\loadmkvifile{typo-prc} + +% \loadmarkfile{anch-pos} + +\loadmkvifile{strc-ini} +\loadmarkfile{strc-tag} +\loadmarkfile{strc-doc} +\loadmarkfile{strc-num} +\loadmarkfile{strc-mar} +\loadmarkfile{strc-sbe} +\loadmkvifile{strc-lst} +\loadmarkfile{strc-sec} +\loadmarkfile{strc-pag} % hm, depends on core-num +\loadmarkfile{strc-ren} +\loadmarkfile{strc-xml} +\loadmarkfile{strc-def} % might happen later +\loadmkvifile{strc-ref} +%loadmarkfile{strc-reg} +\loadmkvifile{strc-lev} % experiment + +\loadmarkfile{spac-hor} +\loadmarkfile{spac-ali} +\loadmarkfile{spac-flr} +\loadmkxlfile{spac-ver} % LMTX beware, hooks into strc-sec +\loadmarkfile{spac-lin} +\loadmarkfile{spac-pag} +\loadmarkfile{spac-par} +\loadmarkfile{spac-def} +\loadmkvifile{spac-prf} +\loadmarkfile{spac-grd} + +%loadmarkfile{anch-pos} + +\loadmkvifile{scrn-ini} +\loadmkvifile{scrn-ref} + +\loadmarkfile{pack-obj} + +\loadmklxfile{strc-itm} % LMTX + +\loadmkvifile{strc-con} +\loadmkvifile{strc-des} +\loadmkvifile{strc-enu} + +\loadmarkfile{strc-ind} +\loadmarkfile{strc-lab} +\loadmarkfile{strc-syn} + +% \loadmarkfile{core-sys} + +\loadmarkfile{page-var} +\loadmkvifile{page-otr} +\loadmarkfile{page-ini} +\loadmarkfile{page-ins} +\loadmarkfile{page-fac} +\loadmarkfile{page-brk} +\loadmarkfile{page-col} +\loadmarkfile{page-inf} +\loadmarkfile{page-flt} +\loadmarkfile{page-bck} +\loadmarkfile{page-not} +\loadmarkfile{page-one} +\loadmarkfile{page-lay} +\loadmkvifile{page-box} +\loadmkvifile{page-txt} +\loadmarkfile{page-sid} % when + +\loadmkvifile{strc-flt} + +\loadmarkfile{page-pst} +\loadmkvifile{page-mbk} +%loadmarkfile{page-mul} % \usecolumns[old-multicolumns] +\loadmarkfile{page-mix} +\loadmarkfile{page-smp} +%loadmarkfile{page-set} % \usecolumns[old-columnsets] +\loadmarkfile{page-cst} +\loadmarkfile{page-pcl} % new +\loadmarkfile{pack-lyr} +\loadmarkfile{pack-pos} +\loadmkvifile{page-mak} + +\loadmarkfile{strc-reg} % uses mixed columns + +\loadmkvifile{page-lin} +\loadmarkfile{page-par} +\loadmarkfile{typo-pag} +\loadmarkfile{typo-mar} +\loadmarkfile{typo-itm} + +\loadmarkfile{buff-ini} +\loadmkxlfile{buff-ver} % LMTX +\loadmkvifile{buff-par} + +\loadmarkfile{buff-imp-tex} % optional as also runtime if not loaded +\loadmarkfile{buff-imp-mp} % optional as also runtime if not loaded +\loadmarkfile{buff-imp-lua} % optional as also runtime if not loaded +\loadmarkfile{buff-imp-xml} % optional as also runtime if not loaded + +\loadmarkfile{buff-imp-parsed-xml} % optional +%loadmarkfile{buff-imp-parsed-lua} % optional + +\loadmarkfile{strc-blk} + +\loadmarkfile{page-imp} +\loadmkvifile{page-sel} % optional +\loadmkvifile{page-inj} % optional + +\loadmkvifile{scrn-pag} +\loadmkvifile{scrn-wid} +\loadmkvifile{scrn-but} +\loadmkvifile{scrn-bar} + +\loadmarkfile{page-com} % optional (after scrn-pag) + +\loadmarkfile{strc-bkm} % bookmarks + +\loadmarkfile{java-ini} + +\loadmkvifile{scrn-fld} +\loadmkvifile{scrn-hlp} + +\loadmarkfile{char-enc} % will move up + +\loadmkvifile{font-lib} % way too late but after language +\loadmklxfile{font-fil} % LMTX +\loadmkvifile{font-var} +\loadmkvifile{font-fea} +\loadmklxfile{font-mat} % LMTX +\loadmklxfile{font-ini} % LMTX +\loadmklxfile{font-sym} % LMTX +\loadmklxfile{font-sty} % LMTX +\loadmkvifile{font-set} +\loadmklxfile{font-emp} % LMTX +\loadmarkfile{font-pre} +\loadmarkfile{font-unk} +\loadmarkfile{font-tra} +\loadmarkfile{font-chk} +\loadmarkfile{font-uni} +\loadmkvifile{font-col} +\loadmkvifile{font-gds} +\loadmkvifile{font-aux} +\loadmkvifile{font-sel} + +\loadmarkfile{typo-tal} +\loadmarkfile{typo-par} % par builders (uses fonts) + +\loadmarkfile{tabl-com} +\loadmarkfile{tabl-pln} + +\loadmarkfile{tabl-tab} % thrd-tab stripped and merged + +\loadmkxlfile{tabl-tbl} % LMTX +\loadmkxlfile{tabl-ntb} % LMTX +\loadmarkfile{tabl-nte} +\loadmarkfile{tabl-ltb} +\loadmarkfile{tabl-frm} +\loadmarkfile{tabl-tsp} +\loadmkvifile{tabl-xtb} +\loadmarkfile{tabl-mis} + +\loadmarkfile{typo-lan} + +\loadmarkfile{lxml-css} + +\loadmarkfile{spac-chr} % depends on fonts + +\loadmarkfile{blob-ini} % not to be used, we only use a helper + +\loadmarkfile{trac-vis} +\loadmarkfile{trac-jus} + +\loadmarkfile{typo-cln} +\loadmarkfile{typo-wrp} +\loadmarkfile{typo-spa} +\loadmarkfile{typo-krn} +\loadmkvifile{typo-itc} +\loadmarkfile{typo-dir} +\loadmarkfile{typo-brk} +\loadmarkfile{typo-cap} +\loadmarkfile{typo-dig} +\loadmarkfile{typo-rep} +\loadmkvifile{typo-txt} +\loadmarkfile{typo-drp} +\loadmarkfile{typo-fln} +\loadmarkfile{typo-sus} +\loadmarkfile{typo-lig} +\loadmarkfile{typo-chr} +\loadmarkfile{typo-rub} +\loadmkivfile{typo-fkr} +\loadmkivfile{typo-pnc} + +\loadmklxfile{type-ini} % LMTX +\loadmarkfile{type-set} + +\loadmarkfile{scrp-ini} + +\loadmarkfile{symb-emj} + +\loadmarkfile{lang-wrd} % can be optional (discussion with mm sideeffect) +\loadmarkfile{lang-rep} % can be optional (bt 2013 side effect) + +\loadmarkfile{prop-ini} % only for downward compatibility + +\loadmkxlfile{mlib-ctx} % messy order + +\loadmarkfile{meta-ini} +\loadmarkfile{meta-tex} +\loadmarkfile{meta-fun} +\loadmarkfile{meta-pag} +\loadmarkfile{meta-grd} +\loadmarkfile{meta-fnt} +\loadmarkfile{meta-nod} +\loadmarkfile{meta-lua} +\loadmkxlfile{meta-mac} + +\loadmarkfile{page-mrk} % depends on mp + +\loadmarkfile{page-flw} +\loadmarkfile{page-spr} +\loadmarkfile{page-plg} +\loadmarkfile{page-str} + +\loadmarkfile{anch-pgr} % can be moved up (nicer for dependencies) +\loadmkvifile{anch-bck} +\loadmarkfile{anch-tab} % overloads tabl-tbl +\loadmarkfile{anch-bar} +%loadmarkfile{anch-snc} % when needed this one will be redone + +\loadmarkfile{math-ini} % way after font-pre ! +\loadmarkfile{math-pln} +\loadmarkfile{math-for} +\loadmarkfile{math-def} % also saves some meanings +\loadmarkfile{math-ali} +%loadmarkfile{math-arr} +\loadmkvifile{math-stc} +\loadmarkfile{math-frc} +\loadmarkfile{math-mis} +\loadmarkfile{math-scr} +\loadmarkfile{math-int} +\loadmarkfile{math-del} +\loadmarkfile{math-fen} +\loadmkvifile{math-acc} +\loadmkvifile{math-rad} +\loadmarkfile{math-inl} +\loadmarkfile{math-dis} +%loadmarkfile{math-lan} + +%loadmarkfile{phys-dim} % moved to after typo-scr + +\loadmarkfile{strc-mat} + +\loadmarkfile{chem-ini} +\loadmarkfile{chem-str} + +\loadmarkfile{typo-scr} +\loadmarkfile{phys-dim} + +\loadmarkfile{node-rul} % beware, defined \underbar so after math +\loadmkvifile{font-sol} % font solutions + +\loadmkvifile{strc-not} +\loadmkvifile{strc-lnt} +\loadmkivfile{strc-tnt} +\loadmkivfile{strc-usr} + +\loadmarkfile{pack-com} +\loadmarkfile{typo-del} + +\loadmarkfile{grph-trf} +\loadmarkfile{grph-inc} +\loadmarkfile{grph-fig} +\loadmarkfile{grph-raw} +\loadmarkfile{grph-rul} +\loadmarkfile{grph-pat} + +\loadmarkfile{pack-box} +\loadmarkfile{pack-bar} +\loadmarkfile{page-app} +\loadmarkfile{meta-fig} + +\loadmarkfile{page-ffl} + +\loadmarkfile{lang-spa} % will become obsolete + +\loadmarkfile{typo-ovl} % fuzzy project (tracing) code + +% old bibtex support: (will be m-oldbibtex.mkiv) + +% \loadmarkfile{bibl-bib} +% \loadmarkfile{bibl-tra} + +% new bibtex support: + +\loadmarkfile{publ-ini} +\loadmarkfile{publ-tra} +\loadmarkfile{publ-xml} +\loadmarkfile{publ-old} + +%loadmarkfile{x-xtag} % no longer preloaded + +\loadmarkfile{meta-xml} + +\loadmarkfile{cont-log} + +% \loadmarkfile{task-ini} + +\loadmarkfile{cldf-ver} % verbatim, this can come late +\loadmarkfile{cldf-com} % commands, this can come late + +\loadmarkfile{core-ctx} % this order might change but we need to check depedencies / move to another namespace + +\loadmarkfile{core-def} + +%usemodule[x][res-04] % xml resource libraries +%usemodule[x][res-08] % rlx runtime conversion +%usemodule[x][res-12] % rli external indentification + +% now we hook in backend code (needs checking) + +\loadmkxlfile{driv-shp} + +\loadmarkfile{back-exp} +\loadmkxlfile{back-pdf} +\loadmkxlfile{back-mps} +\loadmkxlfile{back-lua} + +\loadmarkfile{mlib-pdf} +\loadmarkfile{mlib-pps} +\loadmarkfile{meta-pdf} +\loadmarkfile{meta-blb} +\loadmarkfile{grph-epd} + +\loadmarkfile{math-inc} % an experiment +\loadmarkfile{publ-inc} % an experiment + +\loadmarkfile{task-ini} + +\loadmarkfile{syst-cmp} % compatibility stuff moved here + +\loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv) + +% \loadmkxlfile{driv-shp} + +\appendtoks + \setupoutput[pdf] +\to \everyjob + +\setupcurrentlanguage[\defaultlanguagetag] + +\prependtoks + \ctxlua{statistics.starttiming(statistics)}% +\to \everyjob + +\appendtoks + \ctxlua{statistics.stoptiming(statistics)}% +\to \everyjob + +% \appendtoks +% \ctxlua{job.prepare()}% +% \to \everyjob + +% \appendtoks +% \enabletrackers[*]% +% \to \everyjob + +\appendtoks + \ctxlua{statistics.savefmtstatus("\jobname","\contextversion","context.mkxl","\contextkind","\contextbanner")}% can become automatic +\to \everydump + +\errorstopmode \dump \endinput diff --git a/tex/context/base/mkiv/core-lmt.mkiv b/tex/context/base/mkiv/core-lmt.mkiv deleted file mode 100644 index eda667969..000000000 --- a/tex/context/base/mkiv/core-lmt.mkiv +++ /dev/null @@ -1,32 +0,0 @@ -%D \module -%D [ file=core-lmt, -%D version=2010.08.2, -%D title=\CONTEXT\ System Macros, -%D subtitle=Primitives, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\ifcase\contextlmtxmode\expandafter\endinput\fi - -\writestatus{loading}{ConTeXt System Macros / Primitives} - -\ifdefined\textdir \else - \registerctxluafile{core-lmt}{} -\fi - -\unprotect - -% nothing yet - -\protect \endinput - -% \starttext -% abc{\textdir TRTdef}ghi -% abc{\textdir trtdef}ghi -% \boxdirection0=1 -% \stoptext diff --git a/tex/context/base/mkiv/core-lmt.mkxl b/tex/context/base/mkiv/core-lmt.mkxl new file mode 100644 index 000000000..75a791a50 --- /dev/null +++ b/tex/context/base/mkiv/core-lmt.mkxl @@ -0,0 +1,31 @@ +%D \module +%D [ file=core-lmt, +%D version=2018.08.2, +%D title=\CONTEXT\ System Macros, +%D subtitle=Primitives, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt System Macros / Primitives} + +%D This is offered temporarily because in the end we don't expect u sers to use the +%D low level direction directives directly. + +\registerctxluafile{core-lmt}{} + +\unprotect + +% nothing yet + +\protect \endinput + +% \starttext +% abc{\textdir TRTdef}ghi +% abc{\textdir trtdef}ghi +% \boxdirection0=1 +% \stoptext diff --git a/tex/context/base/mkiv/data-tmp.lua b/tex/context/base/mkiv/data-tmp.lua index e65f7ce61..ae7f65149 100644 --- a/tex/context/base/mkiv/data-tmp.lua +++ b/tex/context/base/mkiv/data-tmp.lua @@ -69,7 +69,8 @@ caches.ask = false caches.relocate = false caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } -directives.register("system.caches.fast",function(v) caches.fast = true end) +directives.register("system.caches.fast", function(v) caches.fast = true end) +directives.register("system.caches.direct",function(v) caches.direct = true end) local writable, readables, usedreadables = nil, { }, { } @@ -361,11 +362,7 @@ end local saveoptions = { compact = true } --- add some point we will only use the internal bytecode compiler and --- then we can flag success in the tma so that it can trigger a compile --- if the other engine - -function caches.savedata(filepath,filename,data,raw) +function caches.savedata(filepath,filename,data) local tmaname, tmcname = caches.setluanames(filepath,filename) data.cache_uuid = os.uuid() if caches.fast then diff --git a/tex/context/base/mkiv/driv-ini.mkiv b/tex/context/base/mkiv/driv-ini.mkiv index 958afb6a9..96e7460a3 100644 --- a/tex/context/base/mkiv/driv-ini.mkiv +++ b/tex/context/base/mkiv/driv-ini.mkiv @@ -13,19 +13,18 @@ \writestatus{loading}{ConTeXt Driver Macros / Initialization} +%D Around the \CONTEXT\ 2018 meeting I had a preliminary backend written in \LUA\ as +%D alternative for the hard coded variant (we're talking of the font embedding and +%D page stream output, the part we still used). Therefore there is a pluggable +%D output driver. But \unknown\ I decided not to waste time on supporting both +%D \LUATEX\ and the new kid \LUAMETATEX, also because in practice \LUATEX\ would be +%D used as benchmark, using the more traditional approach. So, the code in the +%D driver modules is mostly a kind of simple placeholder now and although I could +%D simplify it ther eis no real reason for it. It is no problem to getit all working +%D well in normal \LUATEX, it's just that we don't need it there. + \registerctxluafile{driv-ini}{} \unprotect -\unexpanded\def\page_shipout_box#1% - {\clf_shipoutpage#1\relax - \global\setbox#1\emptybox - \global\deadcycles\zerocount} - -\ifdefined\page_otr_shipout_yes \else - - \let\page_otr_shipout_yes\page_shipout_box - -\fi - \protect \endinput diff --git a/tex/context/base/mkiv/driv-ini.mkxl b/tex/context/base/mkiv/driv-ini.mkxl new file mode 100644 index 000000000..9f489a2a1 --- /dev/null +++ b/tex/context/base/mkiv/driv-ini.mkxl @@ -0,0 +1,20 @@ +%D \module +%D [ file=driv-ini, +%D version=2018.07.26, +%D title=\CONTEXT\ Driver Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Driver Macros / Initialization} + +\registerctxluafile{driv-ini}{} + +\unprotect + +\protect \endinput diff --git a/tex/context/base/mkiv/driv-shp.mkiv b/tex/context/base/mkiv/driv-shp.mkiv deleted file mode 100644 index f92649a48..000000000 --- a/tex/context/base/mkiv/driv-shp.mkiv +++ /dev/null @@ -1,24 +0,0 @@ -%D \module -%D [ file=driv-shp, -%D version=2018.07.26, -%D title=\CONTEXT\ Driver Macros, -%D subtitle=Shipout, -%D author=Hans Hagen, -%D date=\currentdate, -%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] -%C -%C This module is part of the \CONTEXT\ macro||package and is -%C therefore copyrighted by \PRAGMA. See mreadme.pdf for -%C details. - -\ifcase\contextlmtxmode \else - \registerctxluafile{driv-shp}{optimize} -\fi - -\unprotect - -\appendtoks - \clf_enabledriver{pdf}% -\to \everyjob - -\protect \endinput diff --git a/tex/context/base/mkiv/driv-shp.mkxl b/tex/context/base/mkiv/driv-shp.mkxl new file mode 100644 index 000000000..68b62c72a --- /dev/null +++ b/tex/context/base/mkiv/driv-shp.mkxl @@ -0,0 +1,18 @@ +%D \module +%D [ file=driv-shp, +%D version=2018.07.26, +%D title=\CONTEXT\ Driver Macros, +%D subtitle=Shipout, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\registerctxluafile{driv-shp}{optimize} + +\unprotect + +\protect \endinput diff --git a/tex/context/base/mkiv/file-job.lua b/tex/context/base/mkiv/file-job.lua index 486aee63a..fd9a5a120 100644 --- a/tex/context/base/mkiv/file-job.lua +++ b/tex/context/base/mkiv/file-job.lua @@ -172,8 +172,8 @@ implement { -- moved from tex to lua: -local texpatterns = { "%s.mkvi", "%s.mkiv", "%s.tex" } -local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua" } +local texpatterns = { "%s.mkvi", "%s.mkiv", "%s.mklx", "%s.mkxl", "%s.tex" } +local luapatterns = { "%s" .. utilities.lua.suffixes.luc, "%s.lua", "%s.lmt" } local cldpatterns = { "%s.cld" } local xmlpatterns = { "%s.xml" } diff --git a/tex/context/base/mkiv/file-mod.lua b/tex/context/base/mkiv/file-mod.lua index 81320f96e..10a187178 100644 --- a/tex/context/base/mkiv/file-mod.lua +++ b/tex/context/base/mkiv/file-mod.lua @@ -36,7 +36,7 @@ local iterator = utilities.parsers.iterator -- modules can have a specific suffix or can specify one -local prefixes = { +local prefixes = { "m", -- module, extends functionality "p", -- private code "s", -- styles @@ -47,13 +47,24 @@ local prefixes = { -- the order might change and how about cld -local suffixes = { - "mkvi", -- proprocessed mkiv files +local suffixes = CONTEXTLMTXMODE > 0 and +{ + "mklx", -- preprocessed mkiv lmtx files + "mkxl", -- mkiv lmtx files + "mkvi", -- preprocessed mkiv files "mkiv", -- mkiv files "tex", -- normally source code files "cld", -- context lua documents (often stand alone) "lua", -- lua files } + or +{ + "mkvi", + "mkiv", + "tex", + "cld", + "lua", +} local modstatus = { } local missing = false diff --git a/tex/context/base/mkiv/font-emp.mklx b/tex/context/base/mkiv/font-emp.mklx new file mode 100644 index 000000000..7eaf0a24f --- /dev/null +++ b/tex/context/base/mkiv/font-emp.mklx @@ -0,0 +1,256 @@ +%D \module +%D [ file=font-emp, +%D version=20120106, % (moved from font-ini) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Emphasis, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Font Macros / Emphasis} + +\unprotect + +%D \macros +%D {em,emphasistypeface,emphasisboldface} +%D +%D The next macro started as a copy of Donald Arseneau's \type {\em} (\TUGNEWS\ +%D Vol.~3, no.~1, 1994). His implementation was a bit more sophisticated version of +%D the standard \LATEX\ one. We further enhanced the macro, so now it also adapts +%D itself to boldface mode. Because we favor {\sl slanted} type over {\it italic}, +%D we made the emphasis adaptable, for instance: +%D +%D \starttyping +%D \def\emphasistypeface {\it} +%D \def\emphasisboldface {\bi} +%D \stoptyping +%D +%D But we prefer: +%D +%D \starttyping +%D \unexpanded\def\emphasistypeface{\sl} +%D \unexpanded\def\emphasisboldface{\bs} +%D \stoptyping +%D +%D or even better: + +\let\m_font_emphasized_typeface\empty + +\def\font_emphasis_checked_typeface#slanted#italic% + {\edef\m_font_emphasized_typeface{\font_bodyfontvariable\s!em}% + \ifx\m_font_emphasized_typeface\v!slanted + #slanted% + \orelse\ifx\m_font_emphasized_typeface\v!italic + #italic% + \orelse\ifx\m_font_emphasized_typeface\empty + #slanted% + \else + \csname\m_font_emphasized_typeface\endcsname + \fi} + +\unexpanded\def\emphasistypeface{\font_emphasis_checked_typeface\sl\it} +\unexpanded\def\emphasisboldface{\font_emphasis_checked_typeface\bs\bi} + +\unexpanded\def\normalboldface % public + {\relax + \ifx\fontalternative\s!it\bi\orelse + \ifx\fontalternative\s!sl\bs\else + \bf\fi} + +\unexpanded\def\normalitalicface % public + {\relax + \ifx\fontalternative\s!tf\it\orelse + \ifx\fontalternative\s!bf\bi\else + \tf\fi} + +\unexpanded\def\normalslantedface % public + {\relax \ifx\fontalternative\s!tf\sl + \orelse\ifx\fontalternative\s!bf\bs + \else \tf\fi} + +\unexpanded\def\normaltypeface % public + {\relax + \ifx\fontalternative\s!bi \it \orelse + \ifx\fontalternative\s!bs \sl \else + \tf \fi} + +\unexpanded\def\swaptypeface % public + {\relax + \ifx\fontalternative\s!it \tf \orelse + \ifx\fontalternative\s!sl \tf \orelse + \ifx\fontalternative\s!bf \emphasisboldface \orelse + \ifx\fontalternative\s!bs \bf \orelse + \ifx\fontalternative\s!bi \bf \else + \emphasistypeface \fi} + +\let\typeface \normaltypeface % public +\let\boldface \normalboldface % public +\let\slantedface\normalslantedface % public +\let\italicface \normalitalicface % public +\let\swapface \swaptypeface % public + +%D To be set with the default body font environment: \type +%D {em} being \type {slanted} or \type {italic}. + +% maybe a \csname...\fontalternative\endcsname + +\newconditional\c_font_emphasis_needed + +\unexpanded\def\em + {\relax + \ifdim\slantperpoint>\zeropoint + \settrue\c_font_emphasis_needed + \else + \setfalse\c_font_emphasis_needed + \fi + \font_emphasis_set_emphasis_boldface % new + \ifx\fontalternative\s!it + \unexpanded\def\emphasistypeface{\it}\tf + \orelse\ifx\fontalternative\s!sl + \unexpanded\def\emphasistypeface{\sl}\tf + \orelse\ifx\fontalternative\s!bf + \emphasisboldface + \orelse\ifx\fontalternative\s!bs + \unexpanded\def\emphasisboldface{\bs}\bf + \orelse\ifx\fontalternative\s!bi + \unexpanded\def\emphasisboldface{\bi}\bf + \else + \emphasistypeface + \fi + \ifconditional\c_font_emphasis_needed\else + \expandafter\aftergroup + \fi + \emphasiscorrection} + +%D The next feature was not present in previous versions. It +%D takes care of \type {\em \bf ...} situations. + +\let\font_emphasis_saved_emphasis_boldface\relax + +\def\font_emphasis_set_emphasis_boldface + {\let\font_emphasis_saved_emphasis_boldface\bf + \let\font_emphasis_set_emphasis_boldface\relax + \let\bf\font_emphasis_bold_bold} + +\unexpanded\def\font_emphasis_bold_bold + {%\relax + \let\bf\relax % new + \ifx\fontalternative\s!it + \bi + \orelse\ifx\fontalternative\s!sl + \bs + \else + \font_emphasis_saved_emphasis_boldface + \fi + \let\bf\font_emphasis_saved_emphasis_boldface} + +%D Donald's (adapted) macros take the next character into account when placing +%D italic correction. As a bonus we also look for something that looks like a dash, +%D in which case we don't correct. + +\let\italiccorrection=\/ % tex primitive + +\def\emphasiscorrection % public, not in raw alignment groups, else omit problem + {\ifhmode\ifnum\currentgrouptype=\aligngroupcode\else + \expandafter\expandafter\expandafter\font_emphasis_look + \fi\fi} + +\def\font_emphasis_look + {\begingroup + \futurelet\nexttoken\font_emphasis_test} + +\def\font_emphasis_test + {\ifcat\noexpand\nexttoken,% still ok? + \expandafter\font_emphasis_a + \else + \expandafter\font_emphasis_b + \fi} + +\def\font_emphasis_a + {\futurelet\nexttoken\font_emphasis_correction} + +\def\font_emphasis_correction + {\setbox\scratchbox\hbox{\nexttoken}% tricky as next can be a macro + \ifdim\ht\scratchbox=\zeropoint % probably a space + \expandafter\font_emphasis_b + \orelse\ifdim\ht\scratchbox<.3\exheight + \expandafter\expandafter\expandafter\endgroup + \else + \expandafter\expandafter\expandafter\font_emphasis_b + \fi} + +\def\font_emphasis_b + {\scratchskip\lastskip + \ifdim\scratchskip=\zeropoint\relax % == \ifzeropt\scratchskip + \italiccorrection\relax + \else + \unskip\italiccorrection\hskip\scratchskip + \fi + \endgroup} + +%D We end with some examples which show the behavior when some punctuation is met. +%D We also show how the mechanism adapts itself to bold, italic and slanted typing. +%D +%D \startbuffer +%D test {test}test \par +%D test {\sl test}test \par +%D test {\em test}test \par +%D test {\em test}--test \par +%D +%D test {test}, test \par +%D test {\em test}, test \par +%D +%D test {\em test {\em test {\em test} test} test} test \par +%D test {\bf test {\em test {\em test} test} test} test \par +%D test {\sl test {\em test {\em test} test} test} test \par +%D test {\it test {\em test {\em test} test} test} test \par +%D \stopbuffer +%D +%D \typebuffer +%D +%D We get: +%D +%D \startpacked +%D \getbuffer +%D \stoppacked + +%D \macros +%D {emphbf,emphit,emphsl,emphtf} +%D +%D The next emphasis alternatives are for \THANH. They adapt their style as good as +%D possible. These macros are obsolete in \MKIV. + +% \unexpanded\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}} +% \unexpanded\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}} +% \unexpanded\def\emphsl{\groupedcommand{\sl\def\emphbf{\bs}\def\emphit{\it}}{}} +% \unexpanded\def\emphtf{\groupedcommand{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}}{}} +% \unexpanded\def\emph {\groupedcommand{\em}{}} + +\unexpanded\def\font_emphasis_bf{\bf\def\emphit{\bi}\def\emphsl{\bs}} +\unexpanded\def\font_emphasis_it{\it\def\emphbf{\bi}\def\emphsl{\sl}} +\unexpanded\def\font_emphasis_sl{\sl\def\emphbf{\bs}\def\emphit{\it}} +\unexpanded\def\font_emphasis_tf{\tf\def\emphbf{\bf}\def\emphit{\it}\def\emphsl{\sl}} + +\unexpanded\def\emphbf{\triggergroupedcommandcs\font_emphasis_bf} +\unexpanded\def\emphit{\triggergroupedcommandcs\font_emphasis_it} +\unexpanded\def\emphsl{\triggergroupedcommandcs\font_emphasis_sl} +\unexpanded\def\emphtf{\triggergroupedcommandcs\font_emphasis_tf} +\unexpanded\def\emph {\triggergroupedcommandcs\em} + +\unexpanded\def\emphasized{\bgroup\em\let\nexttoken} + +%D \startbuffer +%D TEXT {\emphbf text \emphit text \emphtf text \emphsl text} TEXT +%D TEXT \emphbf{text \emphit{text} \emphtf{text} \emphsl{text}} TEXT +%D \stopbuffer +%D +%D \typebuffer +%D \startlines +%D \getbuffer +%D \stoplines + +\protect \endinput diff --git a/tex/context/base/mkiv/font-emp.mkvi b/tex/context/base/mkiv/font-emp.mkvi index b5c09d4c2..5dacd175b 100644 --- a/tex/context/base/mkiv/font-emp.mkvi +++ b/tex/context/base/mkiv/font-emp.mkvi @@ -18,13 +18,11 @@ %D \macros %D {em,emphasistypeface,emphasisboldface} %D -%D The next macro started as a copy of Donald Arseneau's -%D \type{\em} (\TUGNEWS\ Vol.~3, no.~1, 1994). His -%D implementation was a bit more sophisticated version of the -%D standard \LATEX\ one. We further enhanced the macro, so now -%D it also adapts itself to boldface mode. Because we favor -%D {\sl slanted} type over {\it italic}, we made the emphasis -%D adaptable, for instance: +%D The next macro started as a copy of Donald Arseneau's \type {\em} (\TUGNEWS\ +%D Vol.~3, no.~1, 1994). His implementation was a bit more sophisticated version of +%D the standard \LATEX\ one. We further enhanced the macro, so now it also adapts +%D itself to boldface mode. Because we favor {\sl slanted} type over {\it italic}, +%D we made the emphasis adaptable, for instance: %D %D \starttyping %D \def\emphasistypeface {\it} @@ -148,10 +146,9 @@ \fi\fi \let\bf\font_emphasis_saved_emphasis_boldface} -%D Donald's (adapted) macros take the next character into -%D account when placing italic correction. As a bonus we also -%D look for something that looks like a dash, in which case we -%D don't correct. +%D Donald's (adapted) macros take the next character into account when placing +%D italic correction. As a bonus we also look for something that looks like a dash, +%D in which case we don't correct. \let\italiccorrection=\/ % tex primitive @@ -193,9 +190,8 @@ \fi \endgroup} -%D We end with some examples which show the behavior when -%D some punctuation is met. We also show how the mechanism -%D adapts itself to bold, italic and slanted typing. +%D We end with some examples which show the behavior when some punctuation is met. +%D We also show how the mechanism adapts itself to bold, italic and slanted typing. %D %D \startbuffer %D test {test}test \par @@ -223,9 +219,8 @@ %D \macros %D {emphbf,emphit,emphsl,emphtf} %D -%D The next emphasis alternatives are for \THANH. They adapt -%D their style as good as possible. These macros are obsolete -%D in \MKIV. +%D The next emphasis alternatives are for \THANH. They adapt their style as good as +%D possible. These macros are obsolete in \MKIV. % \unexpanded\def\emphbf{\groupedcommand{\bf\def\emphit{\bi}\def\emphsl{\bs}}{}} % \unexpanded\def\emphit{\groupedcommand{\it\def\emphbf{\bi}\def\emphsl{\sl}}{}} diff --git a/tex/context/base/mkiv/font-fil.mklx b/tex/context/base/mkiv/font-fil.mklx new file mode 100644 index 000000000..6cc25db10 --- /dev/null +++ b/tex/context/base/mkiv/font-fil.mklx @@ -0,0 +1,422 @@ +%D \module +%D [ file=font-fil, +%D version=2011.01.13, % (copied fron font-ini) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Classes and Files, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Font Macros / Classes and Files} + +\unprotect + +%D Personally I think that using \TEX\ macro packages is complicated by the way +%D fonts are handled. Apart from the many encodings, we also deal with different +%D naming schemes. Confronted with this problem, I decided to change the definitions +%D into: +%D +%D \starttyping +%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt] +%D \stoptyping +%D +%D combined with for instance: +%D +%D \starttyping +%D \definefontsynonym [Times-Roman] [tir] +%D \stoptyping + +% \definetypeface[palatino][rm][serif][palatino,allbold][default] +% +% \startfontclass[palatino] +% \definefontsynonym [Serif] [SerifBold] +% \definefontsynonym [SerifItalic] [SerifBoldItalic] +% \definefontsynonym [SerifSlanted] [SerifBoldSlanted] +% \definefontsynonym [SerifCaps] [SerifBold] +% \stopfontclass +% +% \setupbodyfont[palatino] + +\unexpanded\def\startfontclass + {\dosingleempty\font_basics_start_font_class} + +\def\font_basics_start_font_class[#class]% + {\push_macro_fontclass + \doifelse{#class}\v!each + {\let\fontclass\empty} + {\doifsomething{#class}{\def\fontclass{#class}}}} + +\unexpanded\def\stopfontclass + {\pop_macro_fontclass} + +\def\classfont#class#name{#class#name} % \definefont[whatever][\classfont{xx}{yy} at 10pt] + +%D \macros +%D {definefontsynonym, doifelsefontsynonym, +%D expandfontsynonym, truefontname, truefontdata} +%D +%D While looking for fonts, fontsynonyms are used for accessing +%D the files! +%D +%D \starttyping +%D \definefontsynonym[Serif][Lucida-Bright] +%D \definefontsynonym[Lucida-Bright][lbr][encoding=texnansi] +%D \stoptyping + +\installcorenamespace {fontfile} % file synonyms + +\let\m_font_name\empty +\let\m_font_file\empty + +\def \defaultfontfile{\truefontname{Normal}} % was cmtt10, but that one is gone +\edef\nullfontname {\fontname\nullfont} + +\unexpanded\def\definefontsynonym[#name]#crap[#file]% + {\edef\m_font_name{#name}% + \edef\m_font_file{#file}% + \ifx\fontclass\empty + \expandafter\font_basics_define_font_synonym_nop + \else + \expandafter\font_basics_define_font_synonym_yes + \fi} + +\unexpanded\def\font_basics_define_font_synonym_nop + {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file + \doifelsenextoptionalcs\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil} + +\unexpanded\def\font_basics_define_font_synonym_yes + {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file + \doifelsenextoptionalcs\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil} + +\unexpanded\def\edefinefontsynonym[#name]#crap[#file]% + {\edef\m_font_name{#name}% + \edef\m_font_file{#file}% + \ifx\fontclass\empty + \expandafter\font_basics_define_font_synonym_nop_expanded + \else + \expandafter\font_basics_define_font_synonym_yes_expanded + \fi} + +\unexpanded\def\font_basics_define_font_synonym_nop_expanded#crap[#spec]% + {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file + \normalexpanded{\font_basics_define_font_synonym_nop_opt[#1]}} + +\unexpanded\def\font_basics_define_font_synonym_yes_expanded#crap[#spec]% + {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file + \normalexpanded{\font_basics_define_font_synonym_yes_opt[#spec]}} + +\unexpanded\def\font_basics_define_font_synonym_nop_opt[#specification]% + {\let\p_features \undefined + \let\p_fallbacks \undefined + \let\p_goodies \undefined + \let\p_designsize\undefined + \expandafter\font_basics_get_font_parameter_nop#specification,]=,} + +\unexpanded\def\font_basics_define_font_synonym_yes_opt[#specification]% + {\let\p_features \undefined + \let\p_fallbacks \undefined + \let\p_goodies \undefined + \let\p_designsize\undefined + \expandafter\font_basics_get_font_parameter_yes#specification,]=,} + +% todo: check if we can use \edef but then we need to protect \mathsizesuffix .. in fact that +% can be default then: \let\mathsizesuffix\relax .. i need to play with it first + +\def\font_basics_get_font_parameter_nop#key=#value,% + {\if]#key% + \font_basics_get_font_parameter_nop_finish + \else + \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix + \expandafter\font_basics_get_font_parameter_nop + \fi} + +\def\font_basics_get_font_parameter_yes#key=#value,% + {\if]#key% + \font_basics_get_font_parameter_yes_finish + \else + \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix + \expandafter\font_basics_get_font_parameter_yes + \fi} + +% helpers, some day these will be toks and counts + +% \def\fntsetdefname {\glet\somefontname\defaultfontfile} +% \def\fntsetsomename{\gdef\somefontname} % takes argument +% \def\fntsetnopsize {\let\somefontsize\empty} +% \def\fntsetsomesize{\def\somefontsize} % takes argument + +% happens later, else mkvi parsing gets into troubles + +% end of helpers + +% we could collect them in one macro (but no expansion) + +\def\font_basics_define_font_synonym_nop_nil + {\expandafter\let\csname\??fontfile\m_font_name\s!features \endcsname\undefined + \expandafter\let\csname\??fontfile\m_font_name\s!fallbacks \endcsname\undefined + \expandafter\let\csname\??fontfile\m_font_name\s!goodies \endcsname\undefined + \expandafter\let\csname\??fontfile\m_font_name\s!designsize\endcsname\undefined} + +\def\font_basics_define_font_synonym_yes_nil + {\expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!features \endcsname\undefined + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\undefined + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!goodies \endcsname\undefined + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\undefined} + +\def\font_basics_get_font_parameter_nop_finish + {\expandafter\let\csname\??fontfile\m_font_name\s!features \endcsname\p_features + \expandafter\let\csname\??fontfile\m_font_name\s!fallbacks \endcsname\p_fallbacks + \expandafter\let\csname\??fontfile\m_font_name\s!goodies \endcsname\p_goodies + \expandafter\let\csname\??fontfile\m_font_name\s!designsize\endcsname\p_designsize} + +\def\font_basics_get_font_parameter_yes_finish + {\expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!features \endcsname\p_features + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!fallbacks \endcsname\p_fallbacks + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!goodies \endcsname\p_goodies + \expandafter\glet\csname\??fontfile\fontclass\m_font_name\s!designsize\endcsname\p_designsize} + +%\definefontsynonym [KopFont] [\fontclassname{officina}{SerifBold}] +% +%\defineclassfontsynonym [KopFont] [officina] [SerifBold] + +\unexpanded\def\defineclassfontsynonym + {\dotripleargument\font_basics_define_class_font_synonym} + +%\definefontsynonym[#tag][\fontclassname{#class}{#fileortag}]} + +\def\font_basics_define_class_font_synonym[#tag][#class][#fileortag]% needs testing + {\expandafter\normaldef\csname\??fontfile\fontclass#tag\endcsname{\fontclassname{#class}{#fileortag}}% + \font_basics_define_font_synonym_yes_nil} + +\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater + +\unexpanded\def\setupfontsynonym + {\dodoubleempty\dosetupfontsynonym} + +\def\dosetupfontsynonym[#name][#settings]% not yet supported, will do when needed + {} + +% todo: replace * by ... less messy with features + +\def\truefontname#name% + {\expandafter\font_helpers_true_fontname#name*\empty*\relax} + +\def\font_helpers_true_fontname#name*#first#rest*#crap\relax + {\ifcsname\??fontfile\fontclass#name\endcsname + \ifx#first\empty + %\expandafter\truefontname\csname\??fontfile\fontclass#name\endcsname + \expandafter\truefontname\lastnamedcs + \else + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\fontclass#name\endcsname*#first#rest% + \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest% + \fi + \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname + \ifx#first\empty + %\expandafter\truefontname\csname\??fontfile\defaultfontclass#name\endcsname + \expandafter\truefontname\lastnamedcs + \else + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\defaultfontclass#name\endcsname*#first#rest% + \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest% + \fi + \orelse\ifcsname\??fontfile#name\endcsname + \ifx#first\empty + %\expandafter\truefontname\csname\??fontfile#name\endcsname + \expandafter\truefontname\lastnamedcs + \else + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile#name\endcsname*#first#rest% + \expandafter\font_helpers_true_fontname_check\lastnamedcs*#first#rest% + \fi + \else + #name\ifx#first\empty\else*#first#rest\fi + \fi} + +\def\font_helpers_true_fontname_check#name% + {\expandafter\font_helpers_true_fontname_check_indeed#name*\relax} + +\def\font_helpers_true_fontname_check_indeed#name*#crap\relax + {\ifcsname\??fontfile\fontclass#name\endcsname + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\fontclass#name\endcsname + \expandafter\font_helpers_true_fontname_check\lastnamedcs + \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile\defaultfontclass#name\endcsname + \expandafter\font_helpers_true_fontname_check\lastnamedcs + \orelse\ifcsname\??fontfile#name\endcsname + %\expandafter\font_helpers_true_fontname_check\csname\??fontfile#name\endcsname + \expandafter\font_helpers_true_fontname_check\lastnamedcs + \else + #name% + \fi} + +% ok when the last lookup is not stripped .. we need to be able to define synonyms for symbols +% +% \def\truefontname#name% +% %{\normalexpanded{\noexpand\font_helpers_true_fontname{\clf_truefontname{#name}}}} +% {\expandafter\expandafter\expandafter\font_helpers_true_fontname\expandafter\expandafter\expandafter{\clf_truefontname{#name}}} +% +% \def\font_helpers_true_fontname#name% +% {\ifcsname\??fontfile\fontclass#name\endcsname +% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}% +% \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname +% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}% +% \orelse\ifcsname\??fontfile#name\endcsname +% \expandafter\font_helpers_true_fontname\expandafter{\lastnamedcs}% +% \else +% % \clf_truefontname{#name}% +% #name% so the last one can have features ! +% \fi} + +\def\expandfontsynonym#command#name% one level expansion + {\ifcsname\??fontfile\fontclass#name\endcsname + %\expandafter\normaldef\expandafter#command\expandafter{\csname\??fontfile\fontclass#name\endcsname}% + \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}% + \orelse\ifcsname\??fontfile\defaultfontclass#2\endcsname + %\expandafter\normaldef\expandafter#command\expandafter{\csname\??fontfile\defaultfontclass#name\endcsname}% + \expandafter\normaldef\expandafter#command\expandafter{\lastnamedcs}% + \fi} + +\def\doifelsefontsynonym#name% + {\ifcsname\??fontfile\fontclass#name\endcsname + \expandafter\firstoftwoarguments + \orelse\ifcsname\??fontfile\defaultfontclass#name\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doiffontsynonymelse\doifelsefontsynonym + +%D \macros +%D {tracedfontname} +%D +%D A goody: + +\def\tracedfontname#name% + {#name\ifcsname\??fontfile\fontclass#name\endcsname + %\expandafter\tracedfontname\csname\??fontfile\fontclass#name\endcsname + \expandafter\tracedfontname\lastnamedcs + \orelse\ifcsname\??fontfile#name\endcsname + %\expandafter\tracedfontname\csname\??fontfile#name\endcsname + \expandafter\tracedfontname\lastnamedcs + \fi} + +%D \macros +%D {fontclass, defaultfontclass} +%D +%D The fontclass model was introduced a while after we implement the basic font +%D model and at that time we still defaulted to no model at all. Nowadays we default +%D to the \type {modern} fontclass. + +\let\fontclass \empty +\let\defaultfontclass\empty + +\def\fontclassname#class#name% tricky ... no lastnamedcs here due to nesting + {\ifcsname\??fontfile#class#name\endcsname + \fontclassname{#class}{\csname\??fontfile#class#name\endcsname}% + \orelse\ifcsname\??fontfile#name\endcsname + \fontclassname{#class}{\csname\??fontfile#name\endcsname}% + \else + #2% + \fi} + +\installmacrostack\fontclass + +%D Files or names can have properties and these need to be consulted at some point. +%D They can inherit them. + +% Why these expanded and rscale not ... maybe not worth the trouble (delayed +% expansion actually would be better i.e. macros in feature specs). Test +% without pre-expansion. + +\def\font_helpers_update_font_class_parameters + {\edef\m_font_class_direction {\begincsname\??fontclass\fontclass\fontstyle\s!direction \endcsname}% + \edef\m_font_class_features {\begincsname\??fontclass\fontclass\fontstyle\s!features \endcsname}% + \edef\m_font_class_fallbacks {\begincsname\??fontclass\fontclass\fontstyle\s!fallbacks \endcsname}% + \edef\m_font_class_goodies {\begincsname\??fontclass\fontclass\fontstyle\s!goodies \endcsname}% + \edef\m_font_class_designsize{\begincsname\??fontclass\fontclass\fontstyle\s!designsize\endcsname}} + +% resolve + +\def\font_helpers_set_features_yes#name% + {\ifcsname\??fontfile\fontclass#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse % class + symbolic_name + \ifcsname\??fontfile #name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse % symbolic_name + \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \orelse % class + parent_name + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_features_yes\lastnamedcs \else % parent_name + \let\m_font_features\empty\fi} + +\def\font_helpers_set_fallbacks_yes#name% + {\ifcsname\??fontfile\fontclass#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse + \ifcsname\??fontfile #name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse + \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \orelse + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_fallbacks_yes\lastnamedcs \else + \let\m_font_fallbacks\empty\fi} + +\def\font_helpers_set_goodies_yes#name% + {\ifcsname\??fontfile\fontclass#name\s!goodies \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse + \ifcsname\??fontfile #name\s!goodies \endcsname \edef\m_font_goodies{\lastnamedcs}\orelse + \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \orelse + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_goodies_yes\lastnamedcs \else + \let\m_font_goodies\empty\fi} + +\def\font_helpers_set_designsize_yes#name% + {\ifcsname\??fontfile\fontclass#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse + \ifcsname\??fontfile #name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse + \ifcsname\??fontfile\fontclass#name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \orelse + \ifcsname\??fontfile #name\endcsname \expandafter\font_helpers_set_designsize_yes\lastnamedcs \else + \let\m_font_designsize\empty\fi} + +\def\font_helpers_set_features_nop#name% + {\ifcsname\??fontfile#name\s!features\endcsname \edef\m_font_features{\lastnamedcs}\orelse + \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_features_nop\lastnamedcs \else + \let\m_font_features\empty\fi} + +\def\font_helpers_set_fallbacks_nop#name% + {\ifcsname\??fontfile#name\s!fallbacks\endcsname \edef\m_font_fallbacks{\lastnamedcs}\orelse + \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_fallbacks_nop\lastnamedcs \else + \let\m_font_fallbacks\empty\fi} + +\def\font_helpers_set_goodies_nop#name% + {\ifcsname\??fontfile#name\s!goodies\endcsname \edef\m_font_goodies{\lastnamedcs}\orelse + \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_goodies_nop\lastnamedcs \else + \let\m_font_goodies\empty\fi} + +\def\font_helpers_set_designsize_nop#name% + {\ifcsname\??fontfile#name\s!designsize\endcsname \edef\m_font_designsize{\lastnamedcs}\orelse + \ifcsname\??fontfile#name\endcsname \expandafter\font_helpers_set_designsize_nop\lastnamedcs \else + \let\m_font_designsize\empty\fi} + +\def\font_helpers_update_font_parameters_yes + {\font_helpers_set_features_yes \somefontname + \font_helpers_set_fallbacks_yes \somefontname + \font_helpers_set_goodies_yes \somefontname + \font_helpers_set_designsize_yes\somefontname} + +\def\font_helpers_update_font_parameters_nop + {\font_helpers_set_features_nop \somefontname + \font_helpers_set_fallbacks_nop \somefontname + \font_helpers_set_goodies_nop \somefontname + \font_helpers_set_designsize_nop\somefontname} + +\def\font_helpers_update_font_parameters + {\ifx\fontclass\empty\font_helpers_update_font_parameters_nop\else\font_helpers_update_font_parameters_yes\fi} + +\installcorenamespace{fontclass} + +% we can pack them (don't use \setxvalue!) + +\unexpanded\def\savefontclassparameters#style#rscale#features#fallbacks#goodies#designsize#direction% + {\letgvalue{\??fontclass\fontclass#style\s!rscale }#rscale% + \letgvalue{\??fontclass\fontclass#style\s!features }#features% + \letgvalue{\??fontclass\fontclass#style\s!fallbacks }#fallbacks% + \letgvalue{\??fontclass\fontclass#style\s!goodies }#goodies% + \letgvalue{\??fontclass\fontclass#style\s!designsize}#designsize% + \letgvalue{\??fontclass\fontclass#style\s!direction }#direction}% math + +% bonus + +\let\currentfontinstancespec\clf_currentfontinstancespec % expandable + +\protect \endinput diff --git a/tex/context/base/mkiv/font-fil.mkvi b/tex/context/base/mkiv/font-fil.mkvi index ae83ef4c4..8622e733f 100644 --- a/tex/context/base/mkiv/font-fil.mkvi +++ b/tex/context/base/mkiv/font-fil.mkvi @@ -15,11 +15,10 @@ \unprotect -%D Personally I think that using \TEX\ macro packages is -%D complicated by the way fonts are handled. Apart from the -%D many encodings, we also deal with different naming schemes. -%D Confronted with this problem, I decided to change the -%D definitions into: +%D Personally I think that using \TEX\ macro packages is complicated by the way +%D fonts are handled. Apart from the many encodings, we also deal with different +%D naming schemes. Confronted with this problem, I decided to change the definitions +%D into: %D %D \starttyping %D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt] @@ -307,10 +306,9 @@ %D \macros %D {fontclass, defaultfontclass} %D -%D The fontclass model was introduced a while after we implement -%D the basic font model and at that time we still defaulted to -%D no model at all. Nowadays we default to the \type {modern} -%D fontclass. +%D The fontclass model was introduced a while after we implement the basic font +%D model and at that time we still defaulted to no model at all. Nowadays we default +%D to the \type {modern} fontclass. \let\fontclass \empty \let\defaultfontclass\empty @@ -326,8 +324,8 @@ \installmacrostack\fontclass -%D Files or names can have properties and these need to be consulted -%D at some point. They can inherit them. +%D Files or names can have properties and these need to be consulted at some point. +%D They can inherit them. % Why these expanded and rscale not ... maybe not worth the trouble (delayed % expansion actually would be better i.e. macros in feature specs). Test diff --git a/tex/context/base/mkiv/font-ini.mklx b/tex/context/base/mkiv/font-ini.mklx new file mode 100644 index 000000000..4b112322d --- /dev/null +++ b/tex/context/base/mkiv/font-ini.mklx @@ -0,0 +1,2563 @@ +%D \module +%D [ file=font-ini, +%D version=1998.09.11, % (second) +%D version=2001.02.20, % (third) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +% todo: < 3 pt => 3pt +% todo: check where more class usage +% todo: split font-nam (style/alternative/size) +% todo: split font-dim (scales etc) +% todo: reconsider defaultfontclass +% + +%D Watch out: as we define inside macros in sometimes special ways, +%D an occasional \type {\normaldef} is used in order to please the +%D \MKVI\ parser. + +%D Beware, we use a special set of parameters here: +%D +%D \starttabulate[|l|l|] +%D \NC system variable (fixed) \NC \type {\s!text} \NC \NR +%D \NC system variable (fixed) \NC \type {\s!script} \NC \NR +%D \NC system variable (fixed) \NC \type {\s!scriptscript} \NC \NR +%D \NC system variable (fixed) \NC \type {\s!x} \NC \NR +%D \NC system variable (fixed) \NC \type {\s!xx} \NC \NR +%D \NC variable (value) \NC \type {\v!big} \NC \NR +%D \NC variable (value) \NC \type {\v!small} \NC \NR +%D \NC constant (regular key) \NC \type {\c!interlinespace} \NC \NR +%D \NC constant (regular key) \NC \type {\c!em} \NC \NR +%D \stoptabulate +%D +%D The math related ones are similar to the ones used in \TEX\ itself, +%D the size related ones show up as keywords in the user interface +%D when switching sizes, and the two constants are used in key|/|value +%D situations. + +%D We should consider design sizes ... maybe kick 'm out which removes +%D the size code and simplifies things considerably. After all, there +%D will be no latin modern math in sizes. + +\writestatus{loading}{ConTeXt Font Macros / Initialization} + +%D Documentation is somewhat messy as it contains bits and pieces of +%D previous versions. + +\unprotect + +%D There are several ways to specify a font. Three of them are pure \TEX\ ones, the +%D fourth one is new: +%D +%D \starttyping +%D \font\name=cmr12 +%D \font\name=cmr12 at 10pt +%D \font\name=cmr12 scaled 2 +%D \font\name=cmr12 sa 1.440 +%D \stoptyping +%D +%D The non||\TEX\ alternative \type{sa} stands for {\em scaled at}. This means as +%D much as: scale the bodyfontsize with this factor. The scaled option is not that +%D useful as one needs to know the design size. +%D +%D Because \type {sa} (scaled at) and \type {mo} (mapped on) are not low level \TEX\ +%D supported alternatives, we have to test for it ourselves. In doing so, we need an +%D auxiliary \DIMENSION. We cannot use \type{\scratchdimen} because font loading can +%D happen at any moment due to postponed loading. We could instead have used dirty +%D grouping tricks, but this one works too. + +% \enableexperiments[fonts.autorscale] +% +% \starttypescript[mscore] +% \definetypeface [mscore] [rm] [serif] [mscoretimes] [default] +% \definetypeface [mscore] [ss] [sans] [mscorearial] [default] [rscale=auto] % 0.860] +% \definetypeface [mscore] [tt] [mono] [mscorecourier] [default] [rscale=auto] % 1.065] +% \definetypeface [mscore] [mm] [math] [times] [default] [rscale=auto] % 1.020] +% \stoptypescript +% +% \starttext +% \setupbodyfont[mscore,12pt] +% \startTEXpage +% test \ss test \tt test +% \stopTEXpage +% \stoptext + +% \definetypeface[one][rm][serif][computer-roman][default] +% \definetypeface[two][rm][serif][computer-roman][default][rscale=.9] +% +% {\one \bf test \two test} +% {\one \bf test \pushcurrentfont \two \popcurrentfont test} + +%D \macros +%D {rm,ss,tt,hw,cg} +%D +%D Fonts are defined in separate files. When we define a font, we distinguish +%D between several styles. In most cases we will use: +%D +%D \startlinecorrection +%D \starttable[|l||] +%D \HL +%D \NC roman regular serif \NC \type{\rm} \NC\FR +%D \NC sansserif sans support \NC \type{\ss} \NC\MR +%D \NC type teletype mono \NC \type{\tt} \NC\LR +%D \HL +%D \stoptable +%D \stoplinecorrection +%D +%D The number of styles is not limited to these three. When using Lucida Bright we +%D can for instance also define: +%D +%D \startlinecorrection +%D \starttable[|l||] +%D \HL +%D \NC handwritten \NC \type{\hw} \NC\FR +%D \NC calligraphic \NC \type{\cg} \NC\LR +%D \HL +%D \stoptable +%D \stoplinecorrection +%D +%D Within such a font set (\type{cmr}) and style (\type{\rm}) we can define a number +%D of text font alternatives: +%D +%D \startlinecorrection +%D \starttable[|l||] +%D \HL +%D \NC typeface \NC \type{\tf} \NC\FR +%D \NC boldface \NC \type{\bf} \NC\MR +%D \NC slanted \NC \type{\sl} \NC\MR +%D \NC italic \NC \type{\it} \NC\MR +%D \NC boldslanted \NC \type{\bs} \NC\MR +%D \NC bolditalic \NC \type{\bi} \NC\MR +%D \NC smallcaps \NC \type{\sc} \NC\LR +%D \HL +%D \stoptable +%D \stoplinecorrection +%D +%D Internally fonts are stored as combination of size, style +%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}. Users are not confronted +%D with sizes, but use the style or style+alternative to activate them. +%D +%D During the definition of a bodyfont one can also declare the available larger +%D alternatives: +%D +%D \starttyping +%D \tf \tfa \tfb \tfc ... +%D \bf \bfa \bfb \bfc ... +%D \sl \sla \slb \slc ... +%D \stoptyping +%D +%D The smaller ones are automatically supplied and derived from +%D the the bodyfont environment. +%D +%D \starttyping +%D \tfx \tfxx +%D \bfx \bfxx +%D \slx \slxx +%D \stoptyping +%D +%D There are only two smaller alternatives per style. The larger alternatives on the +%D other hand have no limitations. +%D +%D These larger alternatives are mostly used in chapter and section titles or on +%D title pages. When one switches to a larger alternative, the bold an other ones +%D automatically adapt themselves: +%D +%D \startbuffer +%D \tfd Hi \bf there\sl, here \tfb I \bf am +%D \stopbuffer +%D +%S \startnarrower +%D \typebuffer +%S \stopnarrower +%D +%D therefore becomes: +%D +%D \startexample +%D \getbuffer +%D \stopexample +%D +%D Maybe this mechanism isn't always as logic, but as said before, we tried to make +%D it as intuitive as possible. +%D +%D So a specific kind of glyph can be characterized by: +%D +%D \startnarrower +%D family (cmr) + bodyfont (12pt) + style (rm) + alternative (bf) + size (a) +%D \stopnarrower +%D +%D The last component (the size) is optional. +%D +%D We introduced \type {\tf} as command to call for the current normally sized +%D typeface. This commands results in roman, sans serif, teletype or whatever style +%D is in charge. Such rather massive switches of style sometimes take more +%D processing time than comfortable. Of course there is a workaround for this: we +%D can call fonts directly by means of commands like: +%D +%D \starttyping +%D \rmtf \sssl \tttf \rmbsa +%D \stoptyping +%D +%D One should realize that this fast calls have limitations, they lack for instance +%D automatic super- and subscript support. +%D +%D This leaves us two more commands: \type {\tx} and \type {\txx}. These activate a +%D smaller and even more smaller font than the current one and adapt themselves to +%D the current alternative, so when \type {\bf} is active, \type {\tx} gives a +%D smaller boldface, which in turn can be called directly by \type {\bfx}. +%D +%D These two smaller alternatives are specified by the bodyfont environment and +%D therefore not necessarily have similar sizes as \type {\scriptsize} and \type +%D {\scriptscriptsize}. The main reason for this incompatibility (which can easily +%D be undone) lays in the fact that we often want a bit bigger characters than in +%D math mode. In \CONTEXT\ for instance the \type {\tx} and \type {\txx} commands +%D are used for surrogate \cap {smallcaps} which support both nesting and +%D alternatives, like in {\bf \cap {a \cap {small} world}}, which was typeset by +%D +%D \starttyping +%D \bf\cap{a \cap{small} world} +%D \stoptyping +%D +%D And compare $\rm \scriptstyle THIS$ with the slightly larger \cap {THIS}: +%D \ruledhbox {$\rm \scriptstyle scriptstyle: THIS$} or \ruledhbox {\cap {x style: +%D THIS}} makes a big difference. +%D +%D The \type {x..d} sizes should be used grouped. If you don't group them, i.e. call +%D them in a row, \CONTEXT\ will not be able to sort out your intention (\type {x} +%D inside \type {d} inside \type {x}. etc.). The following table demonstrates this: +%D +%D \def\FontState{\setstrut\ruledhbox{\strut Hello}} +%D +%D \starttabulate[|||||] +%D \HL +%D \NC \rlap{\quad\bf grouped} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR +%D \HL +%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR +%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR +%D \NC \type{\tf} \NC \tf \FontState \NC \tf \tx \FontState \NC \tf \txx \FontState \NC \NR +%D \NC \type{\tfa} \NC \tfa \FontState \NC \tfa \tx \FontState \NC \tfa \txx \FontState \NC \NR +%D \NC \type{\tfb} \NC \tfb \FontState \NC \tfb \tx \FontState \NC \tfb \txx \FontState \NC \NR +%D \NC \type{\tfc} \NC \tfc \FontState \NC \tfc \tx \FontState \NC \tfc \txx \FontState \NC \NR +%D \NC \type{\tfd} \NC \tfd \FontState \NC \tfd \tx \FontState \NC \tfd \txx \FontState \NC \NR +%D \NC \type{\tfx} \NC \tfx \FontState \NC \tfx \tx \FontState \NC \tfx \txx \FontState \NC \NR +%D \NC \type{\tfxx} \NC \tfxx \FontState \NC \tfxx\tx \FontState \NC \tfxx\txx \FontState \NC \NR +%D \HL +%D \stoptabulate +%D +%D \blank +%D +%D \starttabulate[|||||] +%D \HL +%D \NC \rlap{\quad\bf stacked} \NC \NC \type {\tx} \NC \type {\txx} \NC \NR +%D \HL +%D \NC \type{\tfx} +%D \NC \tfx \FontState +%D \NC \tfx \tx \FontState +%D \NC \tfx \txx \FontState +%D \NC \NR +%D \NC \type{\tfxx} +%D \NC \tfx\tfxx \FontState +%D \NC \tfx\tfxx \tx \FontState +%D \NC \tfx\tfxx \txx \FontState +%D \NC \NR +%D \NC \type{\tf} +%D \NC \tfx\tfxx\tf \FontState +%D \NC \tfx\tfxx\tf \tx \FontState +%D \NC \tfx\tfxx\tf \txx \FontState +%D \NC \NR +%D \NC \type{\tfa} +%D \NC \tfx\tfxx\tf\tfa \FontState +%D \NC \tfx\tfxx\tf\tfa \tx \FontState +%D \NC \tfx\tfxx\tf\tfa \txx \FontState +%D \NC \NR +%D \NC \type{\tfb} +%D \NC \tfx\tfxx\tf\tfa\tfb \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb \tx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb \txx \FontState +%D \NC \NR +%D \NC \type{\tfc} +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \tx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc \txx \FontState +%D \NC \NR +%D \NC \type{\tfd} +%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \tx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfd \txx \FontState +%D \NC \NR +%D \NC \type{\tfx} +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \tx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx \txx \FontState +%D \NC \NR +%D \NC \type{\tfxx} +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \tx \FontState +%D \NC \tfx\tfxx\tf\tfa\tfb\tfc\tfx\tfxx \txx \FontState +%D \NC \NR +%D \HL +%D \stoptabulate + +\fontslantperpoint \nullfont 0\scaledpoint +\fontinterwordspace \nullfont 256377\scaledpoint +\fontinterwordstretch\nullfont 128188\scaledpoint +\fontinterwordshrink \nullfont 85459\scaledpoint +\fontexheight \nullfont 338952\scaledpoint +\fontemwidth \nullfont 786432\scaledpoint +\fontextraspace \nullfont 85459\scaledpoint + +\appendtoks + \fontslantperpoint \nullfont 0\scaledpoint + \fontinterwordspace \nullfont 256377\scaledpoint + \fontinterwordstretch\nullfont 128188\scaledpoint + \fontinterwordshrink \nullfont 85459\scaledpoint + \fontexheight \nullfont 338952\scaledpoint + \fontemwidth \nullfont 786432\scaledpoint + \fontextraspace \nullfont 85459\scaledpoint +\to \everyjob + +%D Tracing + +\newtoks\t_font_tracers_definitions + +\unexpanded\def\tracefontdefinitions + {\the\t_font_tracers_definitions} + +%D Some housekeeping macros: + +\unexpanded\def\setfontparameters + {\setfalse\c_font_synchronize + \the\everybodyfont + \settrue\c_font_synchronize} + +\let\savedfont\empty + +\installmacrostack\savedfont + +\unexpanded\def\savefont + {\edef\savedfont{\the\font}% gives \csname + \push_macro_savedfont} + +\unexpanded\def\restorefont + {\pop_macro_savedfont + \savedfont} + +\unexpanded\def\pushcurrentfont + {\edef\popcurrentfont + {\def\noexpand\fontbody {\fontbody}% + \def\noexpand\fontstyle {\fontstyle}% + \def\noexpand\fontalternative{\fontalternative}% + \def\noexpand\fontsize {\fontsize}% + \font_helpers_check_big_math_synchronization + \font_helpers_synchronize_font}} + +%D \macros{definedfont} + +\let\thedefinedfont\relax % not to be confused with \everydefinefont + +\unexpanded\def\definedfont + {\doifelsenextoptionalcs\font_basics_defined_font_yes\font_basics_defined_font_nop} + +\def\font_basics_defined_font_yes[#specification]% + {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly + \font_basics_define_font_without_parameters{thedefinedfont}{#specification}% + \thedefinedfont + \the\everydefinedfont} + +\def\font_basics_defined_font_nop + {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly + \thedefinedfont + \the\everydefinedfont} + +%D \macros{startfont} + +\unexpanded\def\startfont{\begingroup\definedfont} +\unexpanded\def\stopfont {\endgroup} + +%D \macros +%D {everybodyfont,everyglobalbodyfont} +%D +%D Every change in bodyfont size has conseqences for the baseline distance and skips +%D between paragraphs. These are initialized in other modules. Here we only provide +%D the hooks that garantees their handling. +%D +%D At the system level one can initialize thing like: +%D +%D \starttyping +%D \appendtoks \setupspacing \to \everybodyfont +%D \stoptyping + +%D \macros +%D {globalbodyfontsize,localbodyfontsize,bodyfontsize} +%D +%D Here we have to distinguish between the global (overal) bodyfont size and the +%D local (sometimes in the textflow) size. We store these dimensions in two +%D \DIMENSION\ registers. These registers are not to be misused in calculations. + +\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt +\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize +\ifdefined\bodyfontsize \else \newdimen\bodyfontsize \fi \bodyfontsize =\globalbodyfontsize + +%D When we assign for instance 12pt to a \DIMENSION\ register the \type {\the}'d +%D value comes out as 12.0pt, which is often not the way users specify the bodyfont +%D size. Therefore we use normalized values. They are cached to save overhead in +%D \LUA\ calls. + +\installcorenamespace{fontnormalizedbody} + +\def\normalizebodyfontsize#macro#body% + {\expandafter\let\expandafter#macro\csname\??fontnormalizedbody\number\dimexpr#body\endcsname + \ifx#macro\relax + \normalizebodyfontsize_indeed#macro{#body}% + \fi} + +\def\normalizebodyfontsize_indeed#macro#body% + {\edef#macro{\clf_nbfs\dimexpr#body\relax}% + \expandafter\glet\csname\??fontnormalizedbody\number\dimexpr#body\endcsname#macro} + +\def\thenormalizedbodyfontsize#body% + {\clf_nbfs\dimexpr#body\relax} + +\edef\normalizedglobalbodyfontsize{\thenormalizedbodyfontsize\bodyfontsize} +\edef\normalizedlocalbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize} +\edef\normalizedbodyfontsize {\thenormalizedbodyfontsize\bodyfontsize} + +%D \macros +%D {mapfontsize} +%D +%D For special purposes, like in math, you may want to use slightly different sizes +%D than the ones given. This happens for instance with the Math Times fonts. Mapped +%D font sizes can be specified by using the \type {mo} key instead of \type {sa} in +%D font definitions. +%D +%D \startbuffer +%D \mapfontsize[10pt][11pt] +%D \mapfontsize[11pt][12pt] +%D \mapfontsize[12pt][13pt] +%D +%D \definefont[test][Serif]\test TEST \par +%D \definefont[test][Serif sa 5]\test TEST \par +%D \definefont[test][Serif mo 5]\test TEST \par +%D \definefont[test][Serif sa d]\test TEST \par +%D \definefont[test][Serif at 60pt]\test TEST \par +%D \definefont[test][Serif scaled 6000]\test TEST \par +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startpacked +%D \getbuffer +%D \stoppacked + +\installcorenamespace{mappedfontsize} + +\unexpanded\def\mapfontsize + {\dodoubleargument\font_basics_map_fontsize} + +\def\font_basics_map_fontsize[#from][#to]% + {\setvalue{\??mappedfontsize\the\dimexpr#from\relax}{#to}} + +\def\font_basics_set_mapped_fontsize#from% + {\ifcsname\??mappedfontsize\the\dimexpr#from\relax\endcsname + \lastnamedcs\else#from% + \fi} + +\installcorenamespace{fontbodyknown} +\installcorenamespace{fontclassyes} % fontclass +\installcorenamespace{fontclassnop} % nofontclass + +\def\font_helpers_process_relative_size_list#command% could be a toks + {#command\v!big + #command\v!small} + +\let\v_font_size_relative \plusone +\def\v_font_size_absolute {\fontbody} + +\let\v_font_rscale_default\!!plusone +\let\p_font_rscale \v_font_rscale_default + +\def\font_helpers_check_relative_font_id % can be plugged in later + {\let\p_font_rscale\minusone + \let\p_font_rscale\v_font_rscale_default} + +\def\font_helpers_check_relative_font_size#style% + {\edef\p_font_rscale + {\ifcsname\??fontclass\fontclass#style\s!rscale\endcsname + \lastnamedcs + \orelse\ifcsname\??fontclass\defaultfontclass#style\s!rscale\endcsname % brr + \lastnamedcs + \else + \v_font_rscale_default + \fi}% + % move elsewhere + \ifx\p_font_rscale\v!auto + \let\p_font_rscale\plusone + \font_helpers_check_relative_font_id + \else + \let\relativefontid\minusone + \fi} + +\def\font_rscale_xx#style% + {\ifcsname\??fontclass\fontclass#style\s!rscale\endcsname + \lastnamedcs + \else + \v_font_rscale_default + \fi} + +\def\font_rscale_mm + {\ifcsname\??fontclass\fontclass\s!mm\s!rscale\endcsname + \lastnamedcs + \else + \v_font_rscale_default + \fi} + +\def\font_helpers_register_fontbody#body% + {\expandafter\let\csname\??fontbodyknown#body\endcsname\empty} + +%D \macros +%D {definefontstyle,definefontsize,definefontalternative} +%D +%D When setting of switching the overall style we can use the short identifier like +%D rm and ss, but when defined we can also use more verbose names like roman or +%D sansserif. Such names are defined by: +%D +%D \starttyping +%D \definefontstyle [serif,rm] [rm] +%D \definefontstyle [sansserif,ss] [ss] +%D \stoptyping + +\installcorenamespace{fontstyle} % full style prefix (roman etc) +\installcorenamespace{fontshortstyle} % short style prefix (rm etc) + +\installcorenamespace{fontstyleknown} +\installcorenamespace{fontalternativeknown} +\installcorenamespace{fontsizeknown} + +\newtoks\t_font_style_commands +\newtoks\t_font_size_commands +\newtoks\t_font_alternative_commands + +\setnewmacro\m_font_style_command \gobbleoneargument +\setnewmacro\m_font_size_command \gobbleoneargument +\setnewmacro\m_font_alternative_command\gobbleoneargument + +\def\font_helpers_process_style_list #command{\def\m_font_style_command {#command}\the\t_font_style_commands} +\def\font_helpers_process_size_list #command{\def\m_font_size_command {#command}\the\t_font_size_commands} +\def\font_helpers_process_alternative_list#command{\def\m_font_alternative_command{#command}\the\t_font_alternative_commands} + +\def\font_helpers_register_style #style{\expandafter\let\csname\??fontstyleknown #style\endcsname\empty} +\def\font_helpers_register_size #size{\expandafter\let\csname\??fontsizeknown #size\endcsname\empty} +\def\font_helpers_register_alternative#alternative{\expandafter\let\csname\??fontalternativeknown#alternative\endcsname\empty} + +\unexpanded\def\definefontstyle + {\dodoubleargument\font_basics_define_fontstyle} + +\def\font_basics_define_fontstyle[#commands][#style]% style: rm ss tt ... + {\ifcsname\??fontstyleknown#style\endcsname \else % can be delayed till used (cg, hw) + \font_helpers_register_style{#style}% + \toksapp\t_font_style_commands{\m_font_style_command{#style}}% + \fi + \processcommalist[#commands]{\font_basics_define_fontstyle_indeed{#style}}} + +\def\font_basics_define_fontstyle_indeed#style#command% + {\setvalue{\??fontshortstyle#command}{#style}% + \setvalue{\??fontstyle #command}{\csname#style\endcsname}} + +\unexpanded\def\definefontsize[#size]% + {\ifcsname\??fontsizeknown#size\endcsname \else + \font_helpers_register_size{#size}% + \toksapp\t_font_size_commands{\m_font_size_command{#size}}% + \fi + \font_helpers_check_fontname_combinations} + +\unexpanded\def\definefontalternative[#alternative]% + {\ifcsname\??fontalternativeknown#alternative\endcsname \else + \font_helpers_register_alternative{#alternative}% + \toksapp\t_font_alternative_commands{\m_font_alternative_command{#alternative}}% + \fi + \font_helpers_check_fontname_combinations} + +\unexpanded\def\font_helpers_check_fontname_combinations % we need to split math and text here ... todo (math only has mr and mb) + {\font_helpers_process_style_list\font_helpers_check_fontname_combinations_s} + +\def\font_helpers_check_fontname_combinations_s#style% + {\font_helpers_process_alternative_list{\font_helpers_check_fontname_combinations_indeed_s_a{#style}}} + +\def\font_helpers_check_fontname_combinations_indeed_s_a#style#alternative% + {\font_helpers_process_size_list{\font_basics_check_fontname_combination{#style}{#alternative}}} + +\definefontstyle [\s!mm] [\s!mm] +\definefontstyle [\s!rm] [\s!rm] +\definefontstyle [\s!ss] [\s!ss] +\definefontstyle [\s!tt] [\s!tt] + +%D We define all the font switching commands globally. After all they are part of +%D the formal font interface once defined. The size can be empty (so checking is +%D needed as \type {\bf} is already defined). +%D +%D The \type {\normal..} variants are available as extras for cases where the \type +%D {..} is overloaded. + +\newmacro\m_font_mm + +\def\font_basics_check_fontname_combination#style% alternative size + {\edef\m_font_mm{#style}% + \ifx\m_font_mm\s!mm % prevents \max and alike (re)defs + \expandafter\font_basics_check_math_bodyfont + \else + \expandafter\font_basics_check_text_bodyfont + \fi{#style}} % no \m_font_mm, not expanded later on + +\def\font_basics_check_math_bodyfont#style#alternative#size% + {} + +\def\font_basics_check_text_bodyfont_step#whatever#body% size can be empty (checking needed as \bf is already defined) + {\ifcsname#whatever\endcsname\else + \setugvalue{#whatever}{#body}% + \fi} + +\def\font_basics_check_text_bodyfont#style#alternative#size% size can be empty (checking needed as \bf is already defined) + {\font_basics_check_text_bodyfont_step{#style#size}{\font_helpers_set_current_font_style_size{#style}{#size}}% \rma + \font_basics_check_text_bodyfont_step{#alternative#size}{\font_helpers_set_current_font_alternative_size{#alternative}{#size}}% \sla + \font_basics_check_text_bodyfont_step{#style#alternative#size}{\font_helpers_set_current_font_style_alternative_size{#style}{#alternative}{#size}}% \rmsla + \font_basics_check_text_bodyfont_step{#style}{\font_helpers_set_current_font_style{#style}}% \rm + \font_basics_check_text_bodyfont_step{#alternative}{\font_helpers_set_current_font_alternative{#alternative}}% \sl + \font_basics_check_text_bodyfont_step{#style\s!x }{\font_helpers_set_current_font_x_style_alternative{#style}}% \rmx + \font_basics_check_text_bodyfont_step{#style\s!xx}{\font_helpers_set_current_font_xx_style_alternative{#style}}% \rmxx + \font_basics_check_text_bodyfont_step{#alternative\s!x }{\font_helpers_set_current_font_x_alternative{#alternative}}% \slx + \font_basics_check_text_bodyfont_step{#alternative\s!xx}{\font_helpers_set_current_font_xx_alternative{#alternative}}% \slxx + \font_basics_check_text_bodyfont_step{#style#alternative}{\font_helpers_set_current_font_style_alternative{#style}{#alternative}}}% \rmsl + +%D Scaling macros: +%D +%D This system is somewhat complicated by two (possible conflicting) demands: +%D +%D \startitemize +%D \item We support wildcards like \type {sa *} which will adapt to the current +%D size. This is also the default specification. +%D \item We support named scales like \type {sa d}; beware: \type {x} and \type {xx} +%D are valid scales but they are not alway the same as the ones used in for +%D instance \type {\bfx} because there the sized come from the bodyfont +%D environment. In the future there maybe a switch that also honors the +%D environment in named scales. +%D \stopitemize +%D +%D Keep in mind that the smaller sizes are just for text super and subscripts while +%D larger sizes can be used in titles where for instance math follows the size. + +% b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par +% 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par +% x:x{\definedfont[SerifBold sa x]x}{\bfx x $x^x$}\par +% xx:x{\definedfont[SerifBold sa xx]x}{\bfxx x $x^x$}\par +% +% *:x{\definedfont[Serif sa *]x}\par +% 1:x{\definedfont[Serif sa 1]x}\par +% 2:x{\definedfont[Serif sa 2]x}\par +% 3:x{\definedfont[Serif sa 3]x}\par +% 4:x{\definedfont[Serif sa 4]x}\par +% 5:x{\definedfont[Serif sa 5]x}\par + +\def\safontscale{\number\dimexpr\v_font_size_absolute\relax} +\def\mofontscale{\number\dimexpr\font_basics_set_mapped_fontsize\v_font_size_absolute\relax} + +\let\somefontname\s!unknown +\let\somefontspec\s!unknown +\let\somefontsize\zerocount + +\newcount\scaledfontmode % also used at the lua end +\newcount\scaledfontsize % also used at the lua end +\newcount\lastfontid % also used at the lua end / tex end +\newtoks \everydefinefont + +\let\relativefontid\minusone % todo, not yet used + +\let\c_font_feature_inheritance_fontnone \zerocount % none +\let\c_font_feature_inheritance_fontonly \plusone % fontonly +\let\c_font_feature_inheritance_classonly \plustwo % classonly +\let\c_font_feature_inheritance_fontfirst \plusthree % fontfirst +\let\c_font_feature_inheritance_classfirst\plusfour % classfirst + +\let\c_font_feature_inheritance_default \c_font_feature_inheritance_fontfirst + +\setnewconstant\c_font_feature_inheritance_mode \c_font_feature_inheritance_default + +\newdimen \d_font_scaled_text_face +\newdimen \d_font_scaled_font_size +\newconditional\c_font_body_scale +\newfraction \f_font_body_scale + +\unexpanded\def\font_helpers_low_level_define#specification#csname% + {% we can now set more at the lua end + \glet\somefontname\defaultfontfile + \let\somefontsize\empty + \clf_definefont_one{\detokenize\expandafter{\normalexpanded{#specification}}}% the escapestring catches at \somedimen + % sets \scaledfontmode and \somefontname and \somefontsize + \ifcase\fontface\relax + % \let\v_font_size_absolute\textface % fontbody + \or + \let\v_font_size_absolute\textface + \or + \let\v_font_size_absolute\scriptface + \or + \let\v_font_size_absolute\scriptscriptface + \or + \let\v_font_size_absolute\xtextface + \or + \let\v_font_size_absolute\xxtextface + \fi + % + \ifcase\scaledfontmode\relax + % none, avoid the designsize if possible + \d_font_scaled_font_size-\plusthousand\scaledpoint + \or + % at + \d_font_scaled_font_size\somefontsize + \or + % sa + \d_font_scaled_font_size\v_font_size_absolute\relax + \d_font_scaled_font_size\currentfontbodysize\d_font_scaled_font_size % uses \somefontsize set by lua + \or + % mo + \d_font_scaled_font_size\font_basics_set_mapped_fontsize\v_font_size_absolute + \d_font_scaled_font_size\currentfontbodysize\d_font_scaled_font_size + \or + % scaled, don't use this one as it's unpredictable + \d_font_scaled_font_size-\somefontsize\scaledpoint + \else % ht cp + % experiment, yet undocumented + \d_font_scaled_font_size\somefontsize + \fi + \relax + \d_font_scaled_font_size\v_font_size_relative\d_font_scaled_font_size + \ifconditional\c_font_auto_size + \font_helpers_check_body_scale\fontsize + \ifconditional\c_font_body_scale + \d_font_scaled_font_size\f_font_body_scale\d_font_scaled_font_size + \d_font_scaled_text_face\f_font_body_scale\dimexpr\textface\relax + \else + \d_font_scaled_font_size\f_font_body_scale + \d_font_scaled_text_face\textface + \fi + \else + \d_font_scaled_text_face\textface + \fi + \edef\somefontspec{at \number\d_font_scaled_font_size sp}% + \edef\somefontfile{\truefontname\somefontname}% + \ifx\somefontfile\s!unknown + \edef\somefontfile{\defaultfontfile}% + \fi + \font_helpers_update_font_parameters + \font_helpers_update_font_class_parameters + %\writestatus{fonts}{low level define: #csname/\somefontfile/\number\d_font_scaled_font_size/\fontface/\number\d_font_scaled_text_face}% + \clf_definefont_two + \ifx\fontclass\empty\s!false\else\s!true\fi + {#csname}% + {\somefontfile}% + \d_font_scaled_font_size + \c_font_feature_inheritance_mode + {\m_font_class_features}% + {\m_font_features}% + {\m_font_class_fallbacks}% + {\m_font_fallbacks}% + \fontface + \d_font_scaled_text_face + \relativefontid + {\m_font_class_goodies}% + {\m_font_goodies}% + {\m_font_class_designsize}% + {\m_font_designsize}% + \scaledfontmode + \relax + \ifcase\scaledfontsize + %\scaledfontsize\plusone + \let\somefontspec\empty + \let\lastrawfontcall\relax + \expandafter\let\csname#csname\endcsname\relax + \else + \edef\somefontspec{at \number\scaledfontsize sp}% we need the resolved designsize (for fallbacks) + \expandafter\let\expandafter\lastrawfontcall\csname#csname\endcsname + \the\everydefinefont + \fi + \c_font_feature_inheritance_mode\c_font_feature_inheritance_default} + +\def\font_helpers_check_body_scale#fontsize% gets character (x xx a etc) + {\ifcsname\??fontenvironments\fontclass\fontbody#fontsize\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \setfalse\c_font_body_scale % ! + \orelse\ifcsname\??fontenvironments\fontclass\s!default#fontsize\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \settrue\c_font_body_scale + \orelse\ifcsname\??fontenvironments\fontbody#fontsize\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \setfalse\c_font_body_scale % ! + \orelse\ifcsname\??fontenvironments\s!default#fontsize\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \settrue\c_font_body_scale + \orelse\ifcsname\??fontenvironments\fontclass\s!default\s!text\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \settrue\c_font_body_scale + \orelse\ifcsname\??fontenvironments\s!default\s!text\endcsname + \expandafter\let\expandafter\f_font_body_scale\lastnamedcs + \settrue\c_font_body_scale + \else + \let\f_font_body_scale\plusone + \settrue\c_font_body_scale + \fi} + +%D The following macros are used at the \LUA\ end. Watch the \type {\normal} +%D hackery: this makes the mkvi parser happy. + +% \normaldef\fntsetdefname {\glet\somefontname\defaultfontfile} % do before calling +% \normaldef\fntsetnopsize {\let\somefontsize\empty} % do before calling +% \normaldef\fntsetsomename{\normalgdef\somefontname} % takes argument +% \normaldef\fntsetsomesize{\normaldef\somefontsize} % takes argument + +\newif\ifskipfontcharacteristics \skipfontcharacteristicstrue + +\tracingfonts\plussix % + +%D When fontclasses are used, we define the font global, since namespaces are +%D used. Otherwise we parse the specs each time. + +\let\fontfile\s!unknown + +%D Relatively new: + +\installcorenamespace{fonts} +\installcorenamespace{fontslanguage} + +\installsetuponlycommandhandler \??fonts {fonts} + +\newconstant\c_fonts_auto_language + +\letvalue{\??fontslanguage\v!auto}\plusone % experimental +%letvalue{\??fontslanguage\v!yes }\plustwo % less efficient, for experiments + +\appendtoks + \c_fonts_auto_language + \ifcsname\??fontslanguage\fontsparameter\c!language\endcsname + \lastnamedcs + \else + \zerocount + \fi +\to \everysetupfonts + +\appendtoks + \ifcase\c_fonts_auto_language + % nothing + \or + \addfflanguage + % \or + % font + \fi +\to \everylanguage + +% \setupfonts +% [\c!language=\v!auto] + +%D \macros +%D {everyfont,everyfontswitch} + +\ifdefined\everyfont \else \newtoks\everyfont \fi +\ifdefined\everyfontswitch \else \newtoks\everyfontswitch \fi + +\def\setfontcharacteristics{\the\everyfont} + +% \appendtoks +% \ifcase\c_fonts_auto_language +% % nothing +% \or +% % auto +% \or +% \addfflanguage +% \fi +% \to \everyfont + +%D \macros +%D {definefont} +%D +%D We also accept \type{sa a}||\type{sa d} as specification. +%D +%D Before we implement the main definition macro, we first show one for local use: +%D +%D \starttyping +%D \definefont[Some][LucidaBright at 100pt] \Some some +%D \definefont[More][LucidaBright scaled 3000] \More more +%D \definefont[Nice][LucidaBright mo 2] \Nice nice +%D \definefont[Text][LucidaBright sa 5.4] \Text last +%D \stoptyping +%D +%D The implementation looks as follows: + +\unexpanded\def\definefont % [name][spec][1.6 | line=10pt | setup_id] + {\dotripleempty\font_basics_define_font} + +\def\font_basics_define_font + {\ifthirdargument + \expandafter\font_basics_define_font_a + \else + \expandafter\font_basics_define_font_b + \fi} + +\def\font_basics_define_font_a[#name][#specification][#settings]% [name][spec][1.6 | line=10pt | setup_id] + {\doifelsesetups{#settings}% + {\setuvalue{#name}{\font_basics_define_font_with_setups {#name}{#specification}{#settings}}} + {\setuvalue{#name}{\font_basics_define_font_with_parameters{#name}{#specification}{#settings}}}} + +\def\font_basics_define_font_b[#name][#specification][#dummy]% + {\setuvalue{#name}{\font_basics_define_font_without_parameters{#name}{#specification}}} + +\def\font_basics_define_font_with_parameters#name#specification#settings% + {\font_basics_define_font_without_parameters{#name}{#specification}% + \setuplocalinterlinespace[#settings]% + \setupspacing\relax} % is this really needed ? + +\def\font_basics_define_font_with_setups#name#specification#settings% + {\font_basics_define_font_without_parameters{#name}{#specification}% + \setups[#settings]} + +%D Beware, in the frozen variants no settings are supported yet, but that might happen +%D some day. + +\unexpanded\def\definefrozenfont + {\dotripleempty\font_basics_define_frozen_font} + +% \def\font_basics_define_frozen_font[#name][#specification][#settings]% +% {\begingroup +% \font_basics_define_font[#name][#specification][#settings]% +% \csname#name\endcsname +% \expandafter\expandafter\expandafter\endgroup\expandafter\let\csname#name\endcsname\lastrawfontcall} + +\def\font_basics_define_frozen_font[#name][#specification][#settings]% + {\begingroup + \font_basics_define_font[#name][#specification][#settings]% + \csname#name\endcsname + \glet\lastglobalrawfontcall\lastrawfontcall + \endgroup + \expandafter\let\csname#name\endcsname\lastglobalrawfontcall} + +%D The instance namespace protection makes the switch local so that we can redefine a +%D logical name and/or change the size in between. + +% todo: now mathsize twice in name (so it can go here) +% todo: check when mathsize is needed + +\ifdefined\??fontinstanceready \else \installcorenamespace{fontinstanceready} \fi +\ifdefined\??fontinstancebasic \else \installcorenamespace{fontinstancebasic} \fi +\ifdefined\??fontinstanceclass \else \installcorenamespace{fontinstanceclass} \fi + +\newconditional\c_font_auto_size \settrue\c_font_auto_size + +\let\lastfontidentifier\empty + +\def\v_font_identifier_basic{\??fontinstancebasic \lastfontidentifier-\fontsize-\fontface} +\def\v_font_identifier_class{\??fontinstanceclass\fontclass-\lastfontidentifier-\fontsize-\fontface} + +\let\v_font_identifier_basic_saved\v_font_identifier_basic +\let\v_font_identifier_class_saved\v_font_identifier_class + +% \def\v_font_identifier_class{\??fontinstanceclass\fontclass-\lastfontidentifier-\fontstyle-\fontsize} % no \fontface + +\def\font_basics_define_font_without_parameters#identifier#2% + {\c_font_feature_inheritance_mode\c_font_feature_inheritance_fontonly + \edef\lastfontidentifier{#identifier}% + \let\v_font_size_relative\v_font_rscale_default + \let\v_font_size_absolute\fontbody + \font_helpers_low_level_define{#2}\v_font_identifier_basic + \csname\v_font_identifier_basic\endcsname + \setfalse\c_font_auto_size + \setfontcharacteristics + \the\everyfontswitch + \let\v_font_identifier_basic\v_font_identifier_basic_saved} + +\unexpanded\def\font_helpers_trigger#identifier% make a traced variant + {\edef\lastfontidentifier{#identifier}% + \ifcsname\v_font_identifier_class\endcsname + % \writestatus{fonts}{trigger: reusing \v_font_identifier_class}% + \expandafter\font_helpers_trigger_reuse + \else + % \writestatus{fonts}{trigger: defining \v_font_identifier_class}% + \expandafter\font_helpers_trigger_define + \fi} + +\def\font_helpers_trigger_define#relative#absolute#specification% + {\def\v_font_size_relative{#relative}% + \def\v_font_size_absolute{#absolute}% + \font_helpers_low_level_define{#specification}\v_font_identifier_class + \csname\v_font_identifier_class\endcsname + \setfalse\c_font_auto_size + \ifskipfontcharacteristics \else + \setfontcharacteristics + \the\everyfontswitch + \fi + \let\v_font_identifier_class\v_font_identifier_class_saved} + +\def\font_helpers_trigger_reuse#relative#absolute#specification% + {\csname\v_font_identifier_class\endcsname + \setfalse\c_font_auto_size + \ifskipfontcharacteristics \else + \setfontcharacteristics + \the\everyfontswitch + \fi + \let\v_font_identifier_class\v_font_identifier_class_saved} + +%D \macros +%D {currentfontbodyscale} +%D +%D Sometimes we need to have access to the font scale including the \type {a}||\type +%D {d} sizes. The next macro returns the current scaling factor. Take a look at +%D \type {cont-log.tex} for an example of its use. + +\installcorenamespace{fontenvironments} + +\def\currentfontbodysize % gets number (the normal sa 1 etc) + {\ifcsname\??fontenvironments\fontclass\s!default\somefontsize\endcsname + \lastnamedcs + \orelse\ifcsname\??fontenvironments\s!default\somefontsize\endcsname + \lastnamedcs + \else + \somefontsize + \fi} + +\def\currentfontbodyscale % gets character (x xx a etc) + {\csname\??fontenvironments + \ifcsname\??fontenvironments\fontclass\s!default\fontsize\endcsname\fontclass\s!default\fontsize\orelse + \ifcsname\??fontenvironments \s!default\fontsize\endcsname \s!default\fontsize\orelse + \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\fontclass\s!default\s!text \orelse + \ifcsname\??fontenvironments \s!default\s!text \endcsname \s!default\s!text \else + \s!default \fi + \endcsname} + +\def\font_currentfontbodyscale % gets character (x xx a etc) + {\ifcsname\??fontenvironments\fontclass\s!default\fontsize\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments \s!default\fontsize\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments \s!default\s!text \endcsname\lastnamedcs\else + \csname\??fontenvironments \s!default \endcsname \fi} + +\def\currentfontscale % used in default definition + {\csname\??fontenvironments + \ifcsname\??fontenvironments\fontclass\s!default\xfontsize\endcsname\fontclass\s!default\fontsize\orelse + \ifcsname\??fontenvironments \s!default\xfontsize\endcsname \s!default\fontsize\orelse + \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\fontclass\s!default\s!text \orelse + \ifcsname\??fontenvironments \s!default\s!text \endcsname \s!default\s!text \else + \s!default \fi + \endcsname} + +\def\font_currentfontscale % used in default definition + {\ifcsname\??fontenvironments\fontclass\s!default\xfontsize\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments \s!default\xfontsize\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\fontclass\s!default\s!text \endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments \s!default\s!text \endcsname\lastnamedcs\else + \csname\??fontenvironments \s!default \endcsname \fi} + +\setvalue{\??fontenvironments\s!default}{1} + +%D In the following macros we use \type {\currentxfontsize} to hold the current +%D x||size of the font. This enables us to support for instance \type {\sl} inside a +%D \type {\tx} switch. + +\newconstant\currentxfontsize + +\def\xfontsize{\ifcase\currentxfontsize\fontsize\or\s!x\else\s!xx\fi} + +%D Now we enter the area of font switching. The switching mechanism has to take care +%D of several situations, like: +%D +%D \startitemize[packed] +%D \item changing the overal document fonts (including margins, headers and footers) +%D \item changing local fonts (only the running text) +%D \item smaller and even more smaller alternatives (super- and subscripts) +%D \stopitemize +%D +%D \TEX\ offers a powerfull family mechanism for super- and subscripts in math mode. +%D In text mode however, we don't use families for the smaller alternatives, and +%D therefore have to take care of it otherwise. +%D +%D \macros +%D {definebodyfontenvironment,setupbodyfontenvironment} +%D +%D The relationship between the several sizes of a font, is +%D defined by: +%D +%D \showsetup{definebodyfontenvironment} +%D +%D Later on we will see how these parameters are used, so for the moment we stick +%D with an example: +%D +%D \starttyping +%D \definebodyfontenvironment +%D [12pt] +%D [ text=12pt, +%D script=9pt, +%D scriptscript=7pt, +%D x=10pt, +%D xx=8pt, +%D big=12pt, +%D small=10pt] +%D \stoptyping +%D +%D The first argument specifies the bodyfont size to which the settings apply. All +%D second parameters are specified in dimensions and tell us more about related +%D sizes. +%D +%D Afterwards, one can change values with +%D +%D \showsetup{setupbodyfontenvironment} +%D +%D When instead of a size the keyword \type{unknown} is +%D passed, fractions (relations) are used instead of fixed +%D sizes. + +%D {\bf Remark:} We need to cover the following cases, otherwise users can get +%D confused: +%D +%D \starttyping +%D \setupbodyfont[23pt] +%D +%D \definebodyfontenvironment[23pt] +%D \setupbodyfont[23pt] +%D +%D \definebodyfontenvironment[23pt] +%D \definebodyfont[23pt][rm,ss,tt][default] +%D \setupbodyfont[23pt] +%D \stoptyping +%D +%D Beware: while some font defs can be global, the bodyfont environment checks +%D local. This means that multiple local checks resulting in definitions are not +%D that efficient. So, apart from an occasional switch, one should define an +%D environment at the outer level. + +% \definebodyfontenvironment[33pt] +% \definebodyfontenvironment[dejavu][default][1=.5] +% \definebodyfontenvironment[dejavu][default][x=1.2] +% \definebodyfontenvironment[dejavu][default][a=5] +% \definebodyfontenvironment[dejavu][33pt][x=100pt] + +% the lookup order is: +% +% [class] [dimension] [parameters] +% [class] [default] [parameters] % factors +% [dimension] [parameters] +% [default] [parameters] % factors +% +% with defaults providing factors + +% todo: class:size +% todo: make assignments global + +\letvalue\??fontenvironments\empty % so we default to empty + +\def\bodyfontvariable#parameter% + {\csname\??fontenvironments + \ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname\fontclass\normalizedbodyfontsize#parameter\orelse + \ifcsname\??fontenvironments\fontclass #parameter\endcsname\fontclass #parameter\orelse + \ifcsname\??fontenvironments \normalizedbodyfontsize#parameter\endcsname \normalizedbodyfontsize#parameter\orelse + \ifcsname\??fontenvironments\s!default #parameter\endcsname\s!default #parameter\fi + \endcsname} + +\def\font_bodyfontvariable#parameter% + {\ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\fontclass #parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments \normalizedbodyfontsize#parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\s!default #parameter\endcsname\lastnamedcs\fi} + +\def\bodyfontsizevariable#size#parameter% + {\csname\??fontenvironments + \ifcsname\??fontenvironments\fontclass#size#parameter\endcsname\fontclass#size#parameter\orelse + \ifcsname\??fontenvironments\fontclass #parameter\endcsname\fontclass #parameter\orelse + \ifcsname\??fontenvironments #size#parameter\endcsname #size#parameter\orelse + \ifcsname\??fontenvironments\s!default #parameter\endcsname\s!default #parameter\fi + \endcsname} + +\def\font_bodyfontsizevariable#size#parameter% + {\ifcsname\??fontenvironments\fontclass#size#parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\fontclass #parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments #size#parameter\endcsname\lastnamedcs\orelse + \ifcsname\??fontenvironments\s!default #parameter\endcsname\lastnamedcs\fi} + +\def\bodyfontinterlinespace{\bodyfontvariable\c!interlinespace} % used elsewhere + +\def\bodyfontdimension#class#size#parameter#body% + {\the\dimexpr + \ifcsname\??fontenvironments #class#size#parameter\endcsname \lastnamedcs \orelse + \ifcsname\??fontenvironments#class\s!default#parameter\endcsname \lastnamedcs\dimexpr#body\relax\orelse % factor + \ifcsname\??fontenvironments #size#parameter\endcsname \lastnamedcs \else + \lastnamedcs\dimexpr#body\relax\fi % factor + \relax} + +\unexpanded\def\definebodyfontenvironment + {\dotripleempty\font_basics_define_body_font_environment} + +\let\setupbodyfontenvironment\definebodyfontenvironment + +\installcorenamespace{fontenvironmentknown} + +\def\font_helpers_register_environment#class#body% + {\expandafter\let\csname\??fontenvironmentknown#class#body\endcsname\empty} + +\newmacro\m_font_body +\newmacro\m_font_body_normalized + +\def\font_basics_define_body_font_environment + {\ifthirdargument + \singleexpandafter\font_basics_define_body_font_environment_class + \orelse\ifsecondargument + \expandafter\font_basics_define_body_font_environment_empty + \else + \expandafter\font_basics_define_body_font_environment_unset + \fi} + +%D First we handle the class specific case. Beware: you can change values before +%D a bodyfont is loaded but changing them afterwards can be sort of tricky as +%D values are not consulted afterwards. + +\def\processbodyfontenvironmentlist#1% no \unexpanded as then we cannot use it in alignments + {\clf_processbodyfontsizes{\strippedcsname#1}} + +\def\bodyfontenvironmentlist + {\clf_getbodyfontsizes} + +\def\font_basics_define_body_font_environment_class[#class][#body][#settings]% + {\edef\m_font_body{#body}% + \ifx\m_font_body\s!default + % these are the last resort within a class + \getrawparameters[\??fontenvironments#class\s!default][#settings]% + \else + \normalizebodyfontsize\m_font_body_normalized\m_font_body + \font_basics_define_body_font_environment_size[#class][\m_font_body_normalized][#settings]% + \clf_registerbodyfontsize{\m_font_body_normalized}% + \fi} + +%D The empty case uses the same code but needs to ignore the current class settings +%D (just to be sure, as it's not really needed). + +\def\font_basics_define_body_font_environment_empty[#body][#settings][#dummy]% + {\push_macro_fontclass + \let\fontclass\empty + \font_basics_define_body_font_environment_class[][#body][#settings]% + \pop_macro_fontclass} + +\def\font_basics_define_body_font_environment_unset[#body][#dummya][#dummyb]% + {\push_macro_fontclass + \let\fontclass\empty + \font_basics_define_body_font_environment_class[][#body][]% + \pop_macro_fontclass} + +%D We don't check too soon as we can refer to later definitions. + +\newconditional\c_font_defining_environment_state % controls messages + +\def\font_basics_define_body_font_environment_size[#class][#normalizedbody][#settings]% normalized body + {\getrawparameters[\??fontenvironments#class#normalizedbody][#settings]% + \ifcsname\??fontenvironmentknown#class#normalizedbody\endcsname + % environment and size already defined + \orelse\ifproductionrun + \push_macro_fontclass + \edef\fontclass{#class}% + \font_helpers_register_environment{#class}{#normalizedbody}% + \settrue\c_font_defining_environment_state + \font_helpers_define_unknown_font{#normalizedbody}% current class + \setfalse\c_font_defining_environment_state + \pop_macro_fontclass + \fi + \font_helpers_register_fontbody{#normalizedbody}} + +%D Checking + +\def\font_helpers_check_bodyfont_environment#normalizedbody#body% + {\ifcsname\??fontenvironmentknown\fontclass#normalizedbody\endcsname + % already defined + \else + \font_helpers_check_bodyfont_environment_indeed{#normalizedbody}{#body}% + \fi} + +\def\font_helpers_check_bodyfont_environment_indeed#normalizedbody#body% + {\font_helpers_register_environment\fontclass{#normalizedbody}% + \ifcsname\??fontbodyknown#normalizedbody\endcsname + \else + \font_helpers_define_unknown_font{#normalizedbody}% + \fi} + +%D We default all parameters to the main bodyfont size, so the next setup is valid +%D too: +%D +%D \starttyping +%D \definebodyfontenvironment[24pt] +%D \stoptyping +%D +%D All parameters can be redefined when needed, so one doesnot have to stick to the +%D default ones. + +%D \macros +%D {definebodyfont} +%D +%D The next step in defining a bodyfont involves the actual font files, which can be +%D recognized by their extension \type {tfm}. Installing those file is often beyond +%D the scope of the user and up to the system administrator. +%D +%D \showsetup{definebodyfont} +%D +%D This commands takes three arguments: a (series of) bodyfont size(s), the style +%D group to which the definitions belong, and an alternative, as specified by the +%D \TEX\ (math) families, extended with~a, b~\unknown. +%D +%D We show two examples, that show all the alternative scaling options. The \type +%D {\tfa} alternatives can be extended with \type {\bfa}, \type {\slb}, etc. or even +%D \type {e} and higher alternatives. The magic scaled values are derived from plain +%D \TEX's \type {\magstep}: +%D +%D \starttyping +%D \definebodyfont [12pt] [rm] +%D [tf=cmr12, +%D bf=cmbx12, +%D it=cmti12, +%D sl=cmsl12, +%D bi=cmbxti10 at 12pt, +%D bs=cmbxsl10 at 12pt, +%D tfa=cmr12 scaled 1.200, +%D tfb=cmr12 scaled 1.440, +%D tfc=cmr12 scaled 1.728, +%D tfd=cmr12 scaled 2.074, +%D sc=cmcsc10 at 12pt] +%D +%D \definebodyfont [12pt,11pt,10pt,9pt,8pt] [rm] +%D [tf=lbr sa 1, +%D bf=lbd sa 1, +%D it=lbi sa 1, +%D sl=lbsl sa 1, +%D bi=lbdi sa 1, +%D bs=lbdi sa 1, +%D tfa=lbr sa 1.200, +%D tfb=lbr sa 1.440, +%D tfc=lbr sa 1.728, +%D tfd=lbr sa 2.074, +%D sc=lbr sa 0.833] +%D \stoptyping +%D +%D The second example shows that we can define more sizes at once. The main +%D difference between these examples is that the Computer Modern Roman come in many +%D design sizes. This means that there we cannot define them in bulk using \type +%D {sa}. Instead of \type {rm} (roman) one can define \type {ss} (sans serif), \type +%D {tt} (teletype), \type {hw} (hand written), \type {cg} (calygraphic) and whatever +%D styles. +%D +%D The first argument may be a comma separated list. This, combined with +%D specifications using \type{sa} can save a lot of typing. Although all arguments +%D should be specified, we treat the second argument as optional. +%D +%D Defining a bodyfont involves two actions: defining the specific style related +%D alternatives, like \type {\rma}, \type {\bfa} and \type {\rmsla}, and storing the +%D definitions of their bodyfont size related fonts. The first step is bodyfont +%D independant but executed every time. This permits user definitions like \type +%D {\tfw} or \type {\bfq} for real large alternatives. +%D +%D If we move design size info to the lfg file (after all only lm has design sizes) +%D we can get rid of much code .. 2012 or so. + +\installcorenamespace{fontdefinitions} + +% [class] [name] [rm,ss] [settings] +% [class] [10pt,11pt] [rm,ss] [settings] +% [class] [10pt,11pt] [rm,ss] [name] + +% [class] [name] [settings] == [name] [rm] [settings] +% [class] [10pt,11pt] [settings] == [name] [rm] [settings] +% [class] [10pt,11pt] [name] == [10pt,11pt] [rm] [name] + +\unexpanded\def\definebodyfont + {\doquadrupleempty\font_basics_define_body_font} + +\def\font_basics_define_body_font[#1][#2][#3][#4]% + {\iffourthargument + \processcommacommand[#1]{\font_basics_define_body_font_class_given[#2][#3][#4]}% + \else + \font_basics_define_body_font_class_known[#1][#2][#3]% + \fi} + +\def\font_basics_define_body_font_class_given[#1][#2][#3]#4% + {\push_macro_fontclass + \doifelse{#4}\s!default + {\let\fontclass\empty} + {\def\fontclass{#4}}% + \definebodyfont[#1][#2][#3]% + \pop_macro_fontclass} + +\def\font_basics_define_body_font_class_known + {\ifthirdargument + \singleexpandafter\font_basics_define_body_font_a + \orelse\ifsecondargument + \expandafter\font_basics_define_body_font_b + \else + \expandafter\font_basics_define_body_font_c + \fi} + +\unexpanded\def\font_basics_define_body_font_b[#whatever][#specification][#dummy]% body|identifier defs|identifier + {\font_basics_define_body_font_a[#whatever][\s!rm][#specification]} + +\unexpanded\def\font_basics_define_body_font_c[#whatever][#dummya][#dummyb]% body|identifier + {\font_basics_define_body_font_a[#whatever][\s!rm][]} + +\unexpanded\def\font_basics_define_body_font_a[#whatever]% + {\doifelsenumber{#whatever}% + \font_basics_define_body_font_body + \font_basics_define_body_font_name + [#whatever]} + +\unexpanded\def\font_basics_define_body_font_body[#body][#style][#specification]% + {\ifcondition\validassignment{#specification}% + \expandafter\font_basics_define_body_font_body_assignment + \else + \expandafter\font_basics_define_body_font_body_identifier + \fi + [#body][#style][#specification]}% + +\unexpanded\def\font_basics_define_body_font_name[#name][#style][#specification]% + {\ifcondition\validassignment{#specification}% + \expandafter\font_basics_define_body_font_name_assignment + \else + \expandafter\font_basics_define_body_font_name_identifier + \fi + [#name][#style][#specification]}% + +\unexpanded\def\font_basics_define_body_font_body_assignment[#bodylist][#stylelist][#assignments]% + {\processcommalist[#bodylist]{\font_basics_define_body_font_body_assignment_a{#stylelist}{#assignments}}} + +\unexpanded\def\font_basics_define_body_font_body_assignment_a#stylelist#assignments#body% + {\normalizebodyfontsize\m_font_asked_body{#body}% + % normally we define quite a lot in advance, i.e global defs + \font_helpers_check_bodyfont_environment\m_font_asked_body\m_font_asked_body % !! + \processcommalist[#stylelist]{\font_basics_define_body_font_body_assignment_b{#assignments}}} + +\unexpanded\def\font_basics_define_body_font_body_assignment_b#assignments#style% + {\edef\m_font_asked_style{#style}% + \processcommalist[#assignments]\font_basics_define_body_font_defs} + +\unexpanded\def\font_basics_define_body_font_defs + {\ifx\fontclass\empty + \expandafter\font_basics_define_body_font_defs_nop + \else + \expandafter\font_basics_define_body_font_defs_yes + \fi} + +\unexpanded\def\font_basics_define_body_font_defs_yes_normal#assignment% + {\ifx\m_font_asked_style\s!mm + \expandafter\font_basics_define_body_font_yes_mm + \else + \expandafter\font_basics_define_body_font_yes_xx + \fi[#assignment]} + +\unexpanded\def\font_basics_define_body_font_defs_nop_normal#assignment% + {\ifx\m_font_asked_style\s!mm + \expandafter\font_basics_define_body_font_nop_mm + \else + \expandafter\font_basics_define_body_font_nop_xx + \fi[#assignment]} + +\unexpanded\def\font_basics_define_body_font_defs_yes_traced#assignment% + {\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] [#assignment]}% + \ifx\m_font_asked_style\s!mm + \expandafter\font_basics_define_body_font_yes_mm + \else + \expandafter\font_basics_define_body_font_yes_xx + \fi[#assignment]} + +\unexpanded\def\font_basics_define_body_font_defs_nop_traced#assignment% + {\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] [#assignment]}% + \ifx\m_font_asked_style\s!mm + \expandafter\font_basics_define_body_font_nop_mm + \else + \expandafter\font_basics_define_body_font_nop_xx + \fi[#assignment]} + +\let\font_basics_define_body_font_defs_yes\font_basics_define_body_font_defs_yes_normal +\let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_normal + +\appendtoks + \let\font_basics_define_body_font_defs_yes\font_basics_define_body_font_defs_yes_traced + \let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_traced +\to \t_font_tracers_definitions + +%D We split into two characters (first part of spec) and the rest: the first two are +%D the style and the rest is a size, although in practice one will seldom define the +%D size directly. We might even drop that as it gives faster code. + +\unexpanded\def\font_basics_define_body_font_nop_xx[#one#two#rest=#value]% local + {\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi + \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname\undefined + \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}% + \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname\undefined + \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}% + \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname\undefined + \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest}{\noexpand\font_rscale_xx{\m_font_asked_style}}{\m_font_asked_body}{\normalunexpanded{#value}}}% + } + +\unexpanded\def\font_basics_define_body_font_yes_xx[#one#two#rest=#value]% global + {\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi + \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-1\endcsname\undefined + \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-0\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-0}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}% + \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-2\endcsname\undefined + \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-4\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-4}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}% + \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-3\endcsname\undefined + \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\m_font_asked_style-#one#two-#rest-5\endcsname + {\font_helpers_trigger{\m_font_asked_body-\m_font_asked_style-#one#two#rest-5}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}% + } + +% \writestatus{fonts}{define \m_asked_style\space yes: {\expandafter\meaning\csname\fontclass\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname} + +%D Here the rest concerns rl or lr so in this case it is not a size specifier but +%D a directional one. + +\unexpanded\def\font_basics_define_body_font_nop_mm[#one#two#rest=#value]% local + {%\ifcsname\s!mm\endcsname\else\font_basics_check_fontname_combination\s!mm{#one#two}{#rest}\fi + \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-1\endcsname\undefined + % \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-2\endcsname\undefined + % \expandafter\let\csname\??fontinstanceclass\m_font_asked_body-\s!mm-#one#two#rest-3\endcsname\undefined + \unexpanded\expandafter\normaledef\csname\??fontinstanceready\m_font_asked_body-\s!mm-#one#two#rest\endcsname + {\font_helpers_trigger{\m_font_asked_body-\s!mm-#one#two#rest}{\noexpand\font_rscale_mm}{\m_font_asked_body}{\normalunexpanded{#value}}}% + } + +% \writestatus{fonts}{define \m_asked_style\space nop: \expandafter\meaning\csname\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname}% + +\unexpanded\def\font_basics_define_body_font_yes_mm[#one#two#rest=#value]% global + {%\ifcsname\s!mm\endcsname\else\font_basics_check_fontname_combination\s!mm{#one#two}{#rest}\fi + \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-1\endcsname\undefined + % \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-2\endcsname\undefined + % \expandafter\glet\csname\??fontinstanceclass\fontclass-\m_font_asked_body-\s!mm-#one#two#rest-3\endcsname\undefined + \unexpanded\expandafter\normalxdef\csname\??fontinstanceready\fontclass-\m_font_asked_body-\s!mm-#one#two#rest\endcsname + {\font_helpers_trigger{\m_font_asked_body-\s!mm-#one#two#rest}{\number\p_font_rscale}{\m_font_asked_body}{\normalunexpanded{#value}}}% + } + +% \writestatus{fonts}{define \m_asked_style\space yes: \expandafter\meaning\csname\fontclass\m_font_asked_body\m_font_asked_style#one#two#rest\endcsname}% + +\unexpanded\def\font_basics_define_body_font_body_identifier[#bodylist][#stylelist][#name]% + {\processcommalist[#bodylist]{\font_basics_define_body_font_body_identifier_a{#stylelist}{#name}}} + +\unexpanded\def\font_basics_define_body_font_body_identifier_a#stylelist#name#body% + {\normalizebodyfontsize\m_font_asked_body{#body}% + \font_helpers_check_bodyfont_environment\m_font_asked_body\m_font_asked_body % !! + \processcommalist[#stylelist]{\font_basics_define_body_font_body_identifier_b{#name}}} + +\unexpanded\def\font_basics_define_body_font_body_identifier_b#name#style% + {\edef\m_font_asked_style{#style}% + %\writestatus\m!fonts{[\fontclass] [\m_font_asked_body] [\m_font_asked_style] => [#name]}% + \csname\??fontdefinitions#name:\m_font_asked_style\endcsname} % no checking + +\unexpanded\def\font_basics_define_body_font_name_assignment[#name][#stylelist][#assignments]% + {\processcommalist[#stylelist]{\font_basics_define_body_font_name_assignment_a{#name}{#assignments}}} + +\unexpanded\def\font_basics_define_body_font_name_assignment_a#name#assignments#style% + {%\writestatus\m!fonts{[#name:#style] => [#assignments]}% + \setevalue{\??fontdefinitions#name:#style}{\font_basics_define_body_font_default{#assignments}}} + +\unexpanded\def\font_basics_define_body_font_name_identifier[#name][#stylelist][#identifier]% + {\processcommalist[#stylelist]{\font_basics_define_body_font_name_identifier_a{#name}{#identifier}}} + +\unexpanded\def\font_basics_define_body_font_name_identifier_a#name#identifier#style% + {%\writestatus\m!fonts{[#name:#style] => [##identifier:#style]}% + \ifcsname\??fontdefinitions#name:#style\endcsname + \expandafter\let\csname\??fontdefinitions#name:#style\expandafter\endcsname\csname\??fontdefinitions#identifier:#style\endcsname + \else + \expandafter\def\csname\??fontdefinitions#name:#style\endcsname{\csname\??fontdefinitions#identifier:#style\endcsname}% + \fi} + +%D The unknown: + +\newconditional\c_font_defining_unknown +\newconditional\c_font_defining_state + +\unexpanded\def\font_helpers_define_unknown_font#body% one level only + {\font_helpers_register_fontbody{#body}% prevents loop, can go + \setfalse\c_font_defining_state + \font_helpers_process_relative_size_list{\font_helpers_define_unknown_check_sizes{#body}}% + \ifconditional\c_font_defining_state + \setfalse\c_font_defining_state + \font_helpers_process_style_list{\font_helpers_define_unknown_check_definitions{#body}}% + \ifconditional\c_font_defining_state + \ifconditional\c_font_defining_environment_state\else + %\showmessage\m!fonts{14}{#body}% main + \clf_registerunknownbodysize{#body}% + \fi + \setfalse\c_font_defining_state + \font_helpers_register_fontbody{#body}% + % needed ? + \ifconditional\c_font_defining_unknown + \else + \settrue\c_font_defining_unknown + \font_helpers_process_relative_size_list{\font_helpers_define_unknown_check_relatives{#body}}% + \setfalse\c_font_defining_unknown + \fi + \fi + \fi} + +\def\font_helpers_define_unknown_check_sizes#body#relativesize% + {\ifcsname\??fontenvironments\s!default#relativesize\endcsname % fontclass ? + \expandafter\normalizebodyfontsize\csname\??fontenvironments#body#relativesize\endcsname{\csname\??fontenvironments\s!default#relativesize\endcsname\dimexpr#body\relax}% + \settrue\c_font_defining_state + \fi} + +\def\font_helpers_define_unknown_check_definitions#body#style% + {\ifcsname\??fontdefinitions\s!default:#style\endcsname + \edef\m_font_asked_body{#body}% + \edef\m_font_asked_style{#style}% + \lastnamedcs + \settrue\c_font_defining_state + \fi} + +% \def\font_helpers_define_unknown_check_relatives#body#relativesize% +% {\ifcsname\??fontbodyknown\csname\??fontenvironments#body#relativesize\endcsname\endcsname \else +% % how \lastnamedcs here +% \expandafter\font_helpers_define_unknown_font\csname\??fontenvironments#body#relativesize\endcsname +% \settrue\c_font_defining_state +% \fi} + +\def\font_helpers_define_unknown_check_relatives#body#relativesize% + {\ifcsname\??fontbodyknown\csname\??fontenvironments#body#relativesize\endcsname\endcsname \else + \expandafter\font_helpers_define_unknown_font\csname\??fontenvironments#body#relativesize\endcsname + \settrue\c_font_defining_state + \fi} + +\unexpanded\def\font_basics_define_body_font_default#assignments% + {\font_helpers_check_relative_font_size\m_font_asked_style % still needed here? + \ifcsname\m_font_asked_style\endcsname\else + \normalexpanded{\definefontstyle[\m_font_asked_style][\m_font_asked_style]}% + \fi + \processcommalist[#assignments]\font_basics_define_body_font_defs + \let\p_font_rscale\v_font_rscale_default} + +%D These macros show that quite some definitions take place. Fonts are not loaded +%D yet! This means that at format generation time, no font files are present. + +\unexpanded\def\font_basics_switch_points#body% + {\ifcsname\??fontbodyknown#body\endcsname \else + % we need to check the relative sizes for this body + \font_helpers_define_unknown_font{#body}% + \fi% + \ifcsname\??fontbodyknown#body\endcsname % always true now + \font_basics_complete_switch{#body}% + \localbodyfontsize#body\relax + \normalizebodyfontsize\normalizedbodyfontsize\localbodyfontsize + \font_helpers_check_bodyfont_environment\normalizedbodyfontsize\normalizedbodyfontsize % !! + \else + \showmessage\m!fonts4{#body}% + \fi} + +\unexpanded\def\font_basics_switch_style#style% + {\ifcsname\??fontstyle#style\endcsname + \lastnamedcs + \edef\fontstyle{#style}% + \ifmmode\mr\fi % in order to be compatible with \rm in math mode + % \the\everybodyfont % cleaner, in setting size as well as style + \else + \showmessage\m!fonts5{#style}% + \fi} + +%D Here comes the main font switching macros. These macros handle changes in size as +%D well as returning to the global bodyfont size. + +\ifdefined\font_preloads_at_definition \else \let\font_preloads_at_definition\relax \fi + +\def\font_helpers_set_font#method#specification% + {\edef\m_font_specification{#specification}% + \ifx\m_font_specification\empty \else + \ifx\m_font_specification\v!global % we can have all kind of presets + \restoreglobalbodyfont + \else + \processcommacommand[\m_font_specification]{\font_helpers_set_font_check_size}% + \processcommacommand[\m_font_specification]{\font_helpers_set_font_set_font{#method}}% + \ifproductionrun + \font_preloads_at_definition + \font_basics_switch_points\normalizedbodyfontsize + \font_basics_switch_style\fontstyle + \ifx\defaultfontclass\empty + \let\defaultfontclass\fontclass + \fi + \fi + \fi + \currentxfontsize\zerocount + \fi} + +\def\font_helpers_set_font_check_size#option% + {\doifelsenumber{#option}{\font_helpers_check_bodyfont_environment{#option}{#option}}\donothing} + +\def\font_helpers_set_font_set_font#method#option% method=1: set, method=2: switch + {\doifsomething{#option}{\font_helpers_set_font_set_font_option{#method}{#option}}} + +\def\font_helpers_set_font_set_font_option#method#option% + {\doifelsenumber{#option}% + \font_helpers_set_font_set_font_option_body + \font_helpers_set_font_set_font_option_keyword + {#method}{#option}{#option}} + +\newmacro\m_font_keyword + +\unexpanded\def\font_helpers_set_font_set_font_option_keyword#method#keyword#message% + {\edef\m_font_keyword{#keyword}% + \ifcsname\??fontenvironments\normalizedbodyfontsize\m_font_keyword\endcsname + \edef\m_font_step{\font_bodyfontvariable\m_font_keyword}% + \normalexpanded{\font_helpers_set_font_set_font_option_body{#method}{\m_font_step}{#message}}% + \orelse\ifx\m_font_keyword\v!reset + \let\fontstyle\empty % new 31/7/2006 + \let\fontsize \empty + \orelse\ifcsname\??fontstyle\m_font_keyword\endcsname + \let\fontstyle\m_font_keyword + \else + \setcurrentfontclass\m_font_keyword + \ifcase#method\relax + \let\globalfontclass\globalfontclass % -) + \else + \let\globalfontclass\fontclass + \fi + \font_helpers_set_fontstyle_of_fontclass + \fi} + +\def\font_helpers_set_fontstyle_of_fontclass % will be overloaded later + {\let\fontstyle\s!rm} + +\unexpanded\def\font_helpers_set_font_set_font_option_body#method#body#message% + {\normalizebodyfontsize\normalizedsetfont{#body}% redundant for some calls + \ifcsname\??fontbodyknown\normalizedsetfont\endcsname \else + \font_helpers_define_unknown_font\normalizedsetfont + \fi + \ifcsname\??fontbodyknown\normalizedsetfont\endcsname + \localbodyfontsize\normalizedsetfont + \let\normalizedbodyfontsize\normalizedsetfont + \else + \showmessage\m!fonts4{#message}% + %\font_helpers_set_font_set_font_option_body_fallbacks{#method}{#body}% + \fi} + +% we need to check the fontclass + +\def\registerfontclass#class% + {\letgvalue{\??fontclassyes#class}\v!yes} % global ? + +\def\setcurrentfontclass#class% + {\ifcsname\??fontclassyes#class\endcsname + \edef\fontclass{#class}% + \orelse\ifcsname\??fontclassnop#class\endcsname + % already tried + \else % too messy: \ifcase\currentgrouplevel % (unpredictable) + \trycurrentfontclass{#class}% + \fi} + +\ifdefined\trycurrentfontclass \else + + \unexpanded\def\trycurrentfontclass#typeface% + {\letvalueempty{\??fontclassnop#typeface}} + +\fi + +\let\defaultfontstyle \s!rm +\let\defaultfontalternative\s!tf +\let\defaultfontsize \empty +\let\defaultfontface \!!zerocount + +%D So far for synchronisation. (We can inline the following macros.) + +\unexpanded\def\setcurrentfont#body#style#alternative#size% not used + {\edef\fontbody {#body}% + \edef\fontstyle {#style}% + \edef\fontalternative{#alternative}% + \edef\fontsize {#size}% + \font_helpers_check_big_math_synchronization + \font_helpers_synchronize_font} + +\unexpanded\def\setcurrentfontbody#body% % not used + {\edef\fontbody{#body}% + \font_helpers_synchronize_font} + +% For Taco: optional fall backs: + +\ifdefined\font_typescripts_inherit_check \else + \let\font_typescripts_inherit_check\gobbleoneargument % implemented in type-ini +\fi + +\unexpanded\def\font_helpers_set_current_font_style#style% + {\edef\fontstyle{#style}% + \font_typescripts_inherit_check\fontstyle + \ifmmode\mr\fi % otherwise \rm not downward compatible ... not adapted yet + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_xsize_alternative#xsize#alternative% + {\edef\fontface{#xsize}% + \edef\fontalternative{#alternative}% + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_alternative#alternative% + {\edef\fontalternative{#alternative}% + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_size#size% + {\edef\fontsize{#size}% + \font_helpers_check_big_math_synchronization % double? better in everymath? + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_style_alternative#style#alternative% \rmsl + {\edef\fontstyle {#style}% + \edef\fontalternative{#alternative}% + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_style_size#style#size% \rma + {\edef\fontstyle{#style}% + \edef\fontsize {#size}% + \font_helpers_check_big_math_synchronization % double? better in everymath? + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_alternative_size#alternative#size% \sla + {\edef\fontalternative{#alternative}% + \edef\fontsize {#size}% + \font_helpers_check_big_math_synchronization % double? better in everymath? + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_set_current_font_style_alternative_size#style#alternative#size% \rmsla + {\edef\fontstyle {#style}% + \edef\fontalternative{#alternative}% + \edef\fontsize {#size}% + \font_helpers_check_big_math_synchronization % double? better in everymath? + \font_helpers_synchronize_font} + +\unexpanded\def\font_helpers_synchronize_font % we can have dups i.e. no need to let fontstrategy + {\ifx\fontclass\empty + \applyfontstrategies + \else + \applyfontclassstrategies + \fi + \setfalse\c_font_auto_size + \ifskipfontcharacteristics + \setfontcharacteristics + \the\everyfontswitch + \fi} + +%D This is the resolver for special cases (sizes) and in practice it is not called +%D that often so further optimization makes no sense. + +\def\font_helpers_check_strategy_class_a % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname + \setfalse\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_class_b + \fi} + +\def\font_helpers_check_strategy_class_b % --- --- --- def % pt tt bf + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_class_c + \fi} + +\def\font_helpers_check_strategy_class_c % --- --- def --- % pt tt tf a + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\defaultfontalternative-\fontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_class_d + \fi} + +\def\font_helpers_check_strategy_class_d % --- --- def def % pt tt tf + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_class_e + \fi} + +\def\font_helpers_check_strategy_class_e % --- def def def % pt rm tf + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \setfalse\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_class_f + \fi} + +\def\font_helpers_check_strategy_class_f % def def def def % rm tf + {\ifcsname\??fontinstanceready\fontclass-\defaultfontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_a + \fi} + +% no class + +\def\font_helpers_check_strategy_a % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname + \setfalse\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_b + \fi} + +\def\font_helpers_check_strategy_b % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\fontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_c + \fi} + +\def\font_helpers_check_strategy_c % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\defaultfontalternative-\fontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_d + \fi} + +\def\font_helpers_check_strategy_d % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontbody-\fontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_e + \fi} + +\def\font_helpers_check_strategy_e % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\fontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \setfalse\c_font_auto_size + \lastnamedcs + \else + \expandafter\font_helpers_check_strategy_f + \fi} + +\def\font_helpers_check_strategy_f % --- --- --- --- % pt tt bf a + {\ifcsname\??fontinstanceready\defaultfontbody-\defaultfontstyle-\defaultfontalternative-\defaultfontsize-\fontface\endcsname + \settrue\c_font_auto_size + \lastnamedcs + \fi} + +\let\applyfontstrategies \font_helpers_check_strategy_a +\let\applyfontclassstrategies\font_helpers_check_strategy_class_a + +%D Let's synchronize: + +\newconditional\c_font_synchronize \settrue\c_font_synchronize + +\prependtoks + \ifconditional\c_font_synchronize + \font_helpers_synchronize_math + \font_helpers_synchronize_font % problem: syncs last font + \fi +\to \everybodyfont + +%D Setting the normal sizes as well as the x and xx smaller sizes is accomplished by +%D the next set of macros. When in math mode, the commands \type {\tx} and \type +%D {\txx} are just a switch to the script and double script styles, but in text mode +%D the values defined by the bodyfontenvironment are used. Here we also set \type +%D {\currentxfontsize}. + +\def\font_helpers_set_current_font_xxx_alternative#alternative#xsize#scriptstyle% + {\ifmmode + #scriptstyle% + \else + \font_helpers_set_current_xsize_alternative{#xsize}{#alternative}% + \fi} + +\def\font_helpers_reset_x_fontsize + {\ifcase\currentxfontsize\else + \currentxfontsize\zerocount + % also \sx and \sxx ? + \let\tx \normaltx + \let\txx\normaltxx + \fi} + +\let\font_helpers_check_nested_x_fontsize\relax + +\def\font_helpers_set_current_font_x_alternative#alternative% + {\font_helpers_check_nested_x_fontsize + \font_helpers_set_current_font_xxx_alternative{#alternative}{4}\scriptstyle + \currentxfontsize\plusone + \let\tx\txx} + +\def\font_helpers_set_current_font_xx_alternative#alternative% + {\font_helpers_check_nested_x_fontsize + \font_helpers_set_current_font_xxx_alternative{#alternative}{5}\scriptscriptstyle + \currentxfontsize\plustwo + \let\tx\empty + \let\txx\empty} + +%D This alterative is not really needed, but for old time's sake we keep it there. +%D We can speed it up when needed. + +\def\font_helpers_set_current_font_x_style_alternative #alternative{\csname#alternative\endcsname\tx} +\def\font_helpers_set_current_font_xx_style_alternative#alternative{\csname#alternative\endcsname\txx} + +%D These macros also show us that when we call for \type {\tx}, this macro is +%D redefined to be \type {\txx}. Therefore calls like: +%D +%D \startbuffer +%D {small \tx is \tx beautiful} +%D {small \tx is \txx beautiful} +%D {small \txx is \tx beautiful} +%D {small \txx is \txx beautiful} +%D \stopbuffer +%D +%D \typebuffer +%D +%D result in: +%D +%D \startlines +%D \getbuffer +%D \stoplines +%D +%D Setting the main size involves the style list and therefore takes a bit more +%D time. Keep in mind that the fontsize is represented by a character or empty. + +\installcorenamespace{fontscalex} +\installcorenamespace{fontscalexx} + +\newconditional\c_font_inherit_scale + +\def\font_scale_inherit#1% + {\begingroup + \scratchcounterone\fontid\font\relax + \currentxfontsize\plusone + \normalexpanded{\definedfont[\clf_specifiedfont\scratchcounterone\font_currentfontscale\relax]}% + \scratchcountertwo\fontid\font\relax + \currentxfontsize\plustwo + \normalexpanded{\definedfont[\clf_specifiedfont\scratchcounterone\font_currentfontscale\relax]}% + \scratchcounterthree\fontid\font\relax + % parent -> x -> xx + % parent -> xx + \global\expandafter\chardef\csname\??fontscalex \number\scratchcounterone\endcsname\scratchcountertwo + \global\expandafter\chardef\csname\??fontscalexx\number\scratchcounterone\endcsname\scratchcounterthree + \global\expandafter\chardef\csname\??fontscalex \number\scratchcountertwo\endcsname\scratchcounterthree + \global\expandafter\chardef\csname\??fontscalexx\number\scratchcountertwo\endcsname\scratchcounterthree + \endgroup + \setfontid\csname#1\number\fontid\font\endcsname} + +\def\font_scale_inherit_x + {\ifcsname\??fontscalex\number\fontid\font\endcsname + \setfontid\lastnamedcs + \else + \font_scale_inherit\??fontscalex + \fi + \ifskipfontcharacteristics + \setfontcharacteristics + \the\everyfontswitch + \fi} + +\def\font_scale_inherit_xx + {\ifcsname\??fontscalexx\number\fontid\font\endcsname + \setfontid\lastnamedcs + \else + \font_scale_inherit\??fontscalexx + \fi + \ifskipfontcharacteristics + \setfontcharacteristics + \the\everyfontswitch + \fi} + +\def\font_scale_defined_x + {\let\fontface\!!plusfour + \let\fontalternative\fontalternative + \font_helpers_synchronize_font} + +\def\font_scale_defined_xx + {\let\fontface\!!plusfive + \let\fontalternative\fontalternative + \font_helpers_synchronize_font} + +\unexpanded\def\tx + {\currentxfontsize\plusone + \ifmmode + \scriptstyle + \else\ifconditional\c_font_inherit_scale + \font_scale_inherit_x + \else + \font_scale_defined_x + \fi\fi + \let\tx\txx} + +\unexpanded\def\txx + {\currentxfontsize\plustwo + \ifmmode + \scriptscriptstyle + \else\ifconditional\c_font_inherit_scale + \font_scale_inherit_xx + \else + \font_scale_defined_xx + \fi\fi + \let\tx \empty + \let\txx\empty} + +\unexpanded\def\sx + {\currentxfontsize\plusone + \ifmmode + \scriptstyle + \else + \font_scale_inherit_x + \fi + \let\tx\txx + \let\sx\sxx} + +\unexpanded\def\sxx + {\currentxfontsize\plustwo + \ifmmode + \scriptscriptstyle + \else + \font_scale_inherit_xx + \fi + \let\tx \empty + \let\txx\empty + \let\sx \empty + \let\sxx\empty} + +\unexpanded\def\useinheritxsizes{\settrue \c_font_inherit_scale} % not yet public, playground for WS and me +\unexpanded\def\usedefinedxsizes{\setfalse\c_font_inherit_scale} % not yet public, playground for WS and me + +\let\normaltx \tx +\let\normaltxx\txx + +\let\normalsx \sx +\let\normalsxx\sxx + +%D When asking for a complete font switch, for instance from 10 to 12~points, the +%D next macro does the job. First we normalize the size, next we define the current +%D range of text, script and scriptscript sizes, then we set the text fonts and the +%D math families and finally we activate the default typeface and also set the font +%D specific parameters assigned to \type {\everybodyfont}. + +\def\textface {\currentbodyfontdimension\s!text } +\def\scriptface {\currentbodyfontdimension\s!script } +\def\scriptscriptface{\currentbodyfontdimension\s!scriptscript} +\def\xtextface {\currentbodyfontdimension\s!x } +\def\xxtextface {\currentbodyfontdimension\s!xx } + +\installcorenamespace{fontbodyfaces} + +\unexpanded\def\font_basics_complete_switch#size% + {\bodyfontsize#size\relax + \normalizebodyfontsize\normalizedbodyfontsize\bodyfontsize + \expandafter\let\expandafter\font_basics_set_faces\csname\??fontbodyfaces\fontbody\endcsname + \ifx\font_basics_set_faces\relax + \font_basics_set_faces_preset + \fi + \font_basics_set_faces} + +\def\font_basics_set_faces_preset + {\edef\font_basics_set_faces{% 0.2 sec on 10K \tfa + \noexpand\edef\noexpand\textface {\currentbodyfontdimension\s!text }% + \noexpand\edef\noexpand\scriptface {\currentbodyfontdimension\s!script }% + \noexpand\edef\noexpand\scriptscriptface{\currentbodyfontdimension\s!scriptscript}% + \noexpand\edef\noexpand\xtextface {\currentbodyfontdimension\s!x }% + \noexpand\edef\noexpand\xxtextface {\currentbodyfontdimension\s!xx }% + }% + \expandafter\glet\csname\??fontbodyfaces\fontbody\endcsname\font_basics_set_faces} + +\def\currentbodyfontdimension#parameter% there can be factors here + {\the\dimexpr + \ifcsname\??fontenvironments\fontclass\normalizedbodyfontsize#parameter\endcsname + \lastnamedcs + \orelse\ifcsname\??fontenvironments\fontclass\s!default#parameter\endcsname + \lastnamedcs + \dimexpr\normalizedbodyfontsize\relax + \orelse\ifcsname\??fontenvironments\normalizedbodyfontsize#parameter\endcsname + \lastnamedcs + \else + \csname\??fontenvironments\s!default#parameter\endcsname + \dimexpr\normalizedbodyfontsize\relax + \fi + \relax} + +%D \macros +%D {setupbodyfont,switchtobodyfont} +%D +%D The next two macros are user ones. With \type {\setupbodyfont} one can set the +%D document bodyfont size, font family, style and/or options defined in files, for +%D example: +%D +%D \starttyping +%D \setupbodyfont[modern,12pt,roman] +%D \stoptyping +%D +%D This command affects the document as a whole: text, headers and footers. The +%D second macro however affects only the text: +%D +%D \starttyping +%D \switchtobodyfont[10pt] +%D \stoptyping +%D +%D So we've got: +%D +%D \showsetup{setupbodyfont} +%D \showsetup{switchtobodyfont} +%D +%D Both macros look alike. The second one also has to take all kind of keywords into +%D account. + +\ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi +\ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi + +% \newtoks \everysetupbodyfont +% \newtoks \everyswitchtobodyfont + +\unexpanded\def\setupbodyfont + {\doifelsenextoptionalcs\font_basics_setupbodyfont_yes\font_basics_setupbodyfont_nop} + +\def\font_basics_setupbodyfont_nop + {\restoreglobalbodyfont + \saveinterlinespace} + +\def\font_basics_setupbodyfont_yes[#specification]% + {\doifsomething{#specification} + {\font_helpers_set_font\plusone{#specification}% + \globalbodyfontsize\localbodyfontsize + \normalizebodyfontsize\normalizedglobalbodyfontsize\globalbodyfontsize + \let\globalfontstyle\fontstyle + \ifproductionrun + \the\everybodyfont + \the\everyglobalbodyfont + \saveinterlinespace + \fi + \the\everysetupbodyfont}} + +\unexpanded\def\font_basics_switchtobodyfont#specification% + {\edef\m_font_step{\font_bodyfontvariable{#specification}}% + \ifx\m_font_step\empty + \font_helpers_set_font\zerocount{#specification}% + \else + \font_helpers_switch_bodyfont_step % so we have a fast [small] switch + \fi + \the\everybodyfont + \the\everyswitchtobodyfont} + +\unexpanded\def\switchtobodyfont[#specification]% could become an ifx + {\doifsomething{#specification}{\font_basics_switchtobodyfont{#specification}}} + +\unexpanded\def\usebodyfontparameter#1% + {\edef\m_font_bodyfont_asked{#1\c!bodyfont}% + \ifx\m_font_bodyfont_asked\empty\else + \font_basics_switchtobodyfont\m_font_bodyfont_asked + \fi} + +\def\font_helpers_switch_bodyfont_step + {\font_basics_switch_points\m_font_step + \font_basics_switch_style \fontstyle} + +%D The following alternative is meant for math||to||text switching and will be +%D optimized. + +\unexpanded\def\fastswitchtobodyfont#name% + {\ifcsname\??fontenvironments\normalizedbodyfontsize#name\endcsname + %\edef\futurebodyfontsize{\csname\??fontenvironments\normalizedbodyfontsize#name\endcsname}% + \edef\futurebodyfontsize{\lastnamedcs}% + \ifcsname\??fontbodyknown\futurebodyfontsize\endcsname + \font_basics_complete_switch\futurebodyfontsize + \localbodyfontsize\futurebodyfontsize\relax + \fi + \fi + \csname\??fontstyle\fontstyle\endcsname + \the\everybodyfont} + +%D \starttyping +%D $\cases{& \ccaron}$ $x=\hbox{\ccaron $x=\hbox{\ccaron}$}$ +%D \stoptyping + +%D \macros +%D {usebodyfont} +%D +%D This looks nicer then a switch in the preamble +%D +%D \starttyping +%D \usebodyfont[pagella,10pt] +%D \usebodyfont[termes,10pt] +%D \usebodyfont[dejavu,10pt] +%D +%D \setupbodyfont[dejavu] +%D +%D \starttext +%D test +%D \stoptext +%D \stoptyping + +\unexpanded\def\usebodyfont[#1]% + {\ifx\fontclass\empty + \setupbodyfont[#1]% + \else + \switchtobodyfont[#1]% + \fullrestoreglobalbodyfont + \fi} + +\unexpanded\def\showbodyfontstate + {\dontleavehmode + \start + \infofont + [fontclass: \fontclass,\space + fontbody: \fontbody ,\space + fontface: \fontface ,\space + fontsize: \fontsize ]% + \stop} + +%D Handy for manuals: + +%D The \type {\tochar} commmand takes a specification: +%D +%D \starttabulate[|l|l|l|] +%D \NC e \NC entity \NC e:eacute \NC \NR +%D \NC x \NC hexadecimal unicode \NC x:013D \NC \NR +%D \NC d \NC decimal unicode \NC d:123 \NC \NR +%D \NC s \NC hexadecimal index (slot) \NC s:210D \NC \NR +%D \NC i \NC decimal index \NC i:456 \NC \NR +%D \NC n \NC name \NC n:eight \NC \NR +%D \NC c \NC name \NC c:x \NC \NR +%D \NC u \NC unicode descriptions \NC u:dog \NC \NR +%D \NC a \NC all (also descriptions) \NC a:rewind \NC \NR +%D \stoptabulate +%D +%D This is an expandable command! + +\unexpanded\def\fontchar #character{\clf_fontchar{#character}} +\unexpanded\def\fontcharbyindex #index{\clf_fontcharbyindex#index\relax} + \def\tochar #specifications{\clf_tochar{#specifications}} % expanded (also used in edef) + +%D The next auxilliary macro is an alternative to \type {\fontname}. + +\def\purefontname#font{\clf_purefontname{\fontname#font}} + +%D \macros +%D {switchstyleonly} +%D +%D For switching a style but keeping the alternative, there +%D is: +%D +%D \starttyping +%D {\bf text \switchstyleonly\ss text} +%D {\bf text \switchstyleonly[ss]text} +%D {\sl text \switchstyleonly[sansserif]text} +%D \stoptyping + +\unexpanded\def\switchstyleonly + {\doifelsenextoptionalcs\font_basics_switch_style_only_opt\font_basics_switch_style_only_arg} + +\def\font_basics_switch_style_only_arg#name% stupid version + {\font_helpers_set_current_font_style{\csname\??fontshortstyle\checkedstrippedcsname#name\endcsname}% + \the\everybodyfont} % needed ? + +\def\font_basics_switch_style_only_opt[#name]% todo : check + {\font_helpers_set_current_font_style{\csname\??fontshortstyle#name\endcsname}% + \the\everybodyfont} % needed ? + +%D \macros +%D {definebodyfontswitch} +%D +%D \PLAIN\ \TEX\ defines some macro's like \type {\tenpoint} to switch to a specific +%D bodyfontsize. Just for the sake of compatibility we can define them like: +%D +%D \starttyping +%D \definebodyfontswitch [twelvepoint] [12pt] +%D \stoptyping +%D +%D We don't support language specific synonyms here. + +\unexpanded\def\definebodyfontswitch + {\dodoubleargument\font_basics_define_bodyfont_switch} + +\def\font_basics_define_bodyfont_switch[#command][#specification]% no longer a commalist (not useful) + {\setvalue{#command}{\switchtobodyfont[#specification]}}% + +%D \macros +%D {setsmallbodyfont,setmainbodyfont,setbigbodyfont} +%D +%D When we're typesetting at for instance 10pt, we can call for the \type {small} as +%D well as the \type {big} alternative, related to this main size, using \type +%D {\switchtobodyfont[small]}. The three alternatives can be activated by the next +%D three system calls and are defined by the bodyfontenvironment. + +\newmacro\m_font_step + +\def\font_helpers_set_bodyfont_step#step% + {\edef\m_font_step{\font_bodyfontvariable{#step}}% not always \cs + \font_basics_switch_points\m_font_step + \font_basics_switch_style \fontstyle} + +\unexpanded\def\setsmallbodyfont{\font_helpers_set_bodyfont_step\v!small\the\everybodyfont} +\unexpanded\def\setbigbodyfont {\font_helpers_set_bodyfont_step\v!big \the\everybodyfont} + +\unexpanded\def\setmainbodyfont + {\font_basics_switch_points\normalizedbodyfontsize + \font_basics_switch_style\fontstyle + \the\everybodyfont + \the\everyglobalbodyfont + \saveinterlinespace} + +%D \macros +%D {restoreglobalbodyfont} +%D +%D Users can set whatever font available while typesetting text. Pagenumbers, +%D footers, headers etc. however must be typeset in the main bodyfont and style of +%D the document. Returning to the global state can be done with the next macro: +%D +%D This macro has to be called when entering the pagebody handling routine as well +%D as the footnote insert routine. Users can access this feature |<|for instance +%D when one wants to typeset tables and alike in the main bodyfont and style while +%D the running text is temporary set to a smaller one|>| by saying \type +%D {\switchtobodyfont [global]}. + +\let\globalfontstyle\s!rm + +\unexpanded\def\fullrestoreglobalbodyfont + {\let\fontsize\defaultfontsize + \let\fontbody\defaultfontbody + \let\fontface\defaultfontface + \currentxfontsize\zerocount + \let\fontclass\globalfontclass + \font_basics_switch_points\normalizedglobalbodyfontsize + \font_basics_switch_style\globalfontstyle + \redoconvertfont % just in case a pagebreak occurs + \tf + \the\everybodyfont + \the\everyglobalbodyfont + \saveinterlinespace} + +\unexpanded\def\partialrestoreglobalbodyfont + {\let\fontsize\defaultfontsize + \let\fontbody\defaultfontbody + \let\fontface\defaultfontface + \currentxfontsize\zerocount + \redoconvertfont + \tf + \the\everybodyfont % indeed needed + \the\everyglobalbodyfont % indeed needed + \saveinterlinespace} + +\unexpanded\def\restoreglobalbodyfont % ook style etc + {\ifx\fontclass\globalfontclass + \ifx\fontstyle\globalfontstyle + \ifx\normalizedbodyfontsize\normalizedglobalbodyfontsize + \partialrestoreglobalbodyfont + \else + \fullrestoreglobalbodyfont + \fi + \else + \fullrestoreglobalbodyfont + \fi + \else + \fullrestoreglobalbodyfont + \fi} + +% in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont + +%D Here are some fast variants that can be used in cases where no font system is +%D needed and where fonts are frozen: +%D +%D \starttyping +%D \definefont [TestA][Serif at 10pt] +%D \predefinefont[TestB][Serif at 20pt] +%D +%D \testfeatureonce{1000}{{\TestA}} % .312 +%D \testfeatureonce{1000}{{\TestB}} % < .016 +%D \testfeatureonce{1000}{{\definedfont[Serif at 30pt]}} % .312 +%D \testfeatureonce{1000}{{\predefinedfont[Serif at 40pt]}} % < .016 +%D \stoptyping + +\installcorenamespace{predefinedfont} + +\unexpanded\def\predefinefont[#1]#2[#3]% global ! + {\setugvalue{#1}{\font_basics_predefine{#1}{#3}}} + +\unexpanded\def\predefinedfont[#1]% global ! + {\ifcsname\??predefinedfont#1\endcsname + \lastnamedcs + \else + \font_basics_predefined{#1}% + \fi} + +\unexpanded\def\font_basics_predefine#1#2% + {\font_basics_defined_font_yes[#2]% + \expandafter\glet\csname#1\expandafter\endcsname\csname\v_font_identifier_basic\endcsname} + +\unexpanded\def\font_basics_predefined#1% + {\font_basics_predefine{\??predefinedfont#1}{#1}} + +%D Handy helper: + +\unexpanded\def\savedefinedfont[#1]% + {\bgroup + \definedfont[#1]% + \xdef\saveddefinedfontid {\number\fontid\font}% + \xdef\saveddefinedfontname{\fontname\font}% + \egroup} + +\def\saveddefinedfontid {\number\fontid\font} +\def\saveddefinedfontname{\fontname\font} + +%D Ugly helper: + +\unexpanded\def\saverunningstyleandcolor + {\unexpanded\edef\restorerunningstyleandcolor + {\setfontid \number\fontid\font + \attribute\colormodelattribute \the\attribute\colormodelattribute + \attribute\colorattribute \the\attribute\colorattribute + \attribute\transparencyattribute\the\attribute\transparencyattribute + \relax}} + +\let\restorerunningstyleandcolor\relax + +%D Handy for defining additional glyphs: + +\let\getprivateglyphslot\clf_getprivateglyphslot % kind of private macro + +\let\getprivatechar \clf_getprivatechar % gives back a utf ! +\let\getprivatemathchar \clf_getprivatemathchar % gives back a utf ! +\let\getprivateslot \clf_getprivateslot % companion to fonts.helpers.addprivate + +% \unexpanded\def\getprivatemathchar#1% +% {\begingroup\the\textfont\zerocount\getprivatechar{#1}\endgroup} + +\def\privatechar % the text variant gets expanded to utf + {\ifmmode + \expandafter\getprivatemathchar + \else + \expandafter\getprivatechar + \fi} + +%D Some fonts can have color specifiers: +%D +%D \starttyping +%D \definefontfeature[seguiemj-cl][default][colr=yes,ccmp=yes,dist=yes] +%D \definefontsynonym[emoji][seguiemj*seguiemj-cl] +%D +%D \definecolor[emoji-red] [r=.4] +%D \definecolor[emoji-gray][s=1,t=.5,a=1] +%D +%D %definefontcolorpalette [emoji-r] [emoji-red,emoji-gray,textcolor] % bad +%D \definefontcolorpalette [emoji-r] [emoji-red,emoji-gray] % okay +%D +%D \definefontfeature[seguiemj-r][ccmp=yes,dist=yes,colr=emoji-r] +%D +%D \definefont[MyEmojiR][seguiemj*seguiemj-r @ 100pt] +%D +%D \startTEXpage[offset=10pt] +%D \MyEmojiR\resolvedemoji{triangular ruler} +%D \stopTEXpage +%D \stoptyping + +\unexpanded\def\definefontcolorpalette + {\dodoubleargument\font_define_color_palette} + +\def\font_define_color_palette[#1][#2]% + {\clf_definefontcolorpalette{#1}{#2}} + +%D \macros +%D {addfontpath} +%D +%D A way to add a path at runtime (no need to generate database): + +\unexpanded\def\usefontpath[#1]% + {\clf_addfontpath{#1}} + +\protect \endinput diff --git a/tex/context/base/mkiv/font-ini.mkvi b/tex/context/base/mkiv/font-ini.mkvi index 0f29cf155..99e7117a3 100644 --- a/tex/context/base/mkiv/font-ini.mkvi +++ b/tex/context/base/mkiv/font-ini.mkvi @@ -53,8 +53,8 @@ \unprotect -%D There are several ways to specify a font. Three of them are -%D pure \TeX\ ones, the fourth one is new: +%D There are several ways to specify a font. Three of them are pure \TEX\ ones, the +%D fourth one is new: %D %D \starttyping %D \font\name=cmr12 @@ -63,18 +63,15 @@ %D \font\name=cmr12 sa 1.440 %D \stoptyping %D -%D The non||\TEX\ alternative \type{sa} stands for {\em scaled -%D at}. This means as much as: scale the bodyfontsize with this -%D factor. The scaled option is not that useful as one needs to -%D know the design size. +%D The non||\TEX\ alternative \type{sa} stands for {\em scaled at}. This means as +%D much as: scale the bodyfontsize with this factor. The scaled option is not that +%D useful as one needs to know the design size. %D -%D Because \type {sa} (scaled at) and \type {mo} (mapped on) -%D are not low level \TEX\ supported alternatives, we have to -%D test for it ourselves. In doing so, we need an auxiliary -%D \DIMENSION. We cannot use \type{\scratchdimen} because font -%D loading can happen at any moment due to postponed loading. -%D We could instead have used dirty grouping tricks, but this -%D one works too. +%D Because \type {sa} (scaled at) and \type {mo} (mapped on) are not low level \TEX\ +%D supported alternatives, we have to test for it ourselves. In doing so, we need an +%D auxiliary \DIMENSION. We cannot use \type{\scratchdimen} because font loading can +%D happen at any moment due to postponed loading. We could instead have used dirty +%D grouping tricks, but this one works too. % \enableexperiments[fonts.autorscale] % @@ -101,9 +98,8 @@ %D \macros %D {rm,ss,tt,hw,cg} %D -%D Fonts are defined in separate files. When we define a font, -%D we distinguish between several styles. In most cases we will -%D use: +%D Fonts are defined in separate files. When we define a font, we distinguish +%D between several styles. In most cases we will use: %D %D \startlinecorrection %D \starttable[|l||] @@ -115,8 +111,8 @@ %D \stoptable %D \stoplinecorrection %D -%D The number of styles is not limited to these three. When -%D using Lucida Bright we can for instance also define: +%D The number of styles is not limited to these three. When using Lucida Bright we +%D can for instance also define: %D %D \startlinecorrection %D \starttable[|l||] @@ -127,8 +123,8 @@ %D \stoptable %D \stoplinecorrection %D -%D Within such a font set (\type{cmr}) and style (\type{\rm}) -%D we can define a number of text font alternatives: +%D Within such a font set (\type{cmr}) and style (\type{\rm}) we can define a number +%D of text font alternatives: %D %D \startlinecorrection %D \starttable[|l||] @@ -145,12 +141,11 @@ %D \stoplinecorrection %D %D Internally fonts are stored as combination of size, style -%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}. -%D Users are not confronted with sizes, but use the style or -%D style+alternative to activate them. +%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}. Users are not confronted +%D with sizes, but use the style or style+alternative to activate them. %D -%D During the definition of a bodyfont one can also declare the -%D available larger alternatives: +%D During the definition of a bodyfont one can also declare the available larger +%D alternatives: %D %D \starttyping %D \tf \tfa \tfb \tfc ... @@ -167,13 +162,12 @@ %D \slx \slxx %D \stoptyping %D -%D There are only two smaller alternatives per style. The -%D larger alternatives on the other hand have no limitations. +%D There are only two smaller alternatives per style. The larger alternatives on the +%D other hand have no limitations. %D -%D These larger alternatives are mostly used in chapter and -%D section titles or on title pages. When one switches to a -%D larger alternative, the bold an other ones automatically -%D adapt themselves: +%D These larger alternatives are mostly used in chapter and section titles or on +%D title pages. When one switches to a larger alternative, the bold an other ones +%D automatically adapt themselves: %D %D \startbuffer %D \tfd Hi \bf there\sl, here \tfb I \bf am @@ -189,8 +183,8 @@ %D \getbuffer %D \stopexample %D -%D Maybe this mechanism isn't always as logic, but as said -%D before, we tried to make it as intuitive as possible. +%D Maybe this mechanism isn't always as logic, but as said before, we tried to make +%D it as intuitive as possible. %D %D So a specific kind of glyph can be characterized by: %D @@ -200,52 +194,43 @@ %D %D The last component (the size) is optional. %D -%D We introduced \type{\tf} as command to call for the current -%D normally sized typeface. This commands results in roman, -%D sans serif, teletype or whatever style is in charge. Such -%D rather massive switches of style sometimes take more -%D processing time than comfortable. Of course there is a -%D workaround for this: we can call fonts directly by means of -%D commands like: +%D We introduced \type {\tf} as command to call for the current normally sized +%D typeface. This commands results in roman, sans serif, teletype or whatever style +%D is in charge. Such rather massive switches of style sometimes take more +%D processing time than comfortable. Of course there is a workaround for this: we +%D can call fonts directly by means of commands like: %D %D \starttyping %D \rmtf \sssl \tttf \rmbsa %D \stoptyping %D -%D One should realize that this fast calls have limitations, -%D they lack for instance automatic super- and subscript -%D support. -%D -%D This leaves us two more commands: \type{\tx} and -%D \type{\txx}. These activate a smaller and even more smaller -%D font than the current one and adapt themselves to the -%D current alternative, so when \type{\bf} is active, -%D \type{\tx} gives a smaller boldface, which in turn can be -%D called directly by \type{\bfx}. -%D -%D These two smaller alternatives are specified by the bodyfont -%D environment and therefore not necessarily have similar sizes -%D as \type{\scriptsize} and \type{\scriptscriptsize}. The main -%D reason for this incompatibility (which can easily be undone) -%D lays in the fact that we often want a bit bigger characters -%D than in math mode. In \CONTEXT\ for instance the \type{\tx} -%D and \type{\txx} commands are used for surrogate -%D \cap{smallcaps} which support both nesting and alternatives, -%D like in {\bf\cap{a \cap{small} world}}, which was typeset by +%D One should realize that this fast calls have limitations, they lack for instance +%D automatic super- and subscript support. +%D +%D This leaves us two more commands: \type {\tx} and \type {\txx}. These activate a +%D smaller and even more smaller font than the current one and adapt themselves to +%D the current alternative, so when \type {\bf} is active, \type {\tx} gives a +%D smaller boldface, which in turn can be called directly by \type {\bfx}. +%D +%D These two smaller alternatives are specified by the bodyfont environment and +%D therefore not necessarily have similar sizes as \type {\scriptsize} and \type +%D {\scriptscriptsize}. The main reason for this incompatibility (which can easily +%D be undone) lays in the fact that we often want a bit bigger characters than in +%D math mode. In \CONTEXT\ for instance the \type {\tx} and \type {\txx} commands +%D are used for surrogate \cap {smallcaps} which support both nesting and +%D alternatives, like in {\bf \cap {a \cap {small} world}}, which was typeset by %D %D \starttyping %D \bf\cap{a \cap{small} world} %D \stoptyping %D -%D And compare $\rm \scriptstyle THIS$ with the slightly larger -%D \cap{THIS}: \ruledhbox{$\rm \scriptstyle scriptstyle: THIS$} -%D or \ruledhbox{\cap{x style: THIS}} makes a big difference. +%D And compare $\rm \scriptstyle THIS$ with the slightly larger \cap {THIS}: +%D \ruledhbox {$\rm \scriptstyle scriptstyle: THIS$} or \ruledhbox {\cap {x style: +%D THIS}} makes a big difference. %D -%D The \type{x..d} sizes should be used grouped. If you -%D don't group them, i.e. call them in a row, \CONTEXT\ will -%D not be able to sort out your intention (\type {x} inside -%D \type {d} inside \type {x}. etc.). The following table -%D demonstrates this: +%D The \type {x..d} sizes should be used grouped. If you don't group them, i.e. call +%D them in a row, \CONTEXT\ will not be able to sort out your intention (\type {x} +%D inside \type {d} inside \type {x}. etc.). The following table demonstrates this: %D %D \def\FontState{\setstrut\ruledhbox{\strut Hello}} %D @@ -398,10 +383,9 @@ %D \macros %D {everybodyfont,everyglobalbodyfont} %D -%D Every change in bodyfont size has conseqences for the baseline -%D distance and skips between paragraphs. These are initialized -%D in other modules. Here we only provide the hooks that -%D garantees their handling. +%D Every change in bodyfont size has conseqences for the baseline distance and skips +%D between paragraphs. These are initialized in other modules. Here we only provide +%D the hooks that garantees their handling. %D %D At the system level one can initialize thing like: %D @@ -411,20 +395,19 @@ %D \macros %D {globalbodyfontsize,localbodyfontsize,bodyfontsize} - -%D Here we have to distinguish between the global (overal) bodyfont -%D size and the local (sometimes in the textflow) size. We store -%D these dimensions in two \DIMENSION\ registers. These registers are -%D not to be misused in calculations. +%D +%D Here we have to distinguish between the global (overal) bodyfont size and the +%D local (sometimes in the textflow) size. We store these dimensions in two +%D \DIMENSION\ registers. These registers are not to be misused in calculations. \ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt \ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize \ifdefined\bodyfontsize \else \newdimen\bodyfontsize \fi \bodyfontsize =\globalbodyfontsize -%D When we assign for instance 12pt to a \DIMENSION\ register the \type -%D {\the}'d value comes out as 12.0pt, which is often not the way users -%D specify the bodyfont size. Therefore we use normalized values. They -%D are cached to save overhead in \LUA\ calls. +%D When we assign for instance 12pt to a \DIMENSION\ register the \type {\the}'d +%D value comes out as 12.0pt, which is often not the way users specify the bodyfont +%D size. Therefore we use normalized values. They are cached to save overhead in +%D \LUA\ calls. % \setnewconstant\fontdigits\plustwo % from now on always 2 @@ -465,11 +448,10 @@ %D \macros %D {mapfontsize} %D -%D For special purposes, like in math, you may want to use -%D slightly different sizes than the ones given. This happens -%D for instance with the Math Times fonts. Mapped font sizes -%D can be specified by using the \type {mo} key instead of -%D \type {sa} in font definitions. +%D For special purposes, like in math, you may want to use slightly different sizes +%D than the ones given. This happens for instance with the Math Times fonts. Mapped +%D font sizes can be specified by using the \type {mo} key instead of \type {sa} in +%D font definitions. %D %D \startbuffer %D \mapfontsize[10pt][11pt] @@ -558,10 +540,9 @@ %D \macros %D {definefontstyle,definefontsize,definefontalternative} %D -%D When setting of switching the overall style we can use the -%D short identifier like rm and ss, but when defined we can -%D also use more verbose names like roman or sansserif. Such -%D names are defined by: +%D When setting of switching the overall style we can use the short identifier like +%D rm and ss, but when defined we can also use more verbose names like roman or +%D sansserif. Such names are defined by: %D %D \starttyping %D \definefontstyle [serif,rm] [rm] @@ -633,12 +614,12 @@ \definefontstyle [\s!ss] [\s!ss] \definefontstyle [\s!tt] [\s!tt] -%D We define all the font switching commands globally. After all they are part -%D of the formal font interface once defined. The size can be empty (so -%D checking is needed as \type {\bf} is already defined) - -%D The \type {\normal..} variants are available as extras for cases where -%D the \type {..} is overloaded. +%D We define all the font switching commands globally. After all they are part of +%D the formal font interface once defined. The size can be empty (so checking is +%D needed as \type {\bf} is already defined). +%D +%D The \type {\normal..} variants are available as extras for cases where the \type +%D {..} is overloaded. \newmacro\m_font_mm @@ -724,23 +705,20 @@ %D Scaling macros: %D -%D This system is somewhat complicated by two (possible conflicting) -%D demands: +%D This system is somewhat complicated by two (possible conflicting) demands: %D %D \startitemize -%D \item We support wildcards like \type {sa *} which will adapt -%D to the current size. This is also the default specification. -%D \item We support named scales like \type {sa d}; beware: \type -%D {x} and \type {xx} are valid scales but they are not alway -%D the same as the ones used in for instance \type {\bfx} because -%D there the sized come from the bodyfont environment. In the -%D future there maybe a switch that also honors the environment -%D in named scales. +%D \item We support wildcards like \type {sa *} which will adapt to the current +%D size. This is also the default specification. +%D \item We support named scales like \type {sa d}; beware: \type {x} and \type {xx} +%D are valid scales but they are not alway the same as the ones used in for +%D instance \type {\bfx} because there the sized come from the bodyfont +%D environment. In the future there maybe a switch that also honors the +%D environment in named scales. %D \stopitemize %D -%D Keep in mind that the smaller sizes are just for text super and -%D subscripts while larger sizes can be used in titles where for -%D instance math follows the size. +%D Keep in mind that the smaller sizes are just for text super and subscripts while +%D larger sizes can be used in titles where for instance math follows the size. % b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par % 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par @@ -993,8 +971,7 @@ %D %D We also accept \type{sa a}||\type{sa d} as specification. %D -%D Before we implement the main definition macro, we first show -%D one for local use: +%D Before we implement the main definition macro, we first show one for local use: %D %D \starttyping %D \definefont[Some][LucidaBright at 100pt] \Some some @@ -1120,9 +1097,8 @@ %D \macros %D {currentfontbodyscale} %D -%D Sometimes we need to have access to the font scale -%D including the \type{a}||\type{d} sizes. The next macro -%D returns the current scaling factor. Take a look at +%D Sometimes we need to have access to the font scale including the \type {a}||\type +%D {d} sizes. The next macro returns the current scaling factor. Take a look at %D \type {cont-log.tex} for an example of its use. \installcorenamespace{fontenvironments} @@ -1192,30 +1168,27 @@ \setvalue{\??fontenvironments\s!default}{1} -%D In the following macros we use \type{\currentxfontsize} to -%D hold the current x||size of the font. This enables us to -%D support for instance \type{\sl} inside a \type{\tx} switch. +%D In the following macros we use \type {\currentxfontsize} to hold the current +%D x||size of the font. This enables us to support for instance \type {\sl} inside a +%D \type {\tx} switch. \newconstant\currentxfontsize \def\xfontsize{\ifcase\currentxfontsize\fontsize\or\s!x\else\s!xx\fi} -%D Now we enter the area of font switching. The switching -%D mechanism has to take care of several situations, like: +%D Now we enter the area of font switching. The switching mechanism has to take care +%D of several situations, like: %D %D \startitemize[packed] -%D \item changing the overal document fonts (including margins, -%D headers and footers) -%D \item changing local fonts (only the running text) -%D \item smaller and even more smaller alternatives (super- -%D and subscripts) +%D \item changing the overal document fonts (including margins, headers and footers) +%D \item changing local fonts (only the running text) +%D \item smaller and even more smaller alternatives (super- and subscripts) %D \stopitemize %D -%D \TEX\ offers a powerfull family mechanism for super- and -%D subscripts in math mode. In text mode however, we don't use -%D families for the smaller alternatives, and therefore have -%D to take care of it otherwise. - +%D \TEX\ offers a powerfull family mechanism for super- and subscripts in math mode. +%D In text mode however, we don't use families for the smaller alternatives, and +%D therefore have to take care of it otherwise. +%D %D \macros %D {definebodyfontenvironment,setupbodyfontenvironment} %D @@ -1224,8 +1197,8 @@ %D %D \showsetup{definebodyfontenvironment} %D -%D Later on we will see how these parameters are used, so for -%D the moment we stick with an example: +%D Later on we will see how these parameters are used, so for the moment we stick +%D with an example: %D %D \starttyping %D \definebodyfontenvironment @@ -1239,9 +1212,9 @@ %D small=10pt] %D \stoptyping %D -%D The first argument specifies the bodyfont size to which the -%D settings apply. All second parameters are specified in -%D dimensions and tell us more about related sizes. +%D The first argument specifies the bodyfont size to which the settings apply. All +%D second parameters are specified in dimensions and tell us more about related +%D sizes. %D %D Afterwards, one can change values with %D @@ -1251,8 +1224,8 @@ %D passed, fractions (relations) are used instead of fixed %D sizes. -%D {\bf Remark:} We need to cover the following cases, otherwise users can -%D get confused: +%D {\bf Remark:} We need to cover the following cases, otherwise users can get +%D confused: %D %D \starttyping %D \setupbodyfont[23pt] @@ -1265,10 +1238,9 @@ %D \setupbodyfont[23pt] %D \stoptyping %D -%D Beware: while some font defs can be global, the bodyfont -%D environment checks local. This means that multiple local -%D checks resulting in definitions are not that efficient. -%D So, apart from an occasional switch, one should define an +%D Beware: while some font defs can be global, the bodyfont environment checks +%D local. This means that multiple local checks resulting in definitions are not +%D that efficient. So, apart from an occasional switch, one should define an %D environment at the outer level. % \definebodyfontenvironment[33pt] @@ -1383,8 +1355,8 @@ \clf_registerbodyfontsize{\m_font_body_normalized}% \fi} -%D The empty case uses the same code but needs to ignore the current class -%D settings (just to be sure, as it's not really needed). +%D The empty case uses the same code but needs to ignore the current class settings +%D (just to be sure, as it's not really needed). \def\font_basics_define_body_font_environment_empty[#body][#settings][#dummy]% {\push_macro_fontclass @@ -1433,36 +1405,33 @@ \font_helpers_define_unknown_font{#normalizedbody}% \fi} -%D We default all parameters to the main bodyfont size, so the next -%D setup is valid too: +%D We default all parameters to the main bodyfont size, so the next setup is valid +%D too: %D %D \starttyping %D \definebodyfontenvironment[24pt] %D \stoptyping %D -%D All parameters can be redefined when needed, so one doesnot have to -%D stick to the default ones. +%D All parameters can be redefined when needed, so one doesnot have to stick to the +%D default ones. %D \macros %D {definebodyfont} %D -%D The next step in defining a bodyfont involves the actual font -%D files, which can be recognized by their extension -%D \type{tfm}. Installing those file is often beyond the -%D scope of the user and up to the system administrator. +%D The next step in defining a bodyfont involves the actual font files, which can be +%D recognized by their extension \type {tfm}. Installing those file is often beyond +%D the scope of the user and up to the system administrator. %D %D \showsetup{definebodyfont} %D -%D This commands takes three arguments: a (series of) bodyfont -%D size(s), the style group to which the definitions belong, -%D and an alternative, as specified by the \TEX\ (math) families, -%D extended with~a, b~\unknown. +%D This commands takes three arguments: a (series of) bodyfont size(s), the style +%D group to which the definitions belong, and an alternative, as specified by the +%D \TEX\ (math) families, extended with~a, b~\unknown. %D -%D We show two examples, that show all the alternative -%D scaling options. The \type{\tfa} alternatives can be -%D extended with \type{\bfa}, \type{\slb}, etc. or even -%D \type{e} and higher alternatives. The magic scaled -%D values are derived from plain \TEX's \type {\magstep}: +%D We show two examples, that show all the alternative scaling options. The \type +%D {\tfa} alternatives can be extended with \type {\bfa}, \type {\slb}, etc. or even +%D \type {e} and higher alternatives. The magic scaled values are derived from plain +%D \TEX's \type {\magstep}: %D %D \starttyping %D \definebodyfont [12pt] [rm] @@ -1492,29 +1461,25 @@ %D sc=lbr sa 0.833] %D \stoptyping %D -%D The second example shows that we can define more sizes at -%D once. The main difference between these examples is that the -%D Computer Modern Roman come in many design sizes. This means -%D that there we cannot define them in bulk using \type{sa}. -%D Instead of \type{rm} (roman) one can define \type{ss} (sans -%D serif), \type{tt} (teletype), \type{hw} (hand written), -%D \type{cg} (calygraphic) and whatever styles. -%D -%D The first argument may be a comma separated list. This, -%D combined with specifications using \type{sa} can save a lot -%D of typing. Although all arguments should be specified, we -%D treat the second argument as optional. -%D -%D Defining a bodyfont involves two actions: defining the -%D specific style related alternatives, like \type{\rma}, -%D \type{\bfa} and \type{\rmsla}, and storing the definitions -%D of their bodyfont size related fonts. The first step is -%D bodyfont independant but executed every time. This permits -%D user definitions like \type{\tfw} or \type{\bfq} for real -%D large alternatives. - -%D If we move design size info to the lfg file (after all only lm -%D has design sizes) we can get rid of much code .. 2012 or so. +%D The second example shows that we can define more sizes at once. The main +%D difference between these examples is that the Computer Modern Roman come in many +%D design sizes. This means that there we cannot define them in bulk using \type +%D {sa}. Instead of \type {rm} (roman) one can define \type {ss} (sans serif), \type +%D {tt} (teletype), \type {hw} (hand written), \type {cg} (calygraphic) and whatever +%D styles. +%D +%D The first argument may be a comma separated list. This, combined with +%D specifications using \type{sa} can save a lot of typing. Although all arguments +%D should be specified, we treat the second argument as optional. +%D +%D Defining a bodyfont involves two actions: defining the specific style related +%D alternatives, like \type {\rma}, \type {\bfa} and \type {\rmsla}, and storing the +%D definitions of their bodyfont size related fonts. The first step is bodyfont +%D independant but executed every time. This permits user definitions like \type +%D {\tfw} or \type {\bfq} for real large alternatives. +%D +%D If we move design size info to the lfg file (after all only lm has design sizes) +%D we can get rid of much code .. 2012 or so. \installcorenamespace{fontdefinitions} @@ -1651,9 +1616,9 @@ \let\font_basics_define_body_font_defs_nop\font_basics_define_body_font_defs_nop_traced \to \t_font_tracers_definitions -% We split into two characters (first part of spec) and the rest: the first two are the style and -% the rest is a size, although in practice one will seldom define the size directly. We might even -% drop that as it gives faster code. +%D We split into two characters (first part of spec) and the rest: the first two are +%D the style and the rest is a size, although in practice one will seldom define the +%D size directly. We might even drop that as it gives faster code. \unexpanded\def\font_basics_define_body_font_nop_xx[#one#two#rest=#value]% local {\ifcsname\m_font_asked_style#one#two#rest\endcsname\else\font_basics_check_fontname_combination\m_font_asked_style{#one#two}{#rest}\fi @@ -1844,9 +1809,8 @@ \showmessage\m!fonts5{#style}% \fi} -%D Here comes the main font switching macros. These macros -%D handle changes in size as well as returning to the global -%D bodyfont size. +%D Here comes the main font switching macros. These macros handle changes in size as +%D well as returning to the global bodyfont size. \ifdefined\font_preloads_at_definition \else \let\font_preloads_at_definition\relax \fi @@ -2022,8 +1986,8 @@ \the\everyfontswitch \fi} -%D This is the resolver for special cases (sizes) and in practice it is not called that often -%D so further optimization makes no sense. +%D This is the resolver for special cases (sizes) and in practice it is not called +%D that often so further optimization makes no sense. \def\font_helpers_check_strategy_class_a % --- --- --- --- % pt tt bf a {\ifcsname\??fontinstanceready\fontclass-\fontbody-\fontstyle-\fontalternative-\fontsize-\fontface\endcsname @@ -2135,12 +2099,11 @@ \fi \to \everybodyfont -%D Setting the normal sizes as well as the x and xx smaller -%D sizes is accomplished by the next set of macros. When in -%D math mode, the commands \type{\tx} and \type{\txx} are -%D just a switch to the script and double script styles, but -%D in text mode the values defined by the bodyfontenvironment are -%D used. Here we also set \type{\currentxfontsize}. +%D Setting the normal sizes as well as the x and xx smaller sizes is accomplished by +%D the next set of macros. When in math mode, the commands \type {\tx} and \type +%D {\txx} are just a switch to the script and double script styles, but in text mode +%D the values defined by the bodyfontenvironment are used. Here we also set \type +%D {\currentxfontsize}. \def\font_helpers_set_current_font_xxx_alternative#alternative#xsize#scriptstyle% {\ifmmode @@ -2181,15 +2144,14 @@ \let\tx\empty \let\txx\empty} -% This alterative is not really needed, but for old time's sake -% we keep it there. We can speed it up when needed. +%D This alterative is not really needed, but for old time's sake we keep it there. +%D We can speed it up when needed. \def\font_helpers_set_current_font_x_style_alternative #alternative{\csname#alternative\endcsname\tx} \def\font_helpers_set_current_font_xx_style_alternative#alternative{\csname#alternative\endcsname\txx} -%D These macros also show us that when we call for \type{\tx}, -%D this macro is redefined to be \type{\txx}. Therefore calls -%D like: +%D These macros also show us that when we call for \type {\tx}, this macro is +%D redefined to be \type {\txx}. Therefore calls like: %D %D \startbuffer %D {small \tx is \tx beautiful} @@ -2206,9 +2168,8 @@ %D \getbuffer %D \stoplines %D -%D Setting the main size involves the style list and therefore -%D takes a bit more time. Keep in mind that the fontsize is -%D represented by a character or empty. +%D Setting the main size involves the style list and therefore takes a bit more +%D time. Keep in mind that the fontsize is represented by a character or empty. % \unexpanded\def\tx {\font_helpers_set_current_font_x_alternative \fontalternative} % \unexpanded\def\txx{\font_helpers_set_current_font_xx_alternative\fontalternative} @@ -2343,13 +2304,11 @@ \let\normalsx \sx \let\normalsxx\sxx -%D When asking for a complete font switch, for instance from 10 -%D to 12~points, the next macro does the job. First we -%D normalize the size, next we define the current range of -%D text, script and scriptscript sizes, then we set the text -%D fonts and the math families and finally we activate the -%D default typeface and also set the font specific parameters -%D assigned to \type{\everybodyfont} +%D When asking for a complete font switch, for instance from 10 to 12~points, the +%D next macro does the job. First we normalize the size, next we define the current +%D range of text, script and scriptscript sizes, then we set the text fonts and the +%D math families and finally we activate the default typeface and also set the font +%D specific parameters assigned to \type {\everybodyfont}. \def\textface {\currentbodyfontdimension\s!text } \def\scriptface {\currentbodyfontdimension\s!script } @@ -2416,16 +2375,16 @@ %D \macros %D {setupbodyfont,switchtobodyfont} %D -%D The next two macros are user ones. With \type{\setupbodyfont} -%D one can set the document bodyfont size, font family, style -%D and/or options defined in files, for example: +%D The next two macros are user ones. With \type {\setupbodyfont} one can set the +%D document bodyfont size, font family, style and/or options defined in files, for +%D example: %D %D \starttyping %D \setupbodyfont[modern,12pt,roman] %D \stoptyping %D -%D This command affects the document as a whole: text, headers -%D and footers. The second macro however affects only the text: +%D This command affects the document as a whole: text, headers and footers. The +%D second macro however affects only the text: %D %D \starttyping %D \switchtobodyfont[10pt] @@ -2436,8 +2395,8 @@ %D \showsetup{setupbodyfont} %D \showsetup{switchtobodyfont} %D -%D Both macros look alike. The second one also has to take -%D all kind of keywords into account. +%D Both macros look alike. The second one also has to take all kind of keywords into +%D account. \ifx\saveinterlinespace \undefined \let\saveinterlinespace \relax \fi \ifx\restoreinterlinespace\undefined \let\restoreinterlinespace\relax \fi @@ -2488,8 +2447,8 @@ {\font_basics_switch_points\m_font_step \font_basics_switch_style \fontstyle} -%D The following alternative is meant for math||to||text -%D switching and will be optimized. +%D The following alternative is meant for math||to||text switching and will be +%D optimized. \unexpanded\def\fastswitchtobodyfont#name% {\ifcsname\??fontenvironments\normalizedbodyfontsize#name\endcsname @@ -2608,9 +2567,8 @@ %D \macros %D {definebodyfontswitch} %D -%D \PLAIN\ \TEX\ defines some macro's like \type{\tenpoint} -%D to switch to a specific bodyfontsize. Just for the sake of -%D compatibility we can define them like: +%D \PLAIN\ \TEX\ defines some macro's like \type {\tenpoint} to switch to a specific +%D bodyfontsize. Just for the sake of compatibility we can define them like: %D %D \starttyping %D \definebodyfontswitch [twelvepoint] [12pt] @@ -2627,11 +2585,10 @@ %D \macros %D {setsmallbodyfont,setmainbodyfont,setbigbodyfont} %D -%D When we're typesetting at for instance 10pt, we can call for -%D the \type{small} as well as the \type{big} alternative, -%D related to this main size, using \type{\switchtobodyfont[small]}. -%D The three alternatives can be activated by the next three -%D system calls and are defined by the bodyfontenvironment. +%D When we're typesetting at for instance 10pt, we can call for the \type {small} as +%D well as the \type {big} alternative, related to this main size, using \type +%D {\switchtobodyfont[small]}. The three alternatives can be activated by the next +%D three system calls and are defined by the bodyfontenvironment. \newmacro\m_font_step @@ -2653,17 +2610,15 @@ %D \macros %D {restoreglobalbodyfont} %D -%D Users can set whatever font available while typesetting text. -%D Pagenumbers, footers, headers etc. however must be typeset -%D in the main bodyfont and style of the document. Returning to -%D the global state can be done with the next macro: +%D Users can set whatever font available while typesetting text. Pagenumbers, +%D footers, headers etc. however must be typeset in the main bodyfont and style of +%D the document. Returning to the global state can be done with the next macro: %D -%D This macro has to be called when entering the pagebody -%D handling routine as well as the footnote insert routine. -%D Users can access this feature |<|for instance when one wants -%D to typeset tables and alike in the main bodyfont and style -%D while the running text is temporary set to a smaller one|>| -%D by saying \type{\switchtobodyfont[global]}. +%D This macro has to be called when entering the pagebody handling routine as well +%D as the footnote insert routine. Users can access this feature |<|for instance +%D when one wants to typeset tables and alike in the main bodyfont and style while +%D the running text is temporary set to a smaller one|>| by saying \type +%D {\switchtobodyfont [global]}. \let\globalfontstyle\s!rm @@ -2709,8 +2664,8 @@ % in case of troubles: \let\restorebodyfont\fullrestoreglobalbodyfont -%D Here are some fast variants that can be used in cases where no font -%D system is needed and where fonts are frozen: +%D Here are some fast variants that can be used in cases where no font system is +%D needed and where fonts are frozen: %D %D \starttyping %D \definefont [TestA][Serif at 10pt] diff --git a/tex/context/base/mkiv/font-mat.mklx b/tex/context/base/mkiv/font-mat.mklx new file mode 100644 index 000000000..d08a2ce87 --- /dev/null +++ b/tex/context/base/mkiv/font-mat.mklx @@ -0,0 +1,500 @@ +%D \module +%D [ file=font-mat, +%D version=2011.01.13, % (copied fron font-ini) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Math, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Font Macros / Math} + +\unprotect + +%D Be nice: + +\ifdefined\??fontinstanceready \else \installcorenamespace{fontinstanceready} \fi +\ifdefined\??fontinstancebasic \else \installcorenamespace{fontinstancebasic} \fi +\ifdefined\??fontinstanceclass \else \installcorenamespace{fontinstanceclass} \fi + +%D The order 3 2 1 of siuze matters: needed for math-fbk relative size storage! + +%D \macros +%D {textonly} +%D +%D Traditionally math has a big impact on font definitions, mainly because we need +%D to define alphabet variants using families and fonts. This means that one can +%D easily get 10 fonts loaded per math size. In \MKIV\ we use a different approach: +%D one family which has either a virtual font made of traditional fonts, or an +%D \OPENTYPE\ font that has it all. +%D +%D We currently use only one math family but in the future we might consider using a +%D second one for bold math. For the moment we keep the \MKII\ method of using a +%D token register for definitions but we already dropped the text and symbols ones +%D since they now live in the same family. + +\newtoks \t_font_math_strategies +\newconditional\c_font_synchronize_math_fonts \settrue\c_font_synchronize_math_fonts + +\unexpanded\def\font_helpers_synchronize_math % math stuff in mmode + {\ifconditional\c_font_synchronize_math_fonts\the\t_font_math_strategies\fi} + +\unexpanded\def\textonly{\setfalse\c_font_synchronize_math_fonts} % document this + +%D The main math font definer. We have removed some optimized code simply because we +%D now always have a fontclass. We could check for fontclass being default or empty +%D and save a few tests but it does not help us when no math is defined. +%D +%D Because we want to keep mr=.. and mb=... settings (read: not break downward +%D compatibility by enforcing mrlr etc) we need a bit more code that optimal. + +% todo: \c_font_fam_mr + +\let\c_font_fam_mr \zerocount % math regular +\let\c_font_fam_mr_lr\plusone % math regular l2r +\let\c_font_fam_mr_rl\plustwo % math regular r2l + +\let\c_font_fam_mb \plusthree % math bold +\let\c_font_fam_mb_lr\plusfour % math bold l2r +\let\c_font_fam_mb_rl\plusfive % math bold r2l + +\definesystemattribute[mathfamily][public] + +\newconditional\c_font_bidirectional_mathstrategy % can be default, not that much overhead: \settrue\c_font_bidirectional_mathstrategy +\newconditional\c_font_complete_bold_mathstrategy \settrue\c_font_complete_bold_mathstrategy + +\def\mathtextsuffix {-text} +\def\mathscriptsuffix {-script} +\def\mathscriptscriptsuffix{-scriptscript} + +\def\mathsizesuffix{\ifcase\fontface\or\mathtextsuffix\or\mathscriptsuffix\or\mathscriptscriptsuffix\fi} + +%D Beware: truefontname also does a fallback on defaultfontclass so there +%D can be some interference here, which is why we use a different method +%D for bold. + +\def\font_helpers_set_math_family_a + {\ifcsname\??fontinstanceready\fontclass -\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size + \lastnamedcs \orelse + \ifcsname\??fontinstanceready\fontclass -\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size + \lastnamedcs \else + \font_helpers_set_math_family_b + \fi} + +\def\font_helpers_set_math_family_b + {\ifcsname\??fontinstanceready\defaultfontclass-\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size + \lastnamedcs \orelse + \ifcsname\??fontinstanceready\defaultfontclass-\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size + \lastnamedcs \else + \font_helpers_set_math_family_c + \fi} + +\def\font_helpers_set_math_family_c + {\ifcsname\??fontinstanceready \fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size + \lastnamedcs \orelse + \ifcsname\??fontinstanceready \fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size + \lastnamedcs \else + \settrue \c_font_auto_size + \fi} + +\let\mathsizesuffix\empty + +\def\font_helpers_set_math_family_indeed#mrtag#family% \fontface etc are also used later on + {\let\savedfontbody\fontbody + \let\fontfamily#family% + % the order is important as we depend on known id's when completing fonts + % enabling is needed when we have fallbacks which spoils the families + \let\mathsizesuffix\mathscriptscriptsuffix\let\fontface\!!plusthree + \font_helpers_set_math_family_a\scriptscriptfont#mrtag\font % defines + \font_helpers_set_math_family_a\scriptscriptfont#mrtag\font % enables + \let\mathsizesuffix\mathscriptsuffix \let\fontface\!!plustwo + \font_helpers_set_math_family_a\scriptfont #mrtag\font % defines + \font_helpers_set_math_family_a\scriptfont #mrtag\font % enables + \let\mathsizesuffix\mathtextsuffix \let\fontface\!!plusone + \font_helpers_set_math_family_a\textfont #mrtag\font % defines + \font_helpers_set_math_family_a\textfont #mrtag\font % enables + \let\mathsizesuffix\empty \let\fontface\!!zerocount + \let\fontbody\savedfontbody + \setfalse\c_font_auto_size} + +\def\font_helpers_set_math_family_bold_a#font#mbfam#mrfam% + {\ifcsname\??fontinstanceready\fontclass-\fontbody-\s!mm-\fontfamily-\fontsize\endcsname \setfalse\c_font_auto_size + \lastnamedcs #font#mbfam\font \orelse + \ifcsname\??fontinstanceready\fontclass-\fontbody-\s!mm-\fontfamily \endcsname \settrue \c_font_auto_size + \lastnamedcs #font#mbfam\font \else + #font#mbfam#font#mrfam% + \fi} + +\def\font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam% \c_font_fam_mb \s!mb \c_font_fam_mr + {\let\savedfontclass\defaultfontclass + \let\defaultfontclass\fontclass % else truefontname falls back on the wrong one + \let\savedfontbody\fontbody + \let\fontfamily#familytag% + \let\mathsizesuffix\mathscriptscriptsuffix\let\fontface\!!plusthree + \font_helpers_set_math_family_bold_a\scriptscriptfont#mbfam#mrfam% defines + \font_helpers_set_math_family_bold_a\scriptscriptfont#mbfam#mrfam% enables + \let\mathsizesuffix\mathscriptsuffix \let\fontface\!!plustwo + \font_helpers_set_math_family_bold_a\scriptfont #mbfam#mrfam% defines + \font_helpers_set_math_family_bold_a\scriptfont #mbfam#mrfam% enables + \let\mathsizesuffix\mathtextsuffix \let\fontface\!!plusone + \font_helpers_set_math_family_bold_a\textfont #mbfam#mrfam% defines + \font_helpers_set_math_family_bold_a\textfont #mbfam#mrfam% enables + \let\mathsizesuffix\empty \let\fontface\!!zerocount + \let\fontbody\savedfontbody + \let\defaultfontclass\savedfontclass + \setfalse\c_font_auto_size} + +% optimized: math fonts are never changed (10K \bfa $x$: 3.2 => 2.5 (baseline 1.0)) +% +% sort of tricky: we cannot reset in \everybeforedefinetypeface as we don't know +% all sizes so we postpone the optimization to the first starttext +% +% pitfall: we should reset 'm when a fontclass name is reused + +\newconditional\optimizemathfontdefinitions \settrue\optimizemathfontdefinitions + +\def\font_helpers_set_math_family#mrfam#familytag% + {\ifconditional\optimizemathfontdefinitions + \ifcsname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname + % \writestatus{fonts}{math: reusing \fontclass\fontbody\s!mm#familytag\fontsize1}% + \font_helpers_preset_math_family_indeed#mrfam#familytag% + \else + % \writestatus{fonts}{math: defining \fontclass\fontbody\s!mm#familytag\fontsize1}% + \font_helpers_set_math_family_indeed#mrfam#familytag% + \fi + \else + \font_helpers_set_math_family_indeed#mrfam#familytag% + \fi} + +\def\font_helpers_set_math_family_bold#mbfam#familytag#mrfam% + {\ifconditional\optimizemathfontdefinitions + %\ifcsname\??fontinstanceclass\fontclass-\textface-\s!mm-#familytag-\fontsize-1\endcsname + \ifcsname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname + \font_helpers_preset_math_family_indeed#mbfam#familytag% + \else + \font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam% + \fi + \else + \font_helpers_set_math_family_bold_indeed#mbfam#familytag#mrfam% + \fi} + +%D It can happen that we use a bodyfont with no math in which case we have a problem +%D with setting the global bodyfont size in the page builder. For instance in: +%D +%D \starttext +%D \definetypeface[test][rm][serif][pagella][default] +%D \setupbodyfont[test] +%D test +%D \stoptext +%D +%D This is why we need the check. At the cost of some extra checking we gain a +%D little in restoring global states and, what's more important, we get rid of large +%D math parameter push/pop in tracingall when not needed. + +\def\font_helpers_preset_math_family_indeed#fam#familytag% + {\expandafter\let\expandafter\v_font_math_one\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-1\endcsname + \ifx\v_font_math_one\relax + \font_helpers_preset_math_family_warning + \orelse\ifnum\fontid\textfont#fam=\fontid\v_font_math_one\else + \font_helpers_preset_math_family_indeed_changed#fam#familytag% + \fi} + +\def\font_helpers_preset_math_family_warning + {\writestatus{fonts}{math: unset for global bodyfont \fontclass\space at \fontbody}} + +\def\font_helpers_preset_math_family_indeed_changed#fam#familytag% + {\scriptscriptfont#fam\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-3\endcsname + \scriptfont #fam\csname\??fontinstanceclass\fontclass-\fontbody-\s!mm-#familytag-\fontsize-2\endcsname + \textfont #fam\v_font_math_one} + +\let\font_helpers_reset_fontclass_math_families\gobbleoneargument + +%D It would be nice if characters could be defined in a neutral way (say fam 255) +%D and be mapped to a real family during noad list construction. However, this +%D changes tex in critical places so for the moment we simulate this using +%D manipulation. +%D +%D For tracing purposes we use three families but in l2r mode 1 and 2 are copies of +%D 0 while in rl mode 0 is a copy of 1. There is no real overhead involved in this. +%D This also permits different font definitions for normal and mixed. + +\let\m_font_class_direction\empty +\let\m_font_class_features \empty +\let\m_font_class_fallbacks\empty +\let\m_font_class_goodies \empty + +\let\m_font_direction\empty +\let\m_font_features \empty +\let\m_font_fallbacks\empty +\let\m_font_goodies \empty + +\appendtoks % can be analyzed once + % why here .. + %\edef\m_font_class_direction{\ifcsname\??fontclass\fontclass\s!mm\s!direction\endcsname\csname\??fontclass\fontclass\s!mm\s!direction\endcsname\fi}% + \edef\m_font_class_direction{\begincsname\??fontclass\fontclass\s!mm\s!direction\endcsname}% + % ... + \ifx\m_font_class_direction\v!both + \settrue\c_font_bidirectional_mathstrategy + \else + \setfalse\c_font_bidirectional_mathstrategy + \fi +\to \t_font_math_strategies + +\def\font_helpers_bidirectional_mathstrategy_yes + {\font_helpers_set_math_family\c_font_fam_mr_lr\s!mrlr + \font_helpers_set_math_family\c_font_fam_mr_rl\s!mrrl + \ifnum\fontid\textfont\c_font_fam_mr=\fontid\textfont\c_font_fam_mr_lr\else + \font_helpers_bidirectional_mathstrategy_yes_changed + \fi} + +\def\font_helpers_bidirectional_mathstrategy_yes_changed + {\textfont \c_font_fam_mr\textfont \c_font_fam_mr_lr + \scriptfont \c_font_fam_mr\scriptfont \c_font_fam_mr_lr + \scriptscriptfont\c_font_fam_mr\scriptscriptfont\c_font_fam_mr_lr} + +\def\font_helpers_bidirectional_mathstrategy_nop + {\font_helpers_set_math_family\c_font_fam_mr\s!mr + \ifnum\fontid\textfont\c_font_fam_mr_rl=\fontid\textfont\c_font_fam_mr\else + \font_helpers_bidirectional_mathstrategy_nop_changed + \fi} + +\def\font_helpers_bidirectional_mathstrategy_nop_changed + {\textfont \c_font_fam_mr_lr\textfont \c_font_fam_mr + \scriptfont \c_font_fam_mr_lr\scriptfont \c_font_fam_mr + \scriptscriptfont\c_font_fam_mr_lr\scriptscriptfont\c_font_fam_mr + \textfont \c_font_fam_mr_rl\textfont \c_font_fam_mr + \scriptfont \c_font_fam_mr_rl\scriptfont \c_font_fam_mr + \scriptscriptfont\c_font_fam_mr_rl\scriptscriptfont\c_font_fam_mr} + +\appendtoks + \ifconditional\c_font_bidirectional_mathstrategy + \font_helpers_bidirectional_mathstrategy_yes + \else + \font_helpers_bidirectional_mathstrategy_nop + \fi +\to \t_font_math_strategies + +\def\font_helpers_complete_bold_mathstrategy_yes_bidi + {\font_helpers_set_math_family_bold\c_font_fam_mb_lr\s!mblr\c_font_fam_mr_lr + \font_helpers_set_math_family_bold\c_font_fam_mb_rl\s!mbrl\c_font_fam_mr_rl + \ifnum\fontid\textfont\c_font_fam_mb=\fontid\textfont\c_font_fam_mb_lr\else + \font_helpers_complete_bold_mathstrategy_yes_bidi_changed + \fi} + +\def\font_helpers_complete_bold_mathstrategy_yes_bidi_changed + {\textfont \c_font_fam_mb\textfont \c_font_fam_mb_lr + \scriptfont \c_font_fam_mb\scriptfont \c_font_fam_mb_lr + \scriptscriptfont\c_font_fam_mb\scriptscriptfont\c_font_fam_mb_lr} + +\def\font_helpers_complete_bold_mathstrategy_yes + {\font_helpers_set_math_family_bold\c_font_fam_mb\s!mb\c_font_fam_mr\relax + \ifnum\fontid\textfont\c_font_fam_mb_rl=\fontid\textfont\c_font_fam_mb\else + \font_helpers_complete_bold_mathstrategy_yes_changed + \fi} + +\def\font_helpers_complete_bold_mathstrategy_yes_changed + {\textfont \c_font_fam_mb_rl\textfont \c_font_fam_mb + \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mb + \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mb + \textfont \c_font_fam_mb_lr\textfont \c_font_fam_mb + \scriptfont \c_font_fam_mb_lr\scriptfont \c_font_fam_mb + \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mb} + +\def\font_helpers_complete_bold_mathstrategy_nop + {\ifnum\fontid\textfont\c_font_fam_mb=\fontid\textfont\c_font_fam_mr\else + \font_helpers_complete_bold_mathstrategy_nop_changed + \fi} + +\def\font_helpers_complete_bold_mathstrategy_nop_changed + {\textfont \c_font_fam_mb \textfont \c_font_fam_mr + \scriptfont \c_font_fam_mb \scriptfont \c_font_fam_mr + \scriptscriptfont\c_font_fam_mb \scriptscriptfont\c_font_fam_mr + \textfont \c_font_fam_mb_lr\textfont \c_font_fam_mr_lr + \scriptfont \c_font_fam_mb_lr\scriptfont \c_font_fam_mr_lr + \scriptscriptfont\c_font_fam_mb_lr\scriptscriptfont\c_font_fam_mr_lr + \textfont \c_font_fam_mb_rl\textfont \c_font_fam_mr_rl + \scriptfont \c_font_fam_mb_rl\scriptfont \c_font_fam_mr_rl + \scriptscriptfont\c_font_fam_mb_rl\scriptscriptfont\c_font_fam_mr_rl} + +\def\font_helpers_apply_complete_bold_mathstrategy + {\ifconditional\c_font_complete_bold_mathstrategy + \ifconditional\c_font_bidirectional_mathstrategy + \font_helpers_complete_bold_mathstrategy_yes_bidi + \else + \font_helpers_complete_bold_mathstrategy_yes + \fi + \else + \font_helpers_complete_bold_mathstrategy_nop + \fi} + +\appendtoks + \font_helpers_apply_complete_bold_mathstrategy +\to \t_font_math_strategies + +\ifdefined\defaultmathfamily \else + \setnewconstant\defaultmathfamily\zerocount +\fi + +\appendtoks + \fam\defaultmathfamily % all characters and symbols are in this family +\to \everymathematics + +\unexpanded\def\font_helpers_synchronize_math_family_mr + {\attribute\mathfamilyattribute\ifconditional\c_font_bidirectional_mathstrategy + \ifconditional\c_math_right_to_left + \plustwo + \else + \plusone + \fi + \else + \zerocount + \fi} + +\unexpanded\def\font_helpers_synchronize_math_family_mb + {\attribute\mathfamilyattribute\ifconditional\c_font_bidirectional_mathstrategy + \ifconditional\c_math_right_to_left + \ifconditional\c_font_pseudo_bold_math_state\pluseight\else\plusfive\fi + \else + \ifconditional\c_font_pseudo_bold_math_state\plusseven\else\plusfour\fi + \fi + \else + \ifconditional\c_font_pseudo_bold_math_state\plussix\else\plusthree\fi + \fi} + +\installcorenamespace{fontmathsynchronizer} +\installcorenamespace{fontmathstoredstrategy} + +\letvalue{\??fontmathsynchronizer\s!tf }\font_helpers_synchronize_math_family_mr +\letvalue{\??fontmathsynchronizer\s!sl }\font_helpers_synchronize_math_family_mr +\letvalue{\??fontmathsynchronizer\s!it }\font_helpers_synchronize_math_family_mr +\letvalue{\??fontmathsynchronizer\s!bf }\font_helpers_synchronize_math_family_mb +\letvalue{\??fontmathsynchronizer\s!bs }\font_helpers_synchronize_math_family_mb +\letvalue{\??fontmathsynchronizer\s!bi }\font_helpers_synchronize_math_family_mb +\letvalue{\??fontmathsynchronizer\empty}\font_helpers_synchronize_math_family_mr + +% \def\font_helpers_synchronize_math_family +% {\csname\??fontmathsynchronizer\ifcsname\??fontmathsynchronizer\fontalternative\endcsname\fontalternative\fi\endcsname} + +\def\font_helpers_synchronize_math_family + {\ifcsname\??fontmathsynchronizer\fontalternative\endcsname + \lastnamedcs + \else + \font_helpers_synchronize_math_family_mr + \fi} + +\ifdefined \fontid % we need to keep this test for a while + \appendtoks + \ifnum\fontid\textfont\zerocount=\fontid\textfont\plusthree + \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_partial_bold_strategy + \else + \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_full_bold_strategy + \fi + \to \t_font_math_strategies +\else + \appendtoks + \edef\currentmathfontmr{\fontname\textfont\zerocount}% + \edef\currentmathfontmb{\fontname\textfont\plusthree}% + \ifx\currentmathfontmr\currentmathfontmb + \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_partial_bold_strategy + \else + \letvalue{\??fontmathstoredstrategy\fontclass}\font_helpers_set_math_full_bold_strategy + \fi + \to \t_font_math_strategies +\fi + +%def\font_helpers_synchronize_math_bold_strategy{\csname\??fontmathstoredstrategy\fontclass\endcsname} +\def\font_helpers_synchronize_math_bold_strategy{\begincsname\??fontmathstoredstrategy\fontclass\endcsname} + +\newconditional\c_font_pseudo_bold_math_state + +\def\font_helpers_set_math_partial_bold_strategy{\settrue \c_font_pseudo_bold_math_state} +\def\font_helpers_set_math_full_bold_strategy {\setfalse\c_font_pseudo_bold_math_state} + +\appendtoks + \font_helpers_synchronize_math_bold_strategy +\to \everymathematics + +%D Bold is somewhat special as we might want both full-bold-math mixed regular-math, +%D as well as automatic adaption to outer bold (in titles and inline text bold) so +%D we will need explicit switches as well as an automatic one. (We will use lucida +%D as an example.) + +\ifdefined\mathdefault \else \let\mathdefault\relax \fi + +\newconditional\c_math_bold + +\unexpanded\def\mr % math regular + {\ifmmode + \font_helpers_synchronize_math_family_mr + \else + \font_helpers_set_current_font_alternative\s!mr + \fi + \mathdefault + \setfalse\c_math_bold} + +\unexpanded\def\mb % math bold + {\ifmmode + \font_helpers_synchronize_math_family_mb + \else + \font_helpers_set_current_font_alternative\s!mb + \fi + \mathdefault + \settrue\c_math_bold} + +\appendtoks + \font_helpers_synchronize_math_family % auto bold +\to \everymathematics + +\appendtoks + \ifconditional\c_math_bold\mb\fi +\to \everymathematics + +%D \macros +%D {bigmath,nobigmath} +%D +%D We can inhibit this slow||downer with: + +% these can best be combined + +% 0=never 1=everymath 2=always + +\setnewconstant\synchronizebigmathflag\plusone + +\appendtoks + \ifcase\synchronizebigmathflag + % never + \or + \synchronizebigmath + \or + % always + \fi +\to \everymathematics + +\unexpanded\def\nobigmath {\synchronizebigmathflag\zerocount} +\unexpanded\def\autobigmath{\synchronizebigmathflag\plusone\synchronizebigmath} +\unexpanded\def\bigmath {\synchronizebigmathflag\plustwo\synchronizebigmath} + +\let\bigmathfontsize\empty + +\unexpanded\def\synchronizebigmath + {\ifx\bigmathfontsize\fontsize + % already in sync + \else + \let\bigmathfontsize\fontsize + \font_helpers_synchronize_math + \fi} + +\unexpanded\def\font_helpers_check_big_math_synchronization + {\ifcase\synchronizebigmathflag + % never + \or + \ifmmode \synchronizebigmath \fi + \or + \synchronizebigmath + \fi} + +\protect \endinput diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 76d7390b6..4fe0a6a97 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -1215,7 +1215,7 @@ readers.vmtx = function(f,fontdata,specification) local topsidebearing = 0 for i=0,nofmetrics-1 do local glyph = glyphs[i] - vheight = readshort(f) + vheight = readushort(f) topsidebearing = readshort(f) if vheight ~= 0 and vheight ~= vdefault then glyph.vheight = vheight @@ -1315,14 +1315,16 @@ local formatreaders = { } local duplicatestoo = true local sequence = { + -- these is some provision against redundant loading { 3, 1, 4 }, { 3, 10, 12 }, { 0, 3, 4 }, + { 0, 3, 12 }, { 0, 1, 4 }, - -- { 0, 1, 12 }, -- maybe for some old mac fonts - -- { 0, 4, 12 }, + { 0, 1, 12 }, -- for some old mac fonts { 0, 0, 6 }, { 3, 0, 6 }, + { 3, 0, 4 }, -- for (likely) old crap -- variants { 0, 5, 14 }, -- last resort ranges @@ -1633,24 +1635,33 @@ formatreaders[14] = function(f,fontdata,offset) end local function checkcmap(f,fontdata,records,platform,encoding,format) - local data = records[platform] - if not data then + local pdata = records[platform] + if not pdata then if trace_cmap_details then report_cmap("skipped, %s, p=%i e=%i f=%i","no platform",platform,encoding,format) end return 0 end - data = data[encoding] - if not data then + local edata = pdata[encoding] + if not edata then if trace_cmap_details then report_cmap("skipped, %s, p=%i e=%i f=%i","no encoding",platform,encoding,format) end return 0 end - data = data[format] - if not data then + local fdata = edata[format] + if not fdata then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","no format",platform,encoding,format) + end + return 0 + elseif type(fdata) ~= "number" then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","already done",platform,encoding,format) + end return 0 end + edata[format] = true -- done local reader = formatreaders[format] if not reader then if trace_cmap_details then @@ -1658,8 +1669,8 @@ local function checkcmap(f,fontdata,records,platform,encoding,format) end return 0 end - local n = reader(f,fontdata,data) or 0 - if trace_cmap then + local n = reader(f,fontdata,fdata) or 0 + if trace_cmap_details or trace_cmap then local p = platforms[platform] local e = encodings[p] report_cmap("checked, platform %i (%s), encoding %i (%s), format %i, new unicodes %i", diff --git a/tex/context/base/mkiv/font-pre.mkiv b/tex/context/base/mkiv/font-pre.mkiv index c1c24b854..d17f57167 100644 --- a/tex/context/base/mkiv/font-pre.mkiv +++ b/tex/context/base/mkiv/font-pre.mkiv @@ -755,6 +755,8 @@ \definealternativestyle [italicface] [\italicface] [] \definealternativestyle [swapface] [\swapface] [] +\definealternativestyle [emphasize] [\em] [\em] % new + % For Alan: \definealternativestyle diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 631f3086e..ba4853ec3 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -23,6 +23,10 @@ local streamscache = containers.define("fonts", "streams", version, true) -- shapes (can be come a separate file at some point) +local compact_streams = false + +directives.register("fonts.streams.compact", function(v) compact_streams = v end) + local function packoutlines(data,makesequence) local subfonts = data.subfonts if subfonts then @@ -209,6 +213,16 @@ local function loadoutlines(cache,filename,sub,instance) return data end +local function cachethem(cache,hash,data) + local fast = caches.fast + if compact_streams then + caches.fast = true + end + containers.write(cache,hash,data) + caches.fast = fast + return containers.read(cache,hash) -- frees old mem +end + local function loadstreams(cache,filename,sub,instance) local base = file.basename(filename) local name = file.removesuffix(base) @@ -240,8 +254,7 @@ local function loadstreams(cache,filename,sub,instance) data.size = size data.format = data.format or (kind == "otf" and "opentype") or "truetype" data.time = time - containers.write(cache,hash,data) - data = containers.read(cache,hash) -- frees old mem + data = cachethem(cache,hash,data) end end elseif size > 0 and (kind == "pfb") then @@ -295,8 +308,7 @@ local function loadstreams(cache,filename,sub,instance) weight = metadata.weight, }, } - containers.write(cache,hash,data) - data = containers.read(cache,hash) -- frees old mem + data = cachethem(cache,hash,data) end end else diff --git a/tex/context/base/mkiv/font-sty.mklx b/tex/context/base/mkiv/font-sty.mklx new file mode 100644 index 000000000..385a9cdbe --- /dev/null +++ b/tex/context/base/mkiv/font-sty.mklx @@ -0,0 +1,449 @@ +%D \module +%D [ file=font-sty, +%D version=2011.01.13, % (copied fron font-ini) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Styles, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Font Macros / Styles} + +\unprotect + +%D \macros +%D {definealternativestyle} +%D +%D In the main modules we are going to implement lots of parameterized commands and +%D one of these parameters will concern the font to use. To suit consistent use of +%D fonts we here implement a mechanism for defining the keywords that present a +%D particular style or alternative. +%D +%D \starttyping +%D \definealternativestyle [keywords] [\style] [\nostyle] +%D \stoptyping +%D +%D The first command is used in the normal textflow, while the second command takes +%D care of headings and alike. Consider the next two definitions: +%D +%D \starttyping +%D \definealternativestyle [bold] [\bf] [] +%D \definealternativestyle [cap] [\cap] [\cap] +%D \stoptyping +%D +%D A change \type {\bf} in a heading which is to be set in \type {\tfd} does not look +%D that well, so therefore we leave the second argument of \type +%D {\definealternativestyle} empty. When we capatalize characters using the pseudo +%D small cap command \type {\cap}, we want this to take effect in both text and +%D headings, which is accomplished by assigning both arguments. + +\installcorenamespace{alternativestyles} % settings +\installcorenamespace{alternativestyle} % instances + +\installsetuponlycommandhandler \??alternativestyles {alternativestyles} + +\setnewconstant \c_font_current_alternative_style_index \plusone + +\unexpanded\def\definealternativestyle + {\dotripleempty\font_basics_define_alternative_style} + +\def\font_basics_define_alternative_style[#commands][#variantone][#varianttwo]% + {\processcommalist[#commands]{\font_basics_define_alternative_style_indeed{#variantone}{#varianttwo}}} + +\let\definestyle\definealternativestyle % later redefined + +\newconstant\c_fonts_basics_alternative_style_method + +\def\font_basics_define_alternative_style_indeed#variantone#varianttwo#command% + {\setuvalue{\??alternativestyle#command}{\font_helpers_apply_alternative_style{#variantone}{#varianttwo}}% + \ifcsname#command\endcsname + % no redefinition + \orelse\ifnum\c_fonts_basics_alternative_style_method=\plusone + \ifthirdargument + \setuevalue{#command}{\triggergroupedcommandcs\begincsname\??alternativestyle#command\endcsname}% + \else + \setuvalue{#command}{\triggergroupedcommand{#variantone}}% + \fi + \else + \setuvalue{#command}{\triggergroupedcommand{#variantone}}% + \fi} + +\def\font_helpers_apply_alternative_style + {\ifcase\c_font_current_alternative_style_index + \expandafter\gobbletwoarguments + \or + \expandafter\firstoftwoarguments + \or + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\def\applyalternativestyle#name% public + {\begincsname\??alternativestyle#name\endcsname} + +\appendtoks + \doifelse{\alternativestylesparameter\c!method}\v!auto + {\c_fonts_basics_alternative_style_method\plusone}% + {\c_fonts_basics_alternative_style_method\zerocount}% +\to \everysetupalternativestyles + +%D Maybe too generic, but probably ok is the following. (Maybe one day we will use a +%D dedicated grouped command for styles.) + +% \appendtoks +% \let\groupedcommand\thirdofthreearguments +% \to \everysimplifycommands + +%D This command also defines the keyword as command. This means that the example +%D definition of \type {bold} we gave before, results in a command \type {\bold} +%D which can be used as: +%D +%D \startbuffer +%D He's a \bold{bold} man with a {\bold head}. +%D \stopbuffer +%D +%D \typebuffer +%D +%D or +%D +%D \startexample +%D \definealternativestyle[bold][\bf][]\getbuffer +%D \stopexample +%D +%D Such definitions are of course unwanted for \type {\cap} because this would +%D result in an endless recursive call. Therefore we check on the existance of both +%D the command and the substitution. The latter is needed because for instance \type +%D {\type} is an entirely diferent command. That command handles verbatim, while the +%D style command would just switch to teletype font. This is just an example of a +%D tricky naming coincidence. +%D +%D \macros +%D {doconvertfont,noconvertfont, +%D dontconvertfont,redoconvertfont} +%D +%D After having defined such keywords, we can call for them by using +%D +%D \starttyping +%D \doconvertfont{keyword}{text} +%D \stoptyping +%D +%D We deliberately pass an argument. This enables us to assign converters that +%D handle one argument, like \type {\cap}. +%D +%D By default the first specification is used to set the style, exept when we say +%D \type {\dontconvertfont}, after which the second specification is used. We can +%D also directly call for \type {\noconvertfont}. In nested calls, we can restore +%D the conversion by saying \type {\redoconvertfont}. +%D +%D These commands are not grouped! Grouping is most probably done by the calling +%D macro's and would lead to unnecessary overhead. + +\let\m_current_convert_font \empty +\let\m_current_convert_font_dt\empty + +\unexpanded\def\doconvertfont#specification% takes second argument / this command is obsolete + {\edef\m_current_convert_font{#specification}% + \ifx\m_current_convert_font\empty + %\expandafter\firstofoneargument + \else + \expandafter\font_helpers_do_convert_font + \fi} + +\def\font_helpers_do_convert_font + {\edef\m_current_convert_font_dt{\detokenize\expandafter{\m_current_convert_font}}% + \ifcsname\??alternativestyle\m_current_convert_font_dt\endcsname + \expandafter\lastnamedcs + \orelse\ifcsname\m_current_convert_font_dt\endcsname + \expandafter\lastnamedcs + \else + \expandafter\m_current_convert_font + \fi} + +%D Low level switches (downward compatible, but we keep them as one can use them in +%D styles): +%D +%D \starttyping +%D \usemodule[abr-02] +%D \setuphead[chapter][style=\bfb] +%D \setupfooter[style=\dontconvertfont\bf] +%D \chapter{This is \TEX} +%D \stoptyping + +\unexpanded\def\dontconvertfont{\c_font_current_alternative_style_index\plustwo} % needs checking in usage +\unexpanded\def\redoconvertfont{\c_font_current_alternative_style_index\plusone} % needs checking in usage + +%D The new one: + +\setfalse\fontattributeisset + +\unexpanded\def\dousestyleparameter#value% + {\edef\currentstyleparameter{#value}% + \ifx\currentstyleparameter\empty\else + \expandafter\dousecurrentstyleparameter + \fi} + +\unexpanded\def\dousestylehashparameter#hash#parameter% + {\ifcsname#hash#parameter\endcsname + \expandafter\dousestyleparameter\lastnamedcs + \fi} + +\unexpanded\def\dousecurrentstyleparameter % empty check outside here + {\edef\detokenizedstyleparameter{\detokenize\expandafter{\currentstyleparameter}}% + \settrue\fontattributeisset % reset is done elsewhere + \ifcsname\??alternativestyle\detokenizedstyleparameter\endcsname + \lastnamedcs + \orelse\ifcsname\detokenizedstyleparameter\endcsname + \lastnamedcs + \else + \currentstyleparameter + \fi} + +\let\dosetfontattribute\dousestylehashparameter % for a while + +%D New commands (not yet interfaced): +%D +%D \startbuffer +%D \definestyle[one][style=bold,color=darkblue] +%D +%D test \one{test} test +%D test \style[one]{test} test +%D test \style[color=red]{test} test +%D test \style[Serif at 20pt]{test} test +%D \stopbuffer +%D +%D \typebuffer \startlines \getbuffer \stoplines + +% definitions .. no tagging here + +\installcorenamespace{style} +\installcorenamespace{stylecheck} + +\installcommandhandler \??style {style} \??style + +\setupstyle + [%\c!style=, + %\c!color=, + \c!method=\v!command] + +\appendtoks + \letvalue{\??stylecheck\currentstyle}\relax + \edef\p_method{\styleparameter\c!method}% + \ifx\p_method\v!command + \setuevalue{\e!start\currentstyle}{\font_styles_apply_start{\currentstyle}}% + \setuevalue{\e!stop \currentstyle}{\font_styles_apply_stop}% + \setuevalue {\currentstyle}{\font_styles_apply_grouped{\currentstyle}}% no longer groupedcommand here + \fi +\to \everydefinestyle + +\unexpanded\def\font_styles_apply_start#name% + {\begingroup + \font_styles_use_defined{#name}} + +\unexpanded\def\font_styles_apply_stop + {\endgroup} + +\unexpanded\def\font_styles_apply_grouped#name% assumes that the next is { or \bgroup + {\bgroup + \def\g_style{\font_styles_use_defined{#name}}% + \afterassignment\g_style + \let\nexttoken} + +\unexpanded\def\font_styles_use_defined#name% + {\edef\currentstyle{#name}% + \usestylestyleandcolor\c!style\c!color} + +\unexpanded\def\font_styles_use_generic#specification% + {\let\currentstyle\s!unknown % reasonable generic tag + \letstyleparameter\c!style\empty + \letstyleparameter\c!color\empty + \setupcurrentstyle[#specification]% + \usestylestyleandcolor\c!style\c!color} + +% commands + +\installcorenamespace{styleargument} + +\unexpanded\def\style[#name]% as this is can be a switch we use groupedcommand + {\csname\??styleargument + \ifcsname\??stylecheck#name\endcsname + 2% defined as style + \orelse\ifcsname#name\endcsname + 1% defined as command + \else + 3% specification + \fi + \endcsname{#name}} + +% \setvalue{\??styleargument1}#name% +% {\groupedcommand{\begincsname#name\endcsname}{}} + +\setvalue{\??styleargument1}#name% + {\expandafter\triggergroupedcommandcs\begincsname#name\endcsname} + +% \setvalue{\??styleargument2}#name% +% {\groupedcommand{\font_styles_use_defined{#name}}{}} % or {\font_styles_apply_grouped{#name}} + +\setvalue{\??styleargument2}#name% + {\triggergroupedcommand{\font_styles_use_defined{#name}}} % or {\font_styles_apply_grouped{#name}} + +\setvalue{\??styleargument3}#specification% + {\doifelseassignment{#specification}\font_styles_assignment\font_styles_direct{#specification}} + +% \def\font_styles_assignment#specification{\groupedcommand{\font_styles_use_generic{#specification}}{}} +% \def\font_styles_direct #specification{\groupedcommand{\definedfont[#specification]}{}} + +\def\font_styles_assignment#specification{\triggergroupedcommand{\font_styles_use_generic{#specification}}} +\def\font_styles_direct #specification{\triggergroupedcommand{\definedfont[#specification]}} + +% environments + +\installcorenamespace{styleenvironment} + +\unexpanded\def\startstyle[#name]% + {\begingroup + \csname\??styleenvironment + \ifcsname\??stylecheck#name\endcsname + 2% defined as style + \orelse\ifcsname#name\endcsname + 1% defined as command + \else + 3% specification + \fi + \endcsname{#name}} + +\unexpanded\def\stopstyle + {\endgroup + \autoinsertnextspace} % will be configurable, maybe also in \definestartstop + +\setvalue{\??styleenvironment1}#name% + {\csname#name\endcsname} + +\setvalue{\??styleenvironment2}#name% + {\font_styles_use_defined{#name}} + +\setvalue{\??styleenvironment3}#specification% + {\doifelseassignment{#specification}\font_styles_start_assignment\font_styles_start_direct{#specification}} + +\def\font_styles_start_assignment#specification{\font_styles_use_generic{#specification}} +\def\font_styles_start_direct #specification{\definedfont[#specification]\relax} + +%D Still experimental (might even go away). + +% \definestylecollection[mine] + +% \definestyleinstance[mine][default][sorry] +% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl] +% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl] +% \definestyleinstance[mine][bf][\sl] +% \definestyleinstance[mine][sl][\tt] + +% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}} + +\installcorenamespace{stylecollection} + +\unexpanded\def\definestylecollection + {\dosingleargument\font_styles_define_style_collection} + +\def\font_styles_define_style_collection[#name]% + {\iffirstargument + \setuvalue{#name}{\styleinstance[#name]}% + \def\font_styles_define_style_collection_a#style% + {\def\font_styles_define_style_collection_b#alternative{\undefinevalue{\??stylecollection#name:#style:#alternative}}% + \font_helpers_process_alternative_list\font_styles_define_style_collection_b + \font_styles_define_style_collection_b\s!default}% + \font_helpers_process_style_list\font_styles_define_style_collection_a + \font_styles_define_style_collection_a\s!default + \fi} + +\let\font_styles_define_style_collection_a\relax +\let\font_styles_define_style_collection_b\relax + +\unexpanded\def\definestyleinstance + {\doquadrupleargument\font_styles_define_style_instance} + +\def\font_styles_define_style_instance[#instance][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever] + {\iffirstargument + \ifcsname#instance\endcsname\else\font_styles_define_style_collection[#instance]\fi + \fi + \iffourthargument + \setvalue{\??stylecollection#instance:#2:#3}{#4}% + \orelse\ifthirdargument + \setvalue{\??stylecollection#instance::#2}{#3}% + \orelse\ifsecondargument + \letvalueempty{\??stylecollection#instance::#2}% + \fi} + +% \unexpanded\def\styleinstance[#instance]% will be made faster +% {%\begingroup\normalexpanded{\noexpand\infofont[#1:\fontstyle:\fontalternative]}\endgroup +% \executeifdefined{\??stylecollection#instance:\fontstyle:\fontalternative}% +% {\executeifdefined{\??stylecollection#instance:\fontstyle:\s!default}% +% {\executeifdefined{\??stylecollection#instance::\fontalternative} +% {\getvalue {\??stylecollection#instance::\s!default}}}}} + +\unexpanded\def\styleinstance[#instance]% maybe \lastnamedcs here too + {\csname\??stylecollection#instance:% + \ifcsname\??stylecollection#instance:\fontstyle:\fontalternative\endcsname + \fontstyle:\fontalternative + \orelse\ifcsname\??stylecollection#instance:\fontstyle:\s!default\endcsname + \fontstyle:\s!default + \orelse\ifcsname\??stylecollection#instance::\fontalternative\endcsname + :\fontalternative + \else + :\s!default + \fi + \endcsname} + +%D Variant selectors +%D +%D \starttyping +%D \mathematics {\vsone{\utfchar{0x2229}}} +%D \mathematics {\utfchar{0x2229}\vsone{}} +%D \stoptyping + +\unexpanded\edef\vsone#character{#character\normalUchar"FE00 } % used +\unexpanded\edef\vstwo#character{#character\normalUchar"FE01 } % not used but handy for testing + +%D For historic reasons we keep the following around but they are no longer that +%D relevant for \MKIV. + +\unexpanded\def\doattributes#1#2#3#4% + {\begingroup % geen \bgroup, anders in mathmode lege \hbox + \dousestylehashparameter{#1}{#2}% + \dousecolorhashparameter{#1}{#3}% + #4% + \endgroup} + +\unexpanded\def\dostartattributes#1#2#3% + {\begingroup % geen \bgroup, anders in mathmode lege \hbox + \dousestylehashparameter{#1}{#2}% + \dousecolorhashparameter{#1}{#3}} + +\let\dostopattributes\endgroup + +%D New but it needs to be supported explicitly (as in natural tables). + +\newconditional\c_font_styles_math + +\unexpanded\def\font_styles_math_reset + {\setfalse\c_font_styles_math} + +\unexpanded\def\font_styles_math_start + {\ifconditional\c_font_styles_math + \startimath + \fi + \relax} + +\unexpanded\def\font_styles_math_stop + {\relax + \ifconditional\c_font_styles_math + \stopimath + \fi} + +\definealternativestyle[\v!math][\settrue\c_font_styles_math] + +\protect \endinput diff --git a/tex/context/base/mkiv/font-sym.mklx b/tex/context/base/mkiv/font-sym.mklx new file mode 100644 index 000000000..33f8a62da --- /dev/null +++ b/tex/context/base/mkiv/font-sym.mklx @@ -0,0 +1,245 @@ +%D \module +%D [ file=font-mat, +%D version=2011.01.13, % (copied fron font-ini) +%D title=\CONTEXT\ Font Macros, +%D subtitle=Symbolic Access, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Font Macros / Symbolic Access} + +\unprotect + +%D \macros +%D {getglyph, symbolicfont} +%D +%D Individual glyphs can be accessed by using +%D +%D \starttyping +%D \getglyph{fontname}{character} +%D \stoptyping +%D +%D This macro is used in for instance the symbol modules and as one can see, it does +%D obey the small and even smaller sizes. The \type {\symbolicfont} macro can be +%D used to switch to a font named \type {fontname} (see \type {cont-log} and \type +%D {symb-eur} for examples of symbolic definitions. + +\def\v_font_string_a + {\ifx\fontstyle\s!rm \s!Serif \orelse + \ifx\fontstyle\s!ss \s!Sans \orelse + \ifx\fontstyle\s!tt \s!Mono \else + \s!Serif \fi} + +\def\v_font_string_b + {\ifx\fontstyle\s!rm \s!Regular \orelse + \ifx\fontstyle\s!ss \s!Support \orelse + \ifx\fontstyle\s!tt \s!Type \else + \s!Serif \fi} + +\def\v_font_string_c + {\ifx\fontalternative\s!bf \s!Bold \orelse + \ifx\fontalternative\s!sl \s!Slanted \orelse + \ifx\fontalternative\s!it \s!Italic \orelse + \ifx\fontalternative\s!bs \s!BoldSlanted \orelse + \ifx\fontalternative\s!bi \s!BoldItalic \fi} + +\let\v_font_string_d\s!Serif % default fontstyle (will be redefined in type-ini) + +\definefontsynonym + [CurrentFont] + [\noexpand\v_font_string_a\noexpand\v_font_string_c] + +% potential generalization: +% +% \letvalue{\??fontfile:t:\s!rm}\s!Serif +% \letvalue{\??fontfile:t:\s!ss}\s!Sans +% \letvalue{\??fontfile:t:\s!tt}\s!Mono +% +% \letvalue{\??fontfile:a:\s!rm}\s!Regular +% \letvalue{\??fontfile:a:\s!ss}\s!Support +% \letvalue{\??fontfile:a:\s!tt}\s!Type +% +% \letvalue{\??fontfile:s:\s!bf}\s!Bold +% \letvalue{\??fontfile:s:\s!sl}\s!Slanted +% \letvalue{\??fontfile:s:\s!it}\s!Italic +% \letvalue{\??fontfile:s:\s!bs}\s!BoldSlanted +% \letvalue{\??fontfile:s:\s!bi}\s!BoldItalic +% +% \def\v_font_string_a{\executeifdefined{\??fontfile:t:\fontstyle}\s!Serif} +% \def\v_font_string_a{\executeifdefined{\??fontfile:t:\fontstyle}\s!Serif} +% \def\v_font_string_b{\executeifdefined{\??fontfile:a:\fontstyle}\s!Serif} +% \def\v_font_string_c{\executeifdefined{\??fontfile:s:\fontstyle}\empty} +% \def\v_font_string_d{\executeifdefined{\??fontfile:t:\csname\??typescriptdefaultstyles\fontclass\endcsname}\s!Serif} + +%D \macros +%D {fontstylesuffix} +%D +%D The next macro is used to map non latin fontnames on fonts. See \type +%D {font-uni} for an example of its use. + +\def\fontstylesuffix% why the \s!Regular ? see \getglyph + {\ifx\fontalternative\s!tf \s!Regular \orelse + \ifx\fontalternative\s!bf \s!Bold \orelse + \ifx\fontalternative\s!sl \s!Slanted \orelse + \ifx\fontalternative\s!it \s!Italic \orelse + \ifx\fontalternative\s!bs \s!BoldSlanted \orelse + \ifx\fontalternative\s!bi \s!BoldItalic \orelse + \ifx\fontalternative\s!sc \s!Caps \else + \s!Regular \fi} + +\def\glyphfontfile#base% appends + {#base% + \ifcsname\??fontfile#base\v_font_string_a\v_font_string_c\endcsname + \v_font_string_a\v_font_string_c + \orelse\ifcsname\??fontfile#base\v_font_string_b\v_font_string_c\endcsname + \v_font_string_b\v_font_string_c + \orelse\ifcsname\??fontfile#base\v_font_string_a\endcsname + \v_font_string_a + \orelse\ifcsname\??fontfile#base\v_font_string_b\endcsname + \v_font_string_b + \orelse\ifcsname\??fontfile#base\v_font_string_c\endcsname + \v_font_string_c + \fi} + +%D The next macro can be used to make decisions based on the shape: + +\def\doifelseitalic#yes#nop% + {\ifx\fontalternative\s!sl#yes\orelse + \ifx\fontalternative\s!it#yes\orelse + \ifx\fontalternative\s!bs#yes\orelse + \ifx\fontalternative\s!bi#yes\else#nop\fi} + +\let\doifitalicelse\doifelseitalic + +%D For an example of usage of the following command, see \type {cont-log.tex}. +%D +%D \starttyping +%D \def\symbolicfont#specification{\definedfont[\glyphfontfile{#specification} sa *]} +%D \stoptyping +%D +%D Since we know what scaling it to be applied, we can implement a much faster +%D alternative: + +\installcorenamespace{symbolfont} + +\let\thedefinedfont\relax + +\def\setscaledstyledsymbolicfont#1#2#3% quite a slowdown, glyphfontfile + {\edef\askedsymbolfont{\truefontname{\glyphfontfile{#3}} at \the\dimexpr#2\dimexpr\currentfontbodyscale\dimexpr#1}% + \ifcsname\??symbolfont\askedsymbolfont\endcsname + \lastnamedcs + \else + \font_basics_define_symbolic_font + \fi} + +\def\setscaleddirectsymbolicfont#1#2#3% quite a slowdown, glyphfontfile + {\edef\askedsymbolfont{\truefontname{#3} at \the\dimexpr#2\dimexpr\currentfontbodyscale\dimexpr#1}% + \ifcsname\??symbolfont\askedsymbolfont\endcsname + \lastnamedcs + \else + \font_basics_define_symbolic_font + \fi} + +\def\setstyledsymbolicfont#fontname% quite a slowdown, glyphfontfile + {\edef\askedsymbolfont{\truefontname{\glyphfontfile{#fontname}} at \the\dimexpr\currentfontbodyscale\dimexpr\fontbody}% + \ifcsname\??symbolfont\askedsymbolfont\endcsname + \lastnamedcs + \else + \font_basics_define_symbolic_font + \fi} + +\def\setdirectsymbolicfont#fontname% + {\edef\askedsymbolfont{\truefontname{#fontname} at \the\dimexpr\currentfontbodyscale\dimexpr\fontbody}% + \ifcsname\??symbolfont\askedsymbolfont\endcsname + \lastnamedcs + \else + \font_basics_define_symbolic_font + \fi} + +\def\font_basics_define_symbolic_font + {\definefont[currentsymbolfont][\askedsymbolfont]% + \currentsymbolfont + \expandafter\glet\csname\??symbolfont\askedsymbolfont\endcsname\lastrawfontcall} + +\unexpanded\def\getnamedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\clf_fontchar{#character}}} +\unexpanded\def\getnamedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\clf_fontchar{#character}}} +\unexpanded\def\getglyphstyled #fontname#character{{\setstyledsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}} +\unexpanded\def\getglyphdirect #fontname#character{{\setdirectsymbolicfont{#fontname}\doifelsenumber{#character}\char\donothing#character}} +\unexpanded\def\resolvedglyphstyled#fontname#character{{\setstyledsymbolicfont{#fontname}\clf_tochar{#character}}} +\unexpanded\def\resolvedglyphdirect#fontname#character{{\setdirectsymbolicfont{#fontname}\clf_tochar{#character}}} + +% this one is wrong: + +\unexpanded\def\getscaledglyph#scale#name#content% + {{\setscaledstyledsymbolicfont\fontbody{#scale}{#name}\doifelsenumber{#content}\char\donothing#content}} + +\let\getglyph \getglyphstyled % old +\let\getrawglyph \getglyphdirect % old +\let\symbolicsizedfont\setscaledstyledsymbolicfont % old +\let\symbolicfont \setstyledsymbolicfont % old + +\unexpanded\def\symbolicscaledfont{\setsscaledstyledsymbolicfont\fontbody} +\unexpanded\def\symbolicscaledfont{\setscaledstyledsymbolicfont\fontbody} + +%D The last implementation of \type {\getglyph} permits definitions like: +%D +%D \starttyping +%D \definefontsynonym [EuroSans] [eurose] +%D \definefontsynonym [EuroSansBold] [euroseb] +%D \definefontsynonym [EuroSansItalic] [eurosei] +%D \definefontsynonym [EuroSansSlanted] [eurosei] +%D \definefontsynonym [EuroSansBoldItalic] [eurosebi] +%D \definefontsynonym [EuroSansBoldSlanted] [eurosebi] +%D +%D \definesymbol [euro] [\getglyph{Euro}{\char160}] +%D +%D \def\euro{\symbol[euro]} +%D \stoptyping +%D +%D These definitions guarantee that the next calls work okay: +%D +%D \starttyping +%D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro +%D \stoptyping +%D +%D The shape as well as the size is adapted to the current environment. + +%D \macros +%D {setfont} +%D +%D Every now and then we want to define a font directly, for instance when we +%D typeset title pages. The next macro saves some typing: + +\unexpanded\def\setfont% geen \font_helpers_set_font mogelijk + {\afterassignment\font_basics_set_font\font\nextfont=} + +\def\font_basics_set_font + {\nextfont\setupinterlinespace}% hm, we need to use \setuplocalinterlinespace + +%D One can call this macro as: +%D +%D \starttyping +%D \setfont cmr10 at 60pt +%D \stoptyping +%D +%D After which the font is active and the baselines and struts are set. + +%D \macros{doiffontcharelse} + +\unexpanded\def\doifelsefontchar#specification#unicode% this could be a direct lua call + {\begingroup + \font_basics_define_font_without_parameters{thedefinedfont}{#specification}% + \iffontchar\font#unicode\relax + \endgroup\expandafter\firstoftwoarguments + \else + \endgroup\expandafter\secondoftwoarguments + \fi} + +\let\doiffontcharelse\doifelsefontchar + +\protect \endinput diff --git a/tex/context/base/mkiv/font-sym.mkvi b/tex/context/base/mkiv/font-sym.mkvi index 3ff85fb4a..b6479535b 100644 --- a/tex/context/base/mkiv/font-sym.mkvi +++ b/tex/context/base/mkiv/font-sym.mkvi @@ -24,12 +24,10 @@ %D \getglyph{fontname}{character} %D \stoptyping %D -%D This macro is used in for instance the symbol modules and -%D as one can see, it does obey the small and even smaller -%D sizes. The \type {\symbolicfont} macro can be used to -%D switch to a font named \type {fontname} (see \type -%D {cont-log} and \type {symb-eur} for examples of symbolic -%D definitions. +%D This macro is used in for instance the symbol modules and as one can see, it does +%D obey the small and even smaller sizes. The \type {\symbolicfont} macro can be +%D used to switch to a font named \type {fontname} (see \type {cont-log} and \type +%D {symb-eur} for examples of symbolic definitions. \def\v_font_string_a {\ifx\fontstyle\s!rm \s!Serif \else @@ -118,15 +116,14 @@ \let\doifitalicelse\doifelseitalic -%D For an example of usage of the following command, -%D see \type {cont-log.tex}. +%D For an example of usage of the following command, see \type {cont-log.tex}. %D %D \starttyping %D \def\symbolicfont#specification{\definedfont[\glyphfontfile{#specification} sa *]} %D \stoptyping %D -%D Since we know what scaling it to be applied, we can -%D implement a much faster alternative: +%D Since we know what scaling it to be applied, we can implement a much faster +%D alternative: \installcorenamespace{symbolfont} @@ -189,8 +186,7 @@ \unexpanded\def\symbolicscaledfont{\setsscaledstyledsymbolicfont\fontbody} \unexpanded\def\symbolicscaledfont{\setscaledstyledsymbolicfont\fontbody} -%D The last implementation of \type {\getglyph} permits -%D definitions like: +%D The last implementation of \type {\getglyph} permits definitions like: %D %D \starttyping %D \definefontsynonym [EuroSans] [eurose] @@ -211,15 +207,13 @@ %D \ss \tf\euro \bf\euro \sla\euro \itd\euro \bs\euro \bic\euro %D \stoptyping %D -%D The shape as well as the size is adapted to the current -%D environment. +%D The shape as well as the size is adapted to the current environment. %D \macros %D {setfont} %D -%D Every now and then we want to define a font directly, for -%D instance when we typeset title pages. The next macro saves -%D some typing: +%D Every now and then we want to define a font directly, for instance when we +%D typeset title pages. The next macro saves some typing: \unexpanded\def\setfont% geen \font_helpers_set_font mogelijk {\afterassignment\font_basics_set_font\font\nextfont=} @@ -233,8 +227,7 @@ %D \setfont cmr10 at 60pt %D \stoptyping %D -%D After which the font is active and the baselines and -%D struts are set. +%D After which the font is active and the baselines and struts are set. %D \macros{doiffontcharelse} diff --git a/tex/context/base/mkiv/lang-ini.mkxl b/tex/context/base/mkiv/lang-ini.mkxl new file mode 100644 index 000000000..8bcba01d8 --- /dev/null +++ b/tex/context/base/mkiv/lang-ini.mkxl @@ -0,0 +1,730 @@ +%D \module +%D [ file=lang-ini, +%D version=1996.01.25, +%D title=\CONTEXT\ Language Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D This module needs a further cleanup (real split between ii/iv). + +% \cldcontext{languages.numbers[tex.count.mainlanguagenumber]} + +%D This module implements multi||language support of \CONTEXT, which should not be +%D confused with the multi||lingual interface. This support will be extended when +%D needed. Properties of languages are defined in \TEX\ files as well as \LUA\ +%D files. + +\writestatus{loading}{ConTeXt Language Macros / Initialization} + +\registerctxluafile{lang-ini}{} +\registerctxluafile{lang-def}{} +\registerctxluafile{lang-cnt}{} + +\unprotect + +\ifdefined\nonfrenchspacing\else \let\nonfrenchspacing\relax \fi +\ifdefined\frenchspacing \else \let\frenchspacing \relax \fi + +%D When loading hyphenation patterns, \TEX\ assign a number to each loaded table, +%D starting with~0. Switching to a specific table is done by assigning the relevant +%D number to the predefined \COUNTER\ \type {\language}. However, in \MKIV\ a lot +%D of management is delegated to \LUA. + +%D We keep track of the last loaded patterns by means of a pseudo \COUNTER. This +%D just one of those situations in which we don't want to spent a real one. Language +%D zero has no patterns, first of all because I like to start numbering at one. It +%D may come in handy for special purposes as well. + +\normallanguage\zerocount \def\loadedlanguage{1} + +%D \macros +%D {currentlanguage, setupcurrentlanguage} +%D +%D Instead of numbers,we are going to use symbolic names for the languages. The +%D current langage is saved in the macro \type {\currentlanguage}. The setup macro +%D is mainly used for cosmetic purposes. +%D +%D \starttyping +%D \dorecurse{3} +%D {\language[nl] +%D \startmode[*en] english \stopmode +%D \startmode[*nl] dutch \stopmode +%D \language[en] +%D \startmode[*en] english \stopmode +%D \startmode[*nl] dutch \stopmode} +%D \stoptyping + +\let\currentlanguage \empty +\let\currentmainlanguage\empty + +%D \macros +%D {defaultlanguage,languageparameter,specificlanguageparameter} +%D +%D We don't use the commandhandler here (yet) because we have a rather special +%D fallback mechanism so quite some compatibility testing is needed. + +\installcorenamespace{language} +\installcorenamespace{languagelinked} + +\def\currentusedlanguage{\currentlanguage} + +\def\defaultlanguage#1% + {\ifcsname\??language#1\s!default\endcsname + \expandafter\defaultlanguage\lastnamedcs + \else + #1% + \fi} + +\def\languageparameter#1% + {\ifcsname\??language\currentlanguage#1\endcsname + \lastnamedcs + \orelse\ifcsname\??language\currentlanguage\s!default\endcsname + \expandafter\specificlanguageparameter\lastnamedcs{#1}% + \orelse\ifcsname\??language\s!default#1\endcsname + \lastnamedcs + \fi} + +\def\specificlanguageparameter#1#2% + {\ifcsname\??language#1#2\endcsname + \lastnamedcs + \orelse\ifcsname\??language#1\s!default\endcsname + \expandafter\specificlanguageparameter\lastnamedcs{#2}% + \orelse\ifcsname\??language\s!default#2\endcsname + \lastnamedcs + \fi} + +\def\mainlanguageparameter#1% + {\ifcsname\??language\currentmainlanguage#1\endcsname + \lastnamedcs + \orelse\ifcsname\??language\currentmainlanguage\s!default\endcsname + \expandafter\specificlanguageparameter\lastnamedcs{#1}% + \orelse\ifcsname\??language\s!default#1\endcsname + \lastnamedcs + \fi} + +\let\usedlanguageparameter\languageparameter + +\def\askedlanguageparameter#1% assumes \currentusedlanguage being set + {\ifcsname\??language\currentusedlanguage#1\endcsname + \lastnamedcs + \orelse\ifcsname\??language\currentusedlanguage\s!default\endcsname + \expandafter\specificlanguageparameter\lastnamedcs{#1}% + \orelse\ifcsname\??language\s!default#1\endcsname + \lastnamedcs + \fi} + +\unexpanded\def\setusedlanguage#1% + {\edef\currentusedlanguage{\reallanguagetag{#1}}% + \ifx\currentusedlanguage\empty + \let\currentusedlanguage \currentlanguage + \let\usedlanguageparameter\languageparameter + \orelse\ifx\currentusedlanguage\v!global + \let\currentusedlanguage \currentmainlanguage + \let\usedlanguageparameter\mainlanguageparameter + \orelse\ifx\currentusedlanguage\v!local + \let\currentusedlanguage \currentlanguage + \let\usedlanguageparameter\languageparameter + \else + \let\usedlanguageparameter\askedlanguageparameter + \fi} + +\unexpanded\def\setupcurrentlanguage[#1]% + {\setcurrentlanguage\currentmainlanguage{#1}} + +\unexpanded\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current) + {\edef\xaskedlanguage{#1}% otherwise clash with \askedlanguage + \ifx\xaskedlanguage\empty \else + \ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi + \let\currentmainlanguage\xaskedlanguage + \setsystemmode{\systemmodeprefix\currentmainlanguage}% + \fi + \edef\xaskedlanguage{#2}% + \ifx\xaskedlanguage\empty \else + \ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi + \let\currentlanguage\xaskedlanguage + \setsystemmode\currentlanguage + \fi} + +%D The internal macros will be defined later. + +%D \macros +%D {installlanguage} +%D +%D Hyphenation patterns can only be loaded when the format file is prepared. The +%D next macro takes care of this loading. A language is specified with +%D +%D \showsetup{installlanguage} +%D +%D When \type {state} equals \type {start}, both patterns and additional hyphenation +%D specifications are loaded. These files are seached for in the patterns path +%D have names like \type {lang-nl.lua}. +%D +%D The \type {spacing} variable specifies how the spaces after punctuation has to be +%D handled. English is by tradition more tolerant to inter||sentence spacing than +%D other languages. +%D +%D This macro also defines \type {\identifier} as a shortcut switch to the language. +%D Furthermore the command defined as being language specific, are executed. With +%D \type {default} we can default to another language (patterns) at format +%D generation time. Patterns are loaded at runtime. + +\newtoks \everysetuplanguage + +\def\installedlanguages{\clf_installedlanguages} + +\unexpanded\def\doifelselanguage#1% + {\ifcsname\??language#1\c!state\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doiflanguageelse\doifelselanguage + +\def\reallanguagetag#1% + {\ifcsname\??languagelinked#1\endcsname\lastnamedcs\else#1\fi} + +% \language[#1] gave unwanted side effect of loading language specifics + +\unexpanded\def\installlanguage + {\dodoubleargument\lang_basics_install} + +% \def\lang_basics_install[#1][#2]% +% {\doifelseassignment{#2} +% {\doifelselanguage{#1} +% {\getparameters[\??language#1][#2]} +% {\setvalue{\??languagelinked#1}{#1}% +% \lang_basics_install_indeed{#1}{#1}% +% \getparameters[\??language#1][\c!state=\v!start,#2]}% +% \edef\currentsetuplanguage{#1}% +% \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}% +% \the\everysetuplanguage} +% {\setvalue{\??languagelinked#1}{#2}% +% \clf_setlanguagesynonym{#1}{#2}% +% \lang_basics_install_indeed{#1}{#2}}} + +\def\lang_basics_install[#1][#2]% + {\ifcondition\validassignment{#2}% + \doifelselanguage{#1} + {\getparameters[\??language#1][#2]} + {\setvalue{\??languagelinked#1}{#1}% + \lang_basics_install_indeed{#1}{#1}% + \getparameters[\??language#1][\c!state=\v!start,#2]}% + \edef\currentsetuplanguage{#1}% + \clf_definelanguage{#1}{\specificlanguageparameter{#1}\s!default}% + \the\everysetuplanguage + \else + \setvalue{\??languagelinked#1}{#2}% + \clf_setlanguagesynonym{#1}{#2}% + \lang_basics_install_indeed{#1}{#2}% + \fi} + +\def\lang_basics_install_indeed#1#2% + {\ifcsname#1\endcsname\else\setuvalue{#1}{\lang_basics_set_current[#2]}\fi} + +%D When the second argument is a language identifier, a synonym is created. This +%D feature is present because we used dutch mnemonics in the dutch version, but +%D nowadays conform a standard. + +\unexpanded\def\doifelsepatterns#1% + {\begingroup % will change + \lang_basics_set_current[#1]% + \ifnum\normallanguage>\zerocount + \endgroup\expandafter\firstoftwoarguments + \else + \endgroup\expandafter\secondoftwoarguments + \fi} + +\let\doifpatternselse\doifelsepatterns + +%D \macros +%D {setuplanguage} +%D +%D Quick and dirty, but useful: +%D +%D \showsetup{setuplanguage} +%D +%D Beware, this command can only be used when a language is installed. + +\unexpanded\def\setuplanguage + {\dodoubleempty\lang_basics_setup} + +\ifdefined\lang_basics_synchronize \else + \let\lang_basics_synchronize\relax % be nice for setups till we have one +\fi + +\installmacrostack\currentlanguage + +\def\lang_basics_setup[#1][#2]% + {\ifsecondargument + \push_macro_currentlanguage % can be default + \edef\currentsetuplanguage{\reallanguagetag{#1}}% + \getparameters[\??language\currentsetuplanguage][#2]% + \the\everysetuplanguage + \pop_macro_currentlanguage + %\doif\currentsetuplanguage\currentlanguage we can have influenced inheritance (default) + \else + \let\currentsetuplanguage\currentlanguage + \getparameters[\??language\currentsetuplanguage][#1]% + \the\everysetuplanguage + \fi + \lang_basics_synchronize} + +\appendtoks + \clf_unloadlanguage{\currentsetuplanguage}% +\to \everysetuplanguage + +\setuplanguage + [\s!default] + [\s!patterns=, + \s!lefthyphenmin=2, + \s!righthyphenmin=2, + \s!lefthyphenchar=-1, + \s!righthyphenchar=45, + % used in compound i.e. interfaced with c! and can be anything so no numbers + \c!lefthyphen=, + \c!righthyphen=-, + \c!hyphen=-, + \c!spacing=\v!packed, + \c!compoundhyphen=\compoundhyphen, + \c!rightcompoundhyphen=\compoundhyphen, + \c!leftcompoundhyphen=, + \c!midsentence=---, + \c!leftsentence=---, + \c!rightsentence=---, + \c!leftsubsentence=---, + \c!rightsubsentence=---, + \c!leftquote=\upperleftsinglesixquote, + \c!rightquote=\upperrightsingleninequote, + \c!leftquotation=\upperleftdoublesixquote, + \c!rightquotation=\upperrightdoubleninequote, + \c!leftspeech=\languageparameter\c!leftquotation, + \c!middlespeech=, + \c!rightspeech=\languageparameter\c!rightquotation, + \c!limittext=\unknown, + \c!time={h,:,m}, + \c!date={\v!year,\ ,\v!month,\ ,\v!day}, + \c!text=Ag, + \s!font=] % \v!auto : experimental ! + +% to be tested: +% +% \setuplanguage +% [\s!default] +% [\c!righthyphenchar="AD] + +%D The values \type {leftsentence} and \type {rightsentence} can be (and are) used +%D to implement automatic subsentence boundary glyphs, like in {\fr |<|french +%D guillemots|>|} or {\de |<|german guillemots|>|} or {\nl |<|dutch dashes|>|} like +%D situations. Furthermore \type {leftquotation} and \type {leftquote} come into +%D view \quotation {when we quote} or \quote {quote} something. + +%D \macros +%D {currentdatespecification, currenttimespecification} +%D +%D Just to make things easy we can ask for the current date specification by saying: + +\def\currentdatespecification{\languageparameter\c!date} +\def\currenttimespecification{\languageparameter\c!time} + +%D Carefull reading of these macros shows that it's legal to say +%D +%D \starttyping +%D \installlanguage [du] [de] +%D \stoptyping + +%D \macros +%D {language,mainlanguage} +%D +%D Switching to another language (actually another hyphenation pattern) is done +%D with: +%D +%D \starttyping +%D \language[identifier] +%D \stoptyping +%D +%D or with \type {\identifier}. Just to be compatible with \PLAIN\ \TEX, we still +%D support the original meaning, so +%D +%D \starttyping +%D \language=1 +%D \stoptyping +%D +%D is a valid operation, where the relation between number and language depends on +%D the order in installing languages. +%D +%D \showsetup{language} +%D \showsetup{mainlanguage} +%D +%D Both commands take a predefined language identifier as argument. We can use \type +%D {\mainlanguage[identifier]} for setting the (indeed) main language. This is the +%D language used for translating labels like {\em figure} and {\em table}. The main +%D language defaults to the current language. + +\newtoks \everylanguage + +\installcorenamespace{languagenumbers} + +\appendtoks + % we need to reassign the number because new patterns can be defined later on + % so let's hope not that many \setups happen during a run + \expandafter\glet\csname\??languagenumbers\currentlanguage\endcsname\undefined +\to \everysetuplanguage + +\def\lang_basics_synchronize_yes + {\zerocount % see below + \global\expandafter\chardef\csname\??languagenumbers\currentlanguage\endcsname + \clf_languagenumber + {\currentlanguage}% + {\defaultlanguage\currentlanguage}% + {\languageparameter\s!patterns}% + {\languageparameter\c!factor}% + \relax + \normallanguage\csname\??languagenumbers\currentlanguage\endcsname} + +\let\lang_basics_synchronize_nop\zerocount % not loaded anyway + +\letvalue{\??languagenumbers}\lang_basics_synchronize_nop % initime + +\appendtoks + \letvalue{\??languagenumbers}\lang_basics_synchronize_yes % runtime +\to \everydump + +\def\lang_basics_synchronize + {\normallanguage\csname\??languagenumbers + \ifcsname\??languagenumbers\currentlanguage\endcsname + \currentlanguage + \fi + \endcsname + \relax + \the\everylanguage + \relax} + +\newcount\hyphenstate +\newcount\hyphenminoffset + +\unexpanded\def\lesshyphens + {\advance\hyphenminoffset\plusone + \lang_basics_synchronize_min_max} + +\unexpanded\def\morehyphens + {\ifcase\hyphenminoffset \else + \advance\hyphenminoffset\minusone + \fi + \lang_basics_synchronize_min_max} + +\unexpanded\def\nohyphens % nicer for url's + {\ifx\dohyphens\relax + \unexpanded\edef\dohyphens + {\hyphenminoffset\the\hyphenminoffset\relax + \lang_basics_synchronize_min_max}% + \fi + \hyphenminoffset\plusthousand + \lang_basics_synchronize_min_max} + +\let\dohyphens\relax + +\unexpanded\def\lang_basics_synchronize_min_max % maybe store this at the lua end + {% these values are stored along with glyph nodes + \lefthyphenmin \numexpr0\languageparameter\s!lefthyphenmin +\hyphenminoffset\relax + \righthyphenmin\numexpr0\languageparameter\s!righthyphenmin+\hyphenminoffset\relax + \hyphenationmin\numexpr0\languageparameter\s!hyphenmin\relax + % these values are stored with the language (global!) + \prehyphenchar \languageparameter\s!righthyphenchar\relax + \posthyphenchar\languageparameter\s!lefthyphenchar \relax} + +\appendtoks + \lang_basics_synchronize_min_max +\to \everylanguage + +\unexpanded\def\unhyphenated + {\groupedcommand{\lefthyphenmin\maxdimen}\donothing} + +% \appendtoks +% \setups[\languageparameter\c!setups]% +% \to \everylanguage + +%D You can setup the default language to reset settings. + +\appendtoks + \edef\currentlanguagesetups{\languageparameter\c!setups}% + \ifx\currentlanguagesetups\empty \else + \setups[\currentlanguagesetups]% + \fi +\to \everylanguage + +% new + +\appendtoks + \usebidiparameter\languageparameter +\to \everylanguage + +% this will move to core-spa ! + +\appendtoks + \edef\p_spacing{\languageparameter\c!spacing}% + \ifx\p_spacing\v!broad + \nonfrenchspacing + \else + \frenchspacing + \fi +\to \everylanguage + +% \mainlanguage[nl] \setuplanguage[nl][lefthyphen=,righthyphen=?] +% +% \dorecurse{100}{dit is toch wel een heel\normalhyphendiscretionary lang\normalhyphendiscretionary woord \recurselevel\ } +% \dorecurse{100}{dit is toch wel een heellangwoord \recurselevel\ } + +% new experimental feature + +\unexpanded\def\setuplanguages + {\setuplanguage[\s!default]} + +% \setuplanguages[\s!font=\v!auto] +% \setuplanguage[\s!default][\s!font=\v!auto] +% \setuplanguage[nl][\s!font=\v!auto] + +\appendtoks + \edef\p_language_font{\languageparameter\s!font}% + \ifx\p_language_font\empty + \orelse\ifx\p_language_font\v!auto + \doaddfeature\currentlanguage + \else + \doaddfeature\p_language_font + \fi +\to \everylanguage + +%D Fast switcher + +\def\lang_basics_switch_asked + {\ifcsname\??languagelinked\askedlanguage\endcsname + \edef\askedlanguage{\lastnamedcs}% + \ifx\currentlanguage\askedlanguage \else + \setcurrentlanguage\currentmainlanguage\askedlanguage + \lang_basics_synchronize + \fi + \fi} + +\unexpanded\def\uselanguageparameter#1% + {\edef\askedlanguage{#1\c!language}% + \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi} + +\unexpanded\def\douselanguageparameter#1% fast setter + {\edef\askedlanguage{#1}% + \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi} + +\unexpanded\def\lang_basics_set_current[#1]% + {\edef\askedlanguage{#1}% + \ifx\askedlanguage\empty\else\lang_basics_switch_asked\fi} + +\unexpanded\def\language + {\doifelsenextoptionalcs\lang_basics_set_current\normallanguage} + +\let\setlanguage\language % we make these synonyms + +\let\patterns\gobbleoneargument + +\newcount\mainlanguagenumber + +%D Beware: you might need to use \type {\dontleavehmode} outside and|/|or \type {\par} +%D inside the group! + +\unexpanded\def\startlanguage + {\begingroup\language} + +\let\stoplanguage\endgroup + +\unexpanded\def\mainlanguage[#1]% + {\edef\askedlanguage{#1}% + \ifx\askedlanguage\empty + \orelse\ifcsname\??languagelinked\askedlanguage\endcsname + %\edef\askedlanguage{\csname\??languagelinked\askedlanguage\endcsname}% + \edef\askedlanguage{\lastnamedcs}% + \ifx\currentlanguage\askedlanguage + \ifx\currentmainlanguage\askedlanguage \else + \setcurrentlanguage\askedlanguage\askedlanguage + \lang_basics_synchronize + \fi + \else + \setcurrentlanguage\askedlanguage\askedlanguage + \lang_basics_synchronize + \fi + \fi + \mainlanguagenumber\normallanguage} + +\appendtoks + \normallanguage\mainlanguagenumber +\to \everybeforepagebody + +%D Used at all? + +\def\splitsequence#1#2% + {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}} + +\def\splitsymbol#1% + {\splitsequence{#1}{\languageparameter\c!limittext}} + +%D Just like with subsentence boundary symbols, quotes placement depends on the +%D current language, therefore we show the defaults here. +%D +%D \def\ShowLanguageValues [#1] [#2] #3 #4 +%D {\blank +%D \startlinecorrection +%D \vbox\bgroup +%D \language[#1] +%D \midaligned{\bf#2 subsentence symbol and quotes} +%D \framed[width=\hsize,frame=off,topframe=on,bottomframe=on,offset=.5ex] +%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil +%D \startsubsentence\startsubsentence#3\stopsubsentence#4\stopsubsentence\hfil} +%D \egroup +%D \stoplinecorrection +%D \blank} +%D +%D \ShowLanguageValues [af] [afrikaans] afrikaanse ... +%D \ShowLanguageValues [ca] [catalan] catalan ... +%D \ShowLanguageValues [cs] [czech] tjechisch tex +%D \ShowLanguageValues [cs] [slovak] slowaakse ... +%D \ShowLanguageValues [da] [danish] deense ... +%D \ShowLanguageValues [de] [german] duitse degelijkheid +%D \ShowLanguageValues [en] [english] engelse humor +%D \ShowLanguageValues [et] [estonian] ... +%D \ShowLanguageValues [fi] [finnish] finse ... +%D \ShowLanguageValues [fr] [french] franse slag +%D \ShowLanguageValues [it] [italian] italiaanse ... +%D \ShowLanguageValues [la] [latin] latijnse missen +%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid +%D \ShowLanguageValues [nb] [bokmal] noorse zalm +%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm +%D \ShowLanguageValues [pl] [polish] poolse vlag +%D \ShowLanguageValues [pt] [portuguese] portugese ... +%D \ShowLanguageValues [es] [spanish] spaans benauwd +%D \ShowLanguageValues [sv] [swedish] zweedse ... +%D \ShowLanguageValues [tr] [turkish] turks fruit + +%D We support a lot of languages. These are specified and loaded in separate files, +%D according to their roots. Here we only take care of (postponed) setting of the +%D current language. +%D +%D \unprotect +%D \placetable{The germanic languages (\type{lang-ger})} +%D \starttable[||||] +%D \HL +%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR +%D \HL +%D \NC \s!nl \NC dutch \NC germanic \NC\FR +%D \NC \s!en \NC english \NC germanic \NC\MR +%D \NC \s!de \NC german \NC germanic \NC\MR +%D \NC \s!da \NC danish \NC germanic \NC\MR +%D \NC \s!sv \NC swedish \NC germanic \NC\MR +%D \NC \s!af \NC afrikaans \NC germanic \NC\MR +%D \NC \s!nb \NC bokmal \NC germanic \NC\LR +%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR +%D \HL +%D \stoptable +%D \protect +%D +%D \unprotect +%D \placetable{The italic languages (\type{lang-ita})} +%D \starttable[||||] +%D \HL +%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR +%D \HL +%D \NC \s!fr \NC french \NC italic \NC\FR +%D \NC \s!ca \NC catalan \NC italic \NC\MR +%D \NC \s!es \NC spanish \NC italic \NC\MR +%D \NC \s!it \NC italian \NC italic \NC\MR +%D \NC \s!la \NC latin \NC italic \NC\MR +%D \NC \s!pt \NC portuguese \NC italic \NC\LR +%D \HL +%D \stoptable +%D \protect +%D +%D \unprotect +%D \placetable{The slavic languages (\type{lang-sla})} +%D \starttable[||||] +%D \HL +%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR +%D \HL +%D \NC \s!pl \NC polish \NC slavic \NC\FR +%D \NC \s!cs \NC czech \NC slavic \NC\MR +%D \NC \s!sk \NC slavik \NC slavic \NC\LR +%D \HL +%D \stoptable +%D \protect +%D \unprotect +%D +%D \placetable{The altaic languages (\type{lang-alt})} +%D \starttable[||||] +%D \HL +%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR +%D \HL +%D \NC \s!tr \NC turkish \NC altaic \NC\SR +%D \HL +%D \stoptable +%D +%D \placetable{The uralic languages (\type{lang-ura})} +%D \starttable[||||] +%D \HL +%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR +%D \HL +%D \NC \s!fi \NC finnish \NC uralic \NC\SR +%D \HL +%D \stoptable +%D \protect + +\unexpanded\def\nopatterns{\normallanguage\minusone} + +%D We default to the language belonging to the interface. This is one of the few +%D places outside the interface modules where \type {\startinterface} is used. + +\setupcurrentlanguage[\s!en] + +\unexpanded\def\initializemainlanguage + {\mainlanguage[\currentlanguage]% + \showmessage\m!languages9\currentlanguage} + +%D New: + +\let\stopexceptions\relax + +\unexpanded\def\startexceptions + {\dosingleempty\lang_basics_start_exceptions} + +\def\lang_basics_start_exceptions[#1]#2\stopexceptions % multilingual or not? + {\begingroup + \edef\askedlanguage{\reallanguagetag{#1}}% + \ifx\askedlanguage\empty + \let\askedlanguage\currentlanguage + \fi + \clf_setlanguageexceptions{\askedlanguage}{#2}% + \endgroup} + +\unexpanded\def\hyphenation + {\clf_setlanguageexceptions{\currentlanguage}} + +%D For the moment here: + +\uchyph 1 % also treat uppercase +\exhyphenchar 45 % to permit breaking at explicit hyphens + +%D New: + +\unexpanded\def\traceddiscretionary#1#2#3% + {\dontleavehmode + \discretionary{\darkred#1}{\darkgreen#2}{\darkblue#3}} + +\unexpanded\def\samplediscretionary + {\traceddiscretionary + {pre\clf_currentprehyphenchar}% + {\clf_currentposthyphenchar post}% + {replace}} + +% todo: make this configurable + +\protect \endinput diff --git a/tex/context/base/mkiv/lang-lab.mkiv b/tex/context/base/mkiv/lang-lab.mkiv index f03d9af3a..1ae2d4c74 100644 --- a/tex/context/base/mkiv/lang-lab.mkiv +++ b/tex/context/base/mkiv/lang-lab.mkiv @@ -24,26 +24,23 @@ \def\sixperemspace{\normalUchar"2006} \fi -%D In this module we deal with language dependant labels and -%D prefixes, like in {\em Figure~12} and {\em Chapter 1}. In -%D this file we set the default values. Users can easily -%D overrule these. +%D In this module we deal with language dependant labels and prefixes, like in {\em +%D Figure~12} and {\em Chapter 1}. In this file we set the default values. Users can +%D easily overrule these. %D -%D This module is dedicated to the grandfather of Tobias -%D Burnus, who's extensive languages oriented library helped us -%D a lot in finding the right translations. All those labels -%D are collected in files that reflect their common ancestor. +%D This module is dedicated to the grandfather of Tobias Burnus, who's extensive +%D languages oriented library helped us a lot in finding the right translations. All +%D those labels are collected in files that reflect their common ancestor. %D -%D Not all languages can be satisfied with the labeling -%D mechanism as provided here. Chinese for instance put a label -%D in front as well as after a part number. This is why the -%D current implementation of labels supports two labels too. +%D Not all languages can be satisfied with the labeling mechanism as provided here. +%D Chinese for instance put a label in front as well as after a part number. This is +%D why the current implementation of labels supports two labels too. %D \macros %D {setupheadtext, setuplabeltext} %D -%D First we present some macros that deal with what we will -%D call head and label texts. Such texts are defines by: +%D First we present some macros that deal with what we will call head and label +%D texts. Such texts are defines by: %D %D \showsetup{setupheadtext} %D \showsetup{setuplabeltext} @@ -165,8 +162,8 @@ %D \macros %D {presetheadtext,presetlabeltext} %D -%D These macros enable us to automatically define head and label -%D texts without replacing predefined ones. They are internal macros. +%D These macros enable us to automatically define head and label texts without +%D replacing predefined ones. They are internal macros. \appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate @@ -301,9 +298,8 @@ %D \macros %D {translate} %D -%D Sometimes macros contain language specific words that are to -%D be typeset. Such macros can be made (more) language -%D independant by using: +%D Sometimes macros contain language specific words that are to be typeset. Such +%D macros can be made (more) language independant by using: %D %D \showsetup{translate} %D @@ -313,8 +309,7 @@ %D \translate[en=something,nl=iets] %D \stoptyping %D -%D which expands to {\em something} or {\em iets}, depending on -%D de current language. +%D which expands to {\em something} or {\em iets}, depending on de current language. \installcorenamespace{translation} @@ -331,8 +326,8 @@ [translation #1]% \fi\fi} -%D When used without argument, the last defined values are -%D used. This enables repetitive use like +%D When used without argument, the last defined values are used. This enables +%D repetitive use like %D %D \starttyping %D \en \translate\ means \nl \translate @@ -341,8 +336,8 @@ %D \macros %D {assigntranslation} %D -%D This macro is a system macro, and can be used to assign a -%D translation to a macro. Its form is: +%D This macro is a system macro, and can be used to assign a translation to a macro. +%D Its form is: %D %D \starttyping %D \assigntranslation[en=something,nl=iets]\to\command diff --git a/tex/context/base/mkiv/lang-lab.mkxl b/tex/context/base/mkiv/lang-lab.mkxl new file mode 100644 index 000000000..a527224e9 --- /dev/null +++ b/tex/context/base/mkiv/lang-lab.mkxl @@ -0,0 +1,390 @@ +%D \module +%D [ file=lang-lab, +%D version=1997.08.27, +%D title=\CONTEXT\ Language Macros, +%D subtitle=Labels, +%D author=Hans Hagen / Tobias Burnus, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Language Macros / Labels} + +\registerctxluafile{lang-lab}{} +\registerctxluafile{lang-txt}{} + +\unprotect + +%D Left-overs: + +\ifdefined\sixperemspace \else + \def\sixperemspace{\normalUchar"2006} +\fi + +%D In this module we deal with language dependant labels and prefixes, like in {\em +%D Figure~12} and {\em Chapter 1}. In this file we set the default values. Users can +%D easily overrule these. +%D +%D This module is dedicated to the grandfather of Tobias Burnus, who's extensive +%D languages oriented library helped us a lot in finding the right translations. All +%D those labels are collected in files that reflect their common ancestor. +%D +%D Not all languages can be satisfied with the labeling mechanism as provided here. +%D Chinese for instance put a label in front as well as after a part number. This is +%D why the current implementation of labels supports two labels too. + +%D \macros +%D {setupheadtext, setuplabeltext} +%D +%D First we present some macros that deal with what we will call head and label +%D texts. Such texts are defines by: +%D +%D \showsetup{setupheadtext} +%D \showsetup{setuplabeltext} +%D +%D A regular \CONTEXT\ stores some 1500 labels at most. +%D +%D These commands accept all kind of inputs: +%D +%D \starttyping +%D \setuplabeltext [language] [labellabel=text] +%D \setuplabeltext [language] [labellabel=text,labellabel=text,...] +%D \setuplabeltext [labellabel=text] +%D \setuplabeltext [labellabel=text,labellabel=text,...] +%D \stoptyping +%D +%D The last two cases concern the current language. + +\installcorenamespace{label} + +\let\currentlabelcategory\empty + +\unexpanded\def\definelabelclass + {\dodoubleempty\lang_labels_define_class} + +\def\lang_labels_define_class[#1][#2]% + {\normalexpanded + {\lang_labels_define_class_indeed + {#1}% + {\ifsecondargument#2\else\zerocount\fi}% + \expandafter\noexpand\csname dogetupsome#1text\endcsname + \expandafter\noexpand\csname #1language\endcsname + \expandafter\noexpand\csname dodogetupsome#1text\endcsname + \expandafter\noexpand\csname left#1text\endcsname + \expandafter\noexpand\csname right#1text\endcsname + \expandafter\noexpand\csname #1texts\endcsname + \expandafter\noexpand\csname #1text\endcsname}} + +% hm, not interfaced + +\let\thetextprefix\empty + +\unexpanded\def\lang_labels_define_class_indeed#1#2#3#4#5#6#7#8#9% + {\setuvalue{setup#1text}{\protecttextprefixes#2\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_setup}% + \setuvalue{preset#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_setup}% + \setuvalue{copy#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dodoubleempty\lang_labels_text_prefix_copy}% + \setuvalue{start#1text}{\protecttextprefixes1\def\currenttextprefixclass{#1}\dotripleempty\lang_labels_text_prefix_start[#1]}% + \letvalue{stop#1text}\relax + \def#4{\reallanguagetag{\defaultlanguage\currentmainlanguage}}% + \ifnum#2=\plustwo % used for math and tags + \def#3{#5#4}% + \def#5##1##2% ##1=language + {\ifcsname\??label\currentlabelcategory#1:##1:##2\endcsname + \lastnamedcs + \orelse\ifcsname\??label#1:##1:##2\endcsname + \lastnamedcs + % \orelse\ifcsname\??language#4\s!default\endcsname + % \expandafter#5\csname\??language#4\s!default\endcsname{##2}% + \orelse\ifcsname\??language##1\s!default\endcsname + %\expandafter#5\csname\??language##1\s!default\endcsname{##2}% + \expandafter#5\lastnamedcs{##2}% + \orelse\ifcsname\??label\currentlabelcategory#1:##2\endcsname + \lastnamedcs + \orelse\ifcsname\??label#1:##2\endcsname + \lastnamedcs + \orelse\ifcsname\??label\currentlabelcategory#1:\s!en:##2\endcsname + \lastnamedcs + \orelse\ifcsname\??label#1:\s!en:##2\endcsname + \lastnamedcs + \else + ##2% + \fi}% + \let#6\gobbleoneargument + \let#7\gobbleoneargument + \let#8\gobbletwoarguments + \let#9#3% + \else + \unexpanded\def#3{#5#4}% + \unexpanded\def#5##1##2% + {\ifcsname\??label#1:##1:##2\endcsname + %\expandafter\let\expandafter\thetextprefix\csname\??label#1:##1:##2\endcsname + \expandafter\let\expandafter\thetextprefix\lastnamedcs + \orelse\ifcsname\??language#4\s!default\endcsname + %\expandafter#5\csname\??language#4\s!default\endcsname{##2}% + \expandafter#5\lastnamedcs{##2}% + \orelse\ifcsname\??label#1:##2\endcsname + %\expandafter\let\expandafter\thetextprefix\csname\??label#1:##2\endcsname + \expandafter\let\expandafter\thetextprefix\lastnamedcs + \orelse\ifcsname\??label#1:\s!en:##2\endcsname + %\expandafter\let\expandafter\thetextprefix\csname\??label#1:\s!en:##2\endcsname + \expandafter\let\expandafter\thetextprefix\lastnamedcs + \else + \let\thetextprefix\dummytextprefix + \fi}% + \unexpanded\def#6##1{#3{##1}\expandafter\flushleftlabelclass \thetextprefix}% + \unexpanded\def#7##1{#3{##1}\expandafter\flushrightlabelclass\thetextprefix}% + \unexpanded\def#8##1{#3{##1}\expandafter\flushbothlabelclass \thetextprefix}% #2 + \unexpanded\def#9##1{#3{##1}\expandafter\flushleftlabelclass \thetextprefix}% + \fi + \appendtoks + \let#6\firstofoneargument % to be checked + \let#7\firstofoneargument % to be checked + \let#8\firstofoneargument % to be checked + \let#9\firstofoneargument % to be checked + \to \everysimplifycommands} + +\let\flushleftlabelclass \firstoftwoarguments +\let\flushrightlabelclass\secondoftwoarguments +\def\flushbothlabelclass #1#2#3{#1#3#2} +\def\dummytextprefix {\empty\empty} + +%D \macros +%D {headtext, labeltext, leftlabeltext, rightlabeltext, labeltexts} +%D +%D Once defined, head and label texts can be called upon using: +%D +%D \showsetup{headtext} +%D \showsetup{labeltext} +%D +%D \macros +%D {presetheadtext,presetlabeltext} +%D +%D These macros enable us to automatically define head and label texts without +%D replacing predefined ones. They are internal macros. + +\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate + +\newconstant\protecttextprefixes + +\let\currenttextprefixtag \s!unknown +\let\currenttextprefixclass\s!unknown + +\def\lang_labels_text_prefix_start[#1][#2][#3]% class language name + {\ifthirdargument + \edef\currenttextprefixtag{\reallanguagetag{#2}}% + \edef\currenttextprefixname{#3}% + \else + \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}% + \edef\currenttextprefixname{#2}% + \fi + \grabuntil{stop#1text}\lang_labels_text_prefix_start_indeed} + +\def\lang_labels_text_prefix_start_indeed#1% text (not special checking done here yet, only for long texts anyway) + {\expandafter\edef\csname\??label\currenttextprefixclass:\currenttextprefixtag:\currenttextprefixname\endcsname% + {{\clf_strip{#1}}\empty}} + +\def\lang_labels_text_prefix_setup[#1][#2]% + {\ifsecondargument + \edef\currenttextprefixtag{\reallanguagetag{#1}}% + \processcommalist[#2]\lang_labels_text_prefix_setup_indeed + \else + \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}% + \processcommalist[#1]\lang_labels_text_prefix_setup_indeed + \fi} + +\def\lang_labels_text_prefix_setup_indeed#1% + {\lang_labels_text_prefix_assign[#1]} + +\def\lang_labels_text_prefix_assign[#1=#2]% + {\lang_labels_text_prefix_assign_indeed{#1}[#2,,]} + +\def\lang_labels_text_prefix_assign_indeed#1% + {\ifcase\protecttextprefixes + % no checking + \expandafter\lang_labels_text_prefix_assign_yes + \or + % checking + \ifcsname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname + \expandafter\expandafter\expandafter\lang_labels_text_prefix_assign_nop + \else + \expandafter\expandafter\expandafter\lang_labels_text_prefix_assign_yes + \fi + \or + % simple assignment (a bit overkill but it fits in the whole) + \expandafter\lang_labels_text_prefix_assign_dumb + \fi{#1}} + +\let\m_lang_labels_left \empty +\let\m_lang_labels_right\empty + +% \def\lang_labels_text_prefix_assign_yes#1[#2,#3,#4]% +% {\def\m_lang_labels_left {#2}% no longer an edef ... else \Word undefined expansion issues +% \def\m_lang_labels_right{#3}% no longer an edef ... else \Word undefined expansion issues +% \ifx\m_lang_labels_right\empty +% \ifx\m_lang_labels_left\empty +% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{\empty\empty}% +% \else +% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{{#2}\empty}% +% \fi +% \else +% \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{{#2}{#3}}% +% \fi} +% +% how we love obscure efficicency ... + +\def\lang_labels_text_prefix_assign_yes#1[#2,#3,#4]% + {\def\m_lang_labels_left {#2}% no longer an edef ... else \Word undefined expansion issues + \def\m_lang_labels_right{#3}% no longer an edef ... else \Word undefined expansion issues + \expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1% + \ifx\m_lang_labels_right\empty + \ifx\m_lang_labels_left\empty + \endcsname{\empty\empty}% + \else + \endcsname{{#2}\empty}% + \fi + \else + \endcsname{{#2}{#3}}% + \fi} + +\def\lang_labels_text_prefix_assign_nop#1[#2]% + {} + +\def\lang_labels_text_prefix_assign_dumb#1[#2,#3]% + {\expandafter\def\csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\endcsname{#2}} + +\unexpanded\def\setlabeltextpair#1#2#3#4#5% a fast one for usage at the Lua end + {%\writestatus{!!!!}{#1:\reallanguagetag{#2}:#3}% + \expandafter\def\csname\??label#1:\reallanguagetag{#2}:#3\endcsname{{#4}{#5}}} % class tag key left right + +\def\lang_labels_text_prefix_copy[#1][#2]% + {\ifsecondargument + \edef\currenttextprefixtag{\reallanguagetag{#1}}% + \processcommalist[#2]\lang_labels_text_prefix_copy_indeed + \else + \edef\currenttextprefixtag{\reallanguagetag\currentmainlanguage}% + \processcommalist[#1]\lang_labels_text_prefix_copy_indeed + \fi} + +\def\lang_labels_text_prefix_copy_indeed#1% + {\lang_labels_text_prefix_copy_pair[#1]} + +\def\lang_labels_text_prefix_copy_pair[#1=#2]% + {\lang_labels_text_prefix_copy_pair_indeed{#1}[#2,,]} + +% \def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]% +% {\expandafter\let +% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#1\expandafter\endcsname +% \csname\??label\currenttextprefixclass:\currenttextprefixtag:#2\endcsname} +% +% this delays the aliasing so that we can switch maillanguage in between + +\def\lang_labels_text_prefix_copy_pair_indeed#1[#2,#3]% + {\expandafter\edef\csname\??label\currenttextprefixclass:#1\endcsname + {{\noexpand\csname\??label\currenttextprefixclass:\noexpand\reallanguagetag\noexpand\currentmainlanguage:#2\endcsname}{}}} + +\definelabelclass [head] [0] % titles +\definelabelclass [label] [0] % texts +\definelabelclass [mathlabel] [0] % functions +\definelabelclass [taglabel] [2] % tags + +\clf_definelabels{head}{titles}\s!true\relax +\clf_definelabels{label}{texts}\s!true\relax +\clf_definelabels{mathlabel}{functions}\s!false\relax +\clf_definelabels{taglabel}{tags}\s!false\relax + +%D \macros +%D {translate} +%D +%D Sometimes macros contain language specific words that are to be typeset. Such +%D macros can be made (more) language independant by using: +%D +%D \showsetup{translate} +%D +%D like for instance: +%D +%D \starttyping +%D \translate[en=something,nl=iets] +%D \stoptyping +%D +%D which expands to {\em something} or {\em iets}, depending on de current language. + +\installcorenamespace{translation} + +\unexpanded\def\translate + {\dosingleempty\lang_translate} + +\def\lang_translate[#1]% + {\getparameters[\??translation][#1]% + \ifcsname\??translation\currentlanguage\endcsname + \lastnamedcs + \orelse\ifcsname\??translation\s!en\endcsname + \lastnamedcs + \else + [translation #1]% + \fi} + +%D When used without argument, the last defined values are used. This enables +%D repetitive use like +%D +%D \starttyping +%D \en \translate\ means \nl \translate +%D \stoptyping + +%D \macros +%D {assigntranslation} +%D +%D This macro is a system macro, and can be used to assign a translation to a macro. +%D Its form is: +%D +%D \starttyping +%D \assigntranslation[en=something,nl=iets]\to\command +%D \stoptyping + +\unexpanded\def\assigntranslation[#1]\to#2% bad, this \to + {\getparameters[\??translation][#1]% + \edef#2{\begincsname\??translation\currentlanguage\endcsname}} + +%D \macros +%D {commalistsentence} +%D +%D Redone in \LUA: +%D +%D \startbuffer +%D \commalistsentence[aap,noot,mies] +%D \commalistsentence[aap,noot] +%D \commalistsentence[aap] +%D \commalistsentence[a,b,c] +%D \commalistsentence[a,b,c][{ \& },{ and }] +%D \commalistsentence[a,b,c][+,-] +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlines +%D \getbuffer +%D \stoplines + +\unexpanded\def\commalistsentence + {\dodoubleempty\typo_helpers_concat_comma_list} + +\def\typo_helpers_concat_comma_list[#1][#2]% + {\clf_concatcommalist + text {#1}% + separators {#2}% + separator {\detokenize\expandafter{\normalexpanded{\labeltext{and-1}}}}% + last {\detokenize\expandafter{\normalexpanded{\labeltext{and-2}}}}% + \relax} + +\setuplabeltext [\s!nl] [and-1={{, }}, and-2={{ en }}] % 1, 2 en 3 +\setuplabeltext [\s!en] [and-1={{, }}, and-2={{, }}] % 1, 2, 3 +\setuplabeltext [\s!de] [and-1={{, }}, and-2={{ und }}] % 1, 2 und 3 +\setuplabeltext [\s!hr] [and-1={{, }}, and-2={{ i }}] % 1, 2 i 3 + +%D Goodie (handy at \LUA\ end): + +\unexpanded\def\LABELTEXT#1{\WORD{\labeltext{#1}}} % only for simple cases! + +\protect \endinput diff --git a/tex/context/base/mkiv/lpdf-eng.lua b/tex/context/base/mkiv/lpdf-eng.lua index 42435fad5..21c7e66e9 100644 --- a/tex/context/base/mkiv/lpdf-eng.lua +++ b/tex/context/base/mkiv/lpdf-eng.lua @@ -6,10 +6,6 @@ if not modules then modules = { } end modules ['lpdf-eng'] = { license = "see context related readme files" } -if CONTEXTLMTXMODE > 0 then - return -end - -- Here we plug in the regular luatex image handler. The low level module itself -- is hidden from the user. diff --git a/tex/context/base/mkiv/lpdf-lmt.lua b/tex/context/base/mkiv/lpdf-lmt.lua index 8fdbf9a36..5d8ad063c 100644 --- a/tex/context/base/mkiv/lpdf-lmt.lua +++ b/tex/context/base/mkiv/lpdf-lmt.lua @@ -18,10 +18,6 @@ if not modules then modules = { } end modules ['lpdf-lmt'] = { -- Thomas's turture test (also for other reasons). But .. who knows what magic -- I can cook up in due time. -if CONTEXTLMTXMODE == 0 then - return -end - -- If you consider this complex, watch: -- -- https://www.youtube.com/watch?v=6H-cAzfB2qo diff --git a/tex/context/base/mkiv/lpdf-nod.lua b/tex/context/base/mkiv/lpdf-nod.lua index db99f0e5d..fcb2d1457 100644 --- a/tex/context/base/mkiv/lpdf-nod.lua +++ b/tex/context/base/mkiv/lpdf-nod.lua @@ -6,10 +6,6 @@ if not modules then modules = { } end modules ['lpdf-nod'] = { license = "see context related readme files" } -if CONTEXTLMTXMODE > 0 then - return -end - local nodecodes = nodes.nodecodes local whatsitcodes = nodes.whatsitcodes diff --git a/tex/context/base/mkiv/luat-env.lua b/tex/context/base/mkiv/luat-env.lua index e0c69d207..e6a0c8c5d 100644 --- a/tex/context/base/mkiv/luat-env.lua +++ b/tex/context/base/mkiv/luat-env.lua @@ -71,6 +71,17 @@ function environment.texfile(filename) end function environment.luafile(filename) -- needs checking + + if CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 and file.suffix(filename) == "lua" then + -- no "tex", as that's pretty slow when not found (suffixes get appended, shouldn't happen) + -- trackers.enable("resolvers.*") + local resolved = resolvers.findfile(file.replacesuffix(filename,"lmt")) or "" + -- trackers.disable("resolvers.*") + if resolved ~= "" then + return resolved + end + end + local resolved = resolvers.findfile(filename,'tex') or "" if resolved ~= "" then return resolved diff --git a/tex/context/base/mkiv/luat-fmt.lua b/tex/context/base/mkiv/luat-fmt.lua index 586c5948e..86cf5cf9e 100644 --- a/tex/context/base/mkiv/luat-fmt.lua +++ b/tex/context/base/mkiv/luat-fmt.lua @@ -107,8 +107,16 @@ function environment.make_format(name,arguments) end report_format("using format path %a",dir.current()) -- check source file - local texsourcename = file.addsuffix(name,"mkiv") - local fulltexsourcename = resolvers.findfile(texsourcename,"tex") or "" + local texsourcename = "" + local fulltexsourcename = "" + if engine == "luametatex" then + texsourcename = file.addsuffix(name,"mkxl") + fulltexsourcename = resolvers.findfile(texsourcename,"tex") or "" + end + if fulltexsourcename == "" then + texsourcename = file.addsuffix(name,"mkiv") + fulltexsourcename = resolvers.findfile(texsourcename,"tex") or "" + end if fulltexsourcename == "" then texsourcename = file.addsuffix(name,"tex") fulltexsourcename = resolvers.findfile(texsourcename,"tex") or "" diff --git a/tex/context/base/mkiv/luat-lib.mkiv b/tex/context/base/mkiv/luat-lib.mkiv index 381a60e42..5b14b1d11 100644 --- a/tex/context/base/mkiv/luat-lib.mkiv +++ b/tex/context/base/mkiv/luat-lib.mkiv @@ -19,18 +19,13 @@ \registerctxluafile{util-sac}{optimize} \registerctxluafile{util-sto}{} % could also be done in trac-deb.mkiv \registerctxluafile{util-pck}{} -% \registerctxluafile{util-seq}{} -%registerctxluafile{util-mrg}{} % not needed in context itself, only mtxrun -%registerctxluafile{util-lua}{} % moved \registerctxluafile{util-prs}{} \registerctxluafile{util-fmt}{} \registerctxluafile{util-dim}{} -%registerctxluafile{trac-inf}{} \registerctxluafile{trac-set}{} \registerctxluafile{trac-log}{} \registerctxluafile{trac-inf}{} -%registerctxluafile{trac-pro}{} \registerctxluafile{util-lua}{} \registerctxluafile{util-deb}{} % could also be done in trac-deb.mkiv @@ -43,16 +38,12 @@ \registerctxluafile{util-soc-imp-reset} {} \registerctxluafile{util-soc-imp-socket} {} -%registerctxluafile{util-soc-imp-copas} {} \registerctxluafile{util-soc-imp-ltn12} {} -%registerctxluafile{util-soc-imp-mbox} {} \registerctxluafile{util-soc-imp-mime} {} \registerctxluafile{util-soc-imp-url} {} \registerctxluafile{util-soc-imp-headers}{} \registerctxluafile{util-soc-imp-http} {} \registerctxluafile{util-soc-imp-tp} {} -%registerctxluafile{util-soc-imp-ftp} {} -%registerctxluafile{util-soc-imp-smtp} {} \ifcase\contextlmtxmode\else \registerctxluafile{util-zip}{} diff --git a/tex/context/base/mkiv/luat-mac.lua b/tex/context/base/mkiv/luat-mac.lua index cc1ee67f2..91148bc32 100644 --- a/tex/context/base/mkiv/luat-mac.lua +++ b/tex/context/base/mkiv/luat-mac.lua @@ -337,8 +337,8 @@ if resolvers.schemes then return cachename end - resolvers.schemes.install('mkvi',handler,1) -- this will cache ! - resolvers.schemes.install('mklx',handler,1) -- bonus, best use just mkvi + resolvers.schemes.install('mkvi',handler,1) + resolvers.schemes.install('mklx',handler,1) end diff --git a/tex/context/base/mkiv/meta-imp-dum.mkiv b/tex/context/base/mkiv/meta-imp-dum.mkiv index b84d4ac7a..457de4b35 100644 --- a/tex/context/base/mkiv/meta-imp-dum.mkiv +++ b/tex/context/base/mkiv/meta-imp-dum.mkiv @@ -30,69 +30,70 @@ %D %D \typebuffer \getbuffer -% currently preparempvariables is unable to resolve number -% fractions like reduction - -% June 22, 2003, this definition was patched to adapt itself -% to transparent colors, but ... in 2011 we no longer have -% is_transparent so we revert. -% -% \startuseMPgraphic{placeholder}{width,height,reduction,color} -% numeric w, h, d, r ; color c, b, cc ; path p ; boolean t ; -% t := is_transparent(\MPvar{color}) ; -% c := not_transparent(\MPvar{color}) ; -% b := not_transparent(white) ; -% w := \MPvar{width} ; -% h := \MPvar{height} ; -% r := \MPvar{reduction} ; -% d := max(w,h) ; -% p := unitsquare xyscaled (w,h) ; -% cc := r[.5c,b] ; -% fill p withcolor if t : transparent(1,.5,cc) else : cc fi ; -% for i := 1 upto 60 : -% cc := r[c randomized(.3,.9),b] ; -% fill fullcircle -% scaled (d/5 randomized (d/5)) -% shifted (center p randomized (d)) -% withcolor if t : transparent(1,.5,cc) else : cc fi ; -% endfor ; -% clip currentpicture to p ; -% \stopuseMPgraphic - -\startuseMPgraphic{minifun::figure:placeholder}{width,height,reduction,color} - begingroup ; - save w, h, d, r, p, c, b ; - numeric w, h, d, r ; path p ; - if cmykcolor \MPvar{color} : - cmykcolor c, b ; b := (0,0,0,0) - else : - color c, b ; b := (1,1,1) - fi ; - c := \MPvar{color} ; - w := \MPvar{width} ; - h := \MPvar{height} ; - r := \MPvar{reduction} ; - d := max(w,h) ; - p := unitsquare xyscaled (w,h) ; - fill p withcolor r[.5c,b] ; - for i := 1 upto 60 : - fill fullcircle - scaled (d/5 randomized (d/5)) - shifted (center p randomized (d)) - withcolor r[c randomized(.3,.9),b] ; - endfor ; - clip currentpicture to p ; - endgroup ; -\stopuseMPgraphic - -\defineoverlay - [figure:placeholder:graphic] - [\useMPgraphic - {minifun::figure:placeholder}% - {width=\figurewidth,% - height=\figureheight,% - reduction=\externalfigureparameter\c!reduction,% - color=placeholder:\the\c_grph_replacement_n}] % weird, why do we need to prefix the palette +\startmkivmode + +%D Currently preparempvariables is unable to resolve number fractions like +%D reduction. + + \startuseMPgraphic{minifun::figure:placeholder}{width,height,reduction,color} + begingroup ; + save w, h, d, r, p, c, b ; + numeric w, h, d, r ; path p ; + if cmykcolor \MPvar{color} : + cmykcolor c, b ; b := (0,0,0,0) + else : + color c, b ; b := (1,1,1) + fi ; + c := \MPvar{color} ; + w := \MPvar{width} ; + h := \MPvar{height} ; + r := \MPvar{reduction} ; + d := max(w,h) ; + p := unitsquare xyscaled (w,h) ; + fill p withcolor r[.5c,b] ; + for i := 1 upto 60 : + fill fullcircle + scaled (d/5 randomized (d/5)) + shifted (center p randomized (d)) + withcolor r[c randomized(.3,.9),b] ; + endfor ; + clip currentpicture to p ; + endgroup ; + \stopuseMPgraphic + + \defineoverlay + [figure:placeholder:graphic] + [\useMPgraphic + {minifun::figure:placeholder}% + {width=\figurewidth,% + height=\figureheight,% + reduction=\externalfigureparameter\c!reduction,% + color=placeholder:\the\c_grph_replacement_n}] % weird, why do we need to prefix the palette + +\stopmkivmode + +\startlmtxmode + + \defineMPparameterset + [placeholder] + [width=dimension, + height=dimension, + reduction=number, + color=string, + alternative=string] + + \defineoverlay + [figure:placeholder:graphic] + [{\useMPmacro + [minifun]% + [placeholder]% + [width=\figurewidth,% + height=\figureheight,% + alternative=\externalfigureparameter\c!alternative, + reduction=\externalfigureparameter\c!reduction,% + color=placeholder:\the\c_grph_replacement_n]}] + +\stoplmtxmode \definepalet [placeholder] diff --git a/tex/context/base/mkiv/meta-mac.mkxl b/tex/context/base/mkiv/meta-mac.mkxl new file mode 100644 index 000000000..3bf38b4c8 --- /dev/null +++ b/tex/context/base/mkiv/meta-mac.mkxl @@ -0,0 +1,66 @@ +%D \module +%D [ file=meta-scn, +%D version=2019.07.19, +%D title=\METAPOST\ Graphics, +%D subtitle=LMTX support, +%D author=Hans Hagen, +%D date=\ currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\unprotect + +\unexpanded\def\defineMPparameterset[#1]{\clf_lmt_parameters_define{#1}} +\unexpanded\def\presetMPparameters [#1]{\clf_lmt_parameters_preset{#1}} +\unexpanded\def\resetMPparameters [#1]{\clf_lmt_parameters_reset {#1}} + +% \unexpanded\def\useMPgraphic +% {\doifnextoptionalelse\meta_use_MP_graphic_yes\meta_use_MP_graphic_nop} + +% \def\meta_use_MP_graphic_nop +% {\dodoublegroupempty\meta_use_graphic} + +% \def\meta_use_MP_graphic_yes +% {\dodoubleempty\meta_use_graphic_new} + +% \def\meta_use_graphic_new[#1][#2]% +% {\begingroup +% % If really needed weh can use grouplevel but normally these graphics are +% % not nested. +% \clf_lmt_parameters_preset{#1}[#2]% +% \meta_use_graphic{#1}{}% +% \clf_lmt_parameters_reset{#1}% +% \endgroup} + +\unexpanded\def\useMPmacro + {\dotripleempty\meta_use_macro} + +\def\meta_use_macro[#1][#2][#3]% + {\ifthirdargument + \meta_begin_graphic_group{#1}% + \meta_enable_include + \clf_lmt_parameters_preset{#2}[#3]% + \meta_process_graphic{lmt_#2;}% + \clf_lmt_parameters_reset{#2}% + \meta_end_graphic_group + \else\ifsecondargument + \doifelseassignment{#2} + {\let\currentMPinstance\defaultMPinstance + \meta_enable_include + \clf_lmt_parameters_preset{#1}[#2]% + \meta_process_graphic{lmt_#1;}% + \clf_lmt_parameters_reset{#1}}% + {\meta_begin_graphic_group{#1}% + \meta_enable_include + \meta_process_graphic{lmt_#1;}% + \meta_end_graphic_group}% + \else + \let\currentMPinstance\defaultMPinstance + \meta_enable_include + \meta_process_graphic{lmt_#1;}% + \fi\fi} + +\protect diff --git a/tex/context/base/mkiv/mlib-ctx.mkiv b/tex/context/base/mkiv/mlib-ctx.mkiv index cb925ec9b..145cdb261 100644 --- a/tex/context/base/mkiv/mlib-ctx.mkiv +++ b/tex/context/base/mkiv/mlib-ctx.mkiv @@ -11,83 +11,14 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -%D This file contains the \MPLIB\ variants of the by now ancient -%D \MPTOPDF\ code. - \writestatus{loading}{MetaPost Library Graphics / Initializations} \registerctxluafile{mlib-run}{} \registerctxluafile{mlib-ctx}{} \registerctxluafile{mlib-lua}{} - -\startlmtxmode - \doifelsefileexists{mlib-scn.lua} { - \registerctxluafile{mlib-scn}{} - } { - % experimental code for Alan and me - } -\stoplmtxmode - \registerctxluafile{mlib-lmp}{} \registerctxluafile{mlib-int}{} \unprotect \protect \endinput - -% local mpgraphic = [[ -% for i=1 upto 1000 : -% beginfig(0); -% draw halfcircle scaled 1cm withcolor green ; -% picture p ; p := "oeps" infont defaultfont scaled .75 rotated 45 ; -% p := p shifted - (xpart center p,0) ; -% draw p ; draw boundingbox p ; -% endfig ; -% beginfig(0); -% draw halfcircle scaled 1cm dashed evenly withcolor green ; -% endfig ; -% beginfig(0); -% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ; -% draw halfcircle scaled 1cm withcolor red ; -% endfig ; -% beginfig(0); -% draw halfcircle scaled 1cm ; -% endfig ; -% beginfig(0); -% pickup pencircle xscaled .5mm yscaled .25mm rotated 45 ; -% for k:=1 upto 10 : -% draw halfcircle scaled uniformdeviate(1cm) withcolor (red/(k/4)) ; -% endfor ; -% endfig ; -% endfor ; -% ]] -% -- local mpx = metapost.format("metafun") -% metapost.process(metapost.format("metafun"),mpgraphic) - -% \starttext -% \setupcolors[state=start] -% \definecolor[red] [r=1] -% \definecolor[cyan][c=1] -% \setbox\scratchbox\hbox{\startMPcode\stopMPcode} % first specials are forgotten -% \definecolor[sss][t=.5,a=1,r=1] -% \definespotcolor[oeps1][green][p=.5] -% \definespotcolor[oeps2][green][p=.25] -% \definespotcolor[oeps3][green][p=.25,t=.5,a=1] -% \startMPpage -% fill fullcircle scaled 10cm withcolor \MPcolor{red} ; -% fill fullcircle scaled 8cm withcolor cmyk(1,0,0,0) ; -% fill fullcircle scaled 6cm withcolor cmyk(0,1,0,0) ; -% fill fullcircle scaled 4cm withcolor cmyk(0,0,1,0) ; -% fill fullcircle scaled 2cm withcolor cmyk(0,0,0,1) ; -% currentpicture := currentpicture shifted (-7.5cm,0) ; -% fill fullcircle scaled 10cm withcolor transparent(1,0.75,cmyk(0,0,1,0)) ; -% fill fullcircle scaled 8cm withcolor \MPcolor{sss} ; -% fill fullcircle scaled 6cm withcolor \MPcolor{oeps1} ; -% fill fullcircle scaled 4cm withcolor \MPcolor{oeps2} ; -% currentpicture := currentpicture shifted (-7.5cm,0) ; -% fill fullcircle scaled 10cm withcolor \MPcolor{oeps3} ; -% circular_shade(fullcircle scaled 8cm, 1, red, blue) ; -% circular_shade(fullcircle scaled 6cm, 1, (1,0,0,0), (0,1,0,0)) ; -% circular_shade(fullcircle scaled 4cm, 1, cmyk(.5,.5,1,0), (0,1,0,0)) ; -% \stopMPpage -% \stoptext diff --git a/tex/context/base/mkiv/mlib-ctx.mkxl b/tex/context/base/mkiv/mlib-ctx.mkxl new file mode 100644 index 000000000..56b8587a8 --- /dev/null +++ b/tex/context/base/mkiv/mlib-ctx.mkxl @@ -0,0 +1,27 @@ +%D \module +%D [ file=mlib-ctx, +%D version=2008.03.25, +%D title=\METAPOST\ Integrated Graphics, +%D subtitle=Basics, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{MetaPost Library Graphics / Initializations} + +\registerctxluafile{mlib-run}{} +\registerctxluafile{mlib-ctx}{} +\registerctxluafile{mlib-lua}{} +\registerctxluafile{mlib-scn}{} +\registerctxluafile{mlib-mat}{} +\registerctxluafile{mlib-lmp}{} +\registerctxluafile{mlib-int}{} + +\unprotect + +\protect \endinput + diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 8310a2925..a3e5e84cd 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -62,12 +62,14 @@ do local stack = { } local get_numeric = mplib.get_numeric + local get_integer = mplib.get_integer local get_string = mplib.get_string local get_boolean = mplib.get_boolean local get_path = mplib.get_path get.numeric = function(s) return get_numeric(currentmpx,s) end get.number = function(s) return get_numeric(currentmpx,s) end + get.integer = function(s) return get_integer(currentmpx,s) end get.string = function(s) return get_string (currentmpx,s) end get.boolean = function(s) return get_boolean(currentmpx,s) end get.path = function(s) return get_path (currentmpx,s) end @@ -81,6 +83,7 @@ do local scan_token = mplib.scan_token local scan_symbol = mplib.scan_symbol local scan_numeric = mplib.scan_numeric + local scan_integer = mplib.scan_integer local scan_boolean = mplib.scan_boolean local scan_string = mplib.scan_string local scan_pair = mplib.scan_pair @@ -95,6 +98,7 @@ do scan.symbol = function(k) return scan_symbol (currentmpx,k) end scan.numeric = function() return scan_numeric (currentmpx) end scan.number = function() return scan_numeric (currentmpx) end + scan.integer = function() return scan_integer (currentmpx) end scan.boolean = function() return scan_boolean (currentmpx) end scan.string = function() return scan_string (currentmpx) end scan.pair = function(t) return scan_pair (currentmpx,t) end diff --git a/tex/context/base/mkiv/mlib-mat.lua b/tex/context/base/mkiv/mlib-mat.lua new file mode 100644 index 000000000..4646a8979 --- /dev/null +++ b/tex/context/base/mkiv/mlib-mat.lua @@ -0,0 +1,133 @@ +if not modules then modules = { } end modules ['mlib-mat'] = { + version = 1.001, + comment = "companion to mlib-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +local scanners = mp.scan +local registerscript = metapost.registerscript + +local scannumeric = scanners.numeric +local scanpair = scanners.pair +local scancolor = scanners.color + +local mppair = mp.pair + +local m = xmath +local c = xcomplex + +local m_acos = m.acos registerscript("m_acos", function() return m_acos (scannumeric()) end) +local m_acosh = m.acosh registerscript("m_acosh", function() return m_acosh (scannumeric()) end) +local m_asin = m.asin registerscript("m_asin", function() return m_asin (scannumeric()) end) +local m_asinh = m.asinh registerscript("m_asinh", function() return m_asinh (scannumeric()) end) +local m_atan = m.atan registerscript("m_atan", function() return m_atan (scannumeric()) end) +local m_atan2 = m.atan2 registerscript("m_atan2", function() return m_atan2 (scanpair ()) end) +local m_atanh = m.atanh registerscript("m_atanh", function() return m_atanh (scannumeric()) end) +local m_cbrt = m.cbrt registerscript("m_cbrt", function() return m_cbrt (scannumeric()) end) +local m_ceil = m.ceil registerscript("m_ceil", function() return m_ceil (scannumeric()) end) +local m_copysign = m.copysign registerscript("m_copysign", function() return m_copysign (scanpair ()) end) +local m_cos = m.cos registerscript("m_cos", function() return m_cos (scannumeric()) end) +local m_cosh = m.cosh registerscript("m_cosh", function() return m_cosh (scannumeric()) end) +local m_deg = m.deg registerscript("m_deg", function() return m_deg (scannumeric()) end) +local m_erf = m.erf registerscript("m_erf", function() return m_erf (scannumeric()) end) +local m_erfc = m.erfc registerscript("m_erfc", function() return m_erfc (scannumeric()) end) +local m_exp = m.exp registerscript("m_exp", function() return m_exp (scannumeric()) end) +local m_exp2 = m.exp2 registerscript("m_exp2", function() return m_exp2 (scannumeric()) end) +local m_expm1 = m.expm1 registerscript("m_expm1", function() return m_expm1 (scannumeric()) end) +local m_fabs = m.fabs registerscript("m_fabs", function() return m_fabs (scannumeric()) end) +local m_fdim = m.fdim registerscript("m_fdim", function() return m_fdim (scanpair ()) end) +local m_floor = m.floor registerscript("m_floor", function() return m_floor (scannumeric()) end) +local m_fma = m.fma registerscript("m_fma", function() return m_fma (scancolor ()) end) +local m_fmax = m.fmax registerscript("m_fmax", function() return m_fmax (scannumeric()) end) +local m_fmin = m.fmin registerscript("m_fmin", function() return m_fmin (scannumeric()) end) +local m_fmod = m.fmod registerscript("m_fmod", function() return m_fmod (scanpair ()) end) +local m_frexp = m.frexp registerscript("m_frexp", function() return m_frexp (scannumeric()) end) +local m_gamma = m.gamma registerscript("m_gamma", function() return m_gamma (scannumeric()) end) +local m_hypot = m.hypot registerscript("m_hypot", function() return m_hypot (scanpair ()) end) +local m_isfinite = m.isfinite registerscript("m_isfinite", function() return m_isfinite (scannumeric()) end) +local m_isinf = m.isinf registerscript("m_isinf", function() return m_isinf (scannumeric()) end) +local m_isnan = m.isnan registerscript("m_isnan", function() return m_isnan (scannumeric()) end) +local m_isnormal = m.isnormal registerscript("m_isnormal", function() return m_isnormal (scannumeric()) end) +local m_j0 = m.j0 registerscript("m_j0", function() return m_j0 (scannumeric()) end) +local m_j1 = m.j1 registerscript("m_j1", function() return m_j1 (scannumeric()) end) +local m_jn = m.jn registerscript("m_jn", function() return m_jn (scanpair ()) end) +local m_ldexp = m.ldexp registerscript("m_ldexp", function() return m_ldexp (scanpair ()) end) +local m_lgamma = m.lgamma registerscript("m_lgamma", function() return m_lgamma (scannumeric()) end) +local m_log = m.log registerscript("m_log", function() return m_log (scannumeric()) end) +local m_log10 = m.log10 registerscript("m_log10", function() return m_log10 (scannumeric()) end) +local m_log1p = m.log1p registerscript("m_log1p", function() return m_log1p (scannumeric()) end) +local m_log2 = m.log2 registerscript("m_log2", function() return m_log2 (scannumeric()) end) +local m_logb = m.logb registerscript("m_logb", function() return m_logb (scannumeric()) end) +local m_modf = m.modf registerscript("m_modf", function() return m_modf (scannumeric()) end) +local m_nearbyint = m.nearbyint registerscript("m_nearbyint", function() return m_nearbyint(scannumeric()) end) +local m_nextafter = m.nextafter registerscript("m_nextafter", function() return m_nextafter(scanpair ()) end) +local m_pow = m.pow registerscript("m_pow", function() return m_pow (scanpair ()) end) +local m_rad = m.rad registerscript("m_rad", function() return m_rad (scannumeric()) end) +local m_remainder = m.remainder registerscript("m_remainder", function() return m_remainder(scanpair ()) end) +local m_remquo = m.remquo registerscript("m_remquo", function() return m_remquo (scannumeric()) end) +local m_round = m.round registerscript("m_round", function() return m_round (scannumeric()) end) +local m_scalbn = m.scalbn registerscript("m_scalbn", function() return m_scalbn (scanpair ()) end) +local m_sin = m.sin registerscript("m_sin", function() return m_sin (scannumeric()) end) +local m_sinh = m.sinh registerscript("m_sinh", function() return m_sinh (scannumeric()) end) +local m_sqrt = m.sqrt registerscript("m_sqrt", function() return m_sqrt (scannumeric()) end) +local m_tan = m.tan registerscript("m_tan", function() return m_tan (scannumeric()) end) +local m_tanh = m.tanh registerscript("m_tanh", function() return m_tanh (scannumeric()) end) +local m_tgamma = m.tgamma registerscript("m_tgamma", function() return m_tgamma (scannumeric()) end) +local m_trunc = m.trunc registerscript("m_trunc", function() return m_trunc (scannumeric()) end) +local m_y0 = m.y0 registerscript("m_y0", function() return m_y0 (scannumeric()) end) +local m_y1 = m.y1 registerscript("m_y1", function() return m_y1 (scannumeric()) end) +local m_yn = m.yn registerscript("m_yn", function() return m_yn (scanpair ()) end) + +local c_topair = c.topair +local c_new = c.new + +local c_sin = c.sin registerscript("c_sin", function() return mppair(c_topair(c_sin (c_new(scanpair())))) end) +local c_cos = c.cos registerscript("c_cos", function() return mppair(c_topair(c_cos (c_new(scanpair())))) end) +local c_tan = c.tan registerscript("c_tan", function() return mppair(c_topair(c_tan (c_new(scanpair())))) end) +local c_sinh = c.sinh registerscript("c_sinh", function() return mppair(c_topair(c_sinh (c_new(scanpair())))) end) +local c_cosh = c.cosh registerscript("c_cosh", function() return mppair(c_topair(c_cosh (c_new(scanpair())))) end) +local c_tanh = c.tanh registerscript("c_tanh", function() return mppair(c_topair(c_tanh (c_new(scanpair())))) end) + +local c_asin = c.asin registerscript("c_asin", function() return mppair(c_topair(c_sin (c_new(scanpair())))) end) +local c_acos = c.acos registerscript("c_acos", function() return mppair(c_topair(c_cos (c_new(scanpair())))) end) +local c_atan = c.atan registerscript("c_atan", function() return mppair(c_topair(c_tan (c_new(scanpair())))) end) +local c_asinh = c.asinh registerscript("c_asinh", function() return mppair(c_topair(c_sinh (c_new(scanpair())))) end) +local c_acosh = c.acosh registerscript("c_acosh", function() return mppair(c_topair(c_cosh (c_new(scanpair())))) end) +local c_atanh = c.atanh registerscript("c_atanh", function() return mppair(c_topair(c_tanh (c_new(scanpair())))) end) + +local c_sqrt = c.sqrt registerscript("c_sqrt", function() return mppair(c_topair(c_sqrt (c_new(scanpair())))) end) +local c_abs = c.abs registerscript("c_abs", function() return c_topair(c_abs (c_new(scanpair()))) end) +local c_arg = c.arg registerscript("c_arg", function() return c_topair(c_arg (c_new(scanpair()))) end) +local c_conj = c.conj registerscript("c_conj", function() return mppair(c_topair(c_conj (c_new(scanpair())))) end) +local c_exp = c.exp registerscript("c_exp", function() return mppair(c_topair(c_exp (c_new(scanpair())))) end) +local c_log = c.log registerscript("c_log", function() return mppair(c_topair(c_log (c_new(scanpair())))) end) +local c_proj = c.proj registerscript("c_proj", function() return mppair(c_topair(c_proj (c_new(scanpair())))) end) + +local c_erf = c.erf registerscript("c_erf", function() return mppair(c_topair(c_erf (c_new(scanpair())))) end) +local c_erfc = c.erfc registerscript("c_erfc", function() return mppair(c_topair(c_erfc (c_new(scanpair())))) end) +local c_erfcx = c.erfcx registerscript("c_erfcx", function() return mppair(c_topair(c_erfcx (c_new(scanpair())))) end) +local c_erfi = c.erfi registerscript("c_erfi", function() return mppair(c_topair(c_erfi (c_new(scanpair())))) end) +local c_dawson = c.dawson registerscript("c_dawson", function() return mppair(c_topair(c_dawson(c_new(scanpair())))) end) + +local c_voigt = c.voigt +local c_voigt_hwhm = c.voigt_hwhm + +registerscript("c_voigt", function() + return mppair(c_topair(c_voigt(c_new(scanpair()),c_new(scanpair()),c_new(scanpair())))) +end) + +registerscript("c_voigt_hwhm", function() + return mppair(c_topair(c_voigt_hwhm(c_new(scanpair()),c_new(scanpair())))) +end) + +local c_pow = c.pow registerscript("c_pow", function() return mppair(c_topair(c_pow(c_new(scanpair()),c_new(scanpair())))) end) +local c_add = c.add registerscript("c_add", function() return mppair(c_topair(c_add(c_new(scanpair()),c_new(scanpair())))) end) +local c_sub = c.sub registerscript("c_sub", function() return mppair(c_topair(c_sub(c_new(scanpair()),c_new(scanpair())))) end) +local c_mul = c.mul registerscript("c_mul", function() return mppair(c_topair(c_mul(c_new(scanpair()),c_new(scanpair())))) end) +local c_div = c.div registerscript("c_div", function() return mppair(c_topair(c_div(c_new(scanpair()),c_new(scanpair())))) end) + +local c_imag = c.imag registerscript("c_imag", function() return c_topair(c_imag(c_new(scanpair()))) end) +local c_real = c.real registerscript("c_real", function() return c_topair(c_real(c_new(scanpair()))) end) +local c_neg = c.neg registerscript("c_new", function() return c_topair(c_neg (c_new(scanpair()))) end) diff --git a/tex/context/base/mkiv/mlib-run.lua b/tex/context/base/mkiv/mlib-run.lua index 0118f6cbd..fb1367151 100644 --- a/tex/context/base/mkiv/mlib-run.lua +++ b/tex/context/base/mkiv/mlib-run.lua @@ -434,8 +434,11 @@ function metapost.checkformat(mpsinput,method) if file.suffix(mpsinput) ~= "" then foundfile = find_file(mpsinput) or "" end - if foundfile == "" then - foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or "" + -- if foundfile == "" then + -- foundfile = find_file(file.replacesuffix(mpsinput,"mpvi")) or "" + -- end + if CONTEXTLMTXMODE > 0 and foundfile == "" then + foundfile = find_file(file.replacesuffix(mpsinput,"mpxl")) or "" end if foundfile == "" then foundfile = find_file(file.replacesuffix(mpsinput,"mpiv")) or "" diff --git a/tex/context/base/mkiv/mlib-scn.lua b/tex/context/base/mkiv/mlib-scn.lua new file mode 100644 index 000000000..4045173ac --- /dev/null +++ b/tex/context/base/mkiv/mlib-scn.lua @@ -0,0 +1,529 @@ +if not modules then modules = { } end modules ['mlib-scn'] = { + version = 1.001, + comment = "companion to mlib-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- Very experimental, for Alan and me. + +-- for i = 1 upto 32000 : % 0.062 +-- ts := 5mm / 20; +-- endfor ; +-- +-- for i = 1 upto 32000 : % 0.219 +-- ts := (getparameter "axis" "sy") / 20; +-- endfor ; +-- +-- for i = 1 upto 32000 : % 0.266 +-- ts := (getparameterx "axis" "sy") / 20; +-- endfor ; +-- +-- pushparameters "axis"; +-- for i = 1 upto 32000 : % 0.250 +-- ts := (getparameterx "sy") / 20; +-- endfor ; +-- popparameters; + +local type, next = type, next +local byte = string.byte +local insert, remove = table.insert, table.remove + +local codes = mplib.codes() +local types = mplib.types() + +table.hashed(codes) +table.hashed(types) + +metapost.codes = codes +metapost.types = types + +local setmetatableindex = table.setmetatableindex + +local scanners = mp.scan + +local scannext = scanners.next +local scanexpression = scanners.expression +local scantoken = scanners.token +local scansymbol = scanners.symbol +local scannumeric = scanners.numeric +local scannumber = scanners.number +local scaninteger = scanners.integer +local scanboolean = scanners.boolean +local scanstring = scanners.string +local scanpair = scanners.pair +local scancolor = scanners.color +local scancmykcolor = scanners.cmykcolor +local scantransform = scanners.transform +local scanpath = scanners.path + +local mpprint = mp.print +local mpnumeric = mp.numeric +local mpstring = mp.string +local mpquoted = mp.quoted +local mpboolean = mp.boolean +local mppair = mp.pair +local mppath = mp.path +local mptriplet = mp.triplet +local mpquadruple = mp.quadruple +local mpvalue = mp.value + +local report = logs.reporter("metapost") + +local semicolon_code = codes.semicolon +local equals_code = codes.equals +local comma_code = codes.comma +local colon_code = codes.colon +local leftbrace_code = codes.leftbrace +local rightbrace_code = codes.rightbrace +local leftbracket_code = codes.leftbracket +local rightbracket_code = codes.rightbracket +local leftdelimiter_code = codes.leftdelimiter +local rightdelimiter_code = codes.rightdelimiter +local numeric_code = codes.numeric +local string_code = codes.string +local capsule_code = codes.capsule +local nullary_code = codes.nullary +local tag_code = codes.tag + +local typescanners = nil +local tokenscanners = nil +local scanset = nil +local scanparameters = nil + +scanset = function() -- can be optimized, we now read twice + scantoken() + if scantoken(true) == rightbrace_code then + scantoken() + return { } + else + local l = { } + local i = 0 + while true do + i = i + 1 + local s = scansymbol(true) + if s == "{" then + l[i] = scanset() + elseif s == "[" then + local d = { } + scansymbol() + while true do + local s = scansymbol() + if s == "]" then + break; + elseif s == "," then + -- continue + else + local t = scantoken(true) + if t == equals_code or t == colon_code then + scantoken() + end + d[s] = tokenscanners[scantoken(true)]() + end + end + l[i] = d + else + local e = scanexpression(true) + l[i] = (typescanners[e] or scanexpression)() + end + if scantoken() == rightbrace_code then + break + else + -- whatever + end + end + return l + end +end + +tokenscanners = { + [leftbrace_code] = scanset, + [numeric_code] = scannumeric, + [string_code] = scanstring, + [nullary_code] = scanboolean, -- todo +} + +typescanners = { + [types.known] = scannumeric, + [types.numeric] = scannumeric, + [types.string] = scanstring, + [types.boolean] = scanboolean, + [types.pair] = function() return scanpair (true) end, + [types.color] = function() return scancolor (true) end, + [types.cmykcolor] = function() return scancmykcolor(true) end, + [types.transform] = function() return scantransform(true) end, + [types.path] = function() return scanpath () end, +} + +table.setmetatableindex(tokenscanners,function() + local e = scanexpression(true) + return typescanners[e] or scanexpression +end) + +local function scanparameters(fenced) + local data = { } + local close = "]" + if not fenced then + close = ";" + elseif scansymbol(true) == "[" then + scansymbol() + else + return data + end + while true do + local s = scansymbol() + if s == close then + break; + elseif s == "," then + -- continue + else + local t = scantoken(true) + if t == equals_code or t == colon_code then + -- optional equal or : + scantoken() + end + data[s] = tokenscanners[scantoken(true)]() + end + end + return data +end + +local namespaces = { } +local presets = { } +local passed = { } + +local function get_parameters(nested) + local data = { } + if nested or scansymbol(true) == "[" then + scansymbol() + else + return data + end + while true do + -- a key like 'color' has code 'declare' + -- print(scansymbol(true),scantoken(true),codes[scantoken(true)]) + local s = scansymbol() + if s == "]" then + break; + elseif s == "," then + -- continue + else + local t = scantoken(true) + if t == equals_code or t == colon_code then + -- optional equal or : + scantoken() + end + local kind = scantoken(true) + if kind == leftdelimiter_code or kind == tag_code then + kind = scanexpression(true) + data[s] = (typescanners[kind] or scanexpression)() + elseif kind == leftbracket_code then + data[s] = get_parameters(true) + else + data[s] = tokenscanners[kind]() + end + end + end + return data +end + +local function getparameters() + local namespace = scanstring() + -- same as below + local parameters = get_parameters() + local presets = presets[namespace] + local passed = passed[namespace] + if passed then + if presets then + setmetatableindex(passed,presets) + end + setmetatableindex(parameters,passed) + elseif presets then + setmetatableindex(parameters,presets) + end + namespaces[namespace] = parameters + -- +end + +local function applyparameters() + local saved = namespaces + local namespace = scanstring() + local action = scanstring() -- before we scan the parameters + -- same as above + local parameters = get_parameters() + local presets = presets[namespace] + local passed = passed[namespace] + if passed then + if presets then + setmetatableindex(passed,presets) + end + setmetatableindex(parameters,passed) + elseif presets then + setmetatableindex(parameters,presets) + end + namespaces[namespace] = parameters + -- till here + mpprint(action) + namespaces = saved +end + +local function presetparameters() + local namespace = scanstring() + presets[namespace] = get_parameters() +end + +local function collectnames() + local l = { } -- can be reused but then we can't nest + local n = 0 + while true do + local t = scantoken(true) + -- (1) not really needed + if t == numeric_code or t == capsule_code then + n = n + 1 l[n] = scaninteger(1) + elseif t == string_code then + n = n + 1 l[n] = scanstring(1) + elseif t == nullary_code then + n = n + 1 l[n] = scanboolean(1) + elseif t == leftdelimiter_code then + t = scanexpression(true) + n = n + 1 l[n] = (typescanners[t] or scanexpression)() + else + break + end + end + return l, n +end + +local function get(v) + local t = type(v) + if t == "number" then + return mpnumeric(v) + elseif t == "boolean" then + return mpboolean(v) + elseif t == "string" then + return mpquoted(v) + elseif t == "table" then + local n = #v + if type(v[1]) == "table" then + return mppath(v) -- cycle ? + elseif n == 2 then + return mppair(v) + elseif n == 3 then + return mptriplet(v) + elseif n == 4 then + return mpquadruple(v) + end + end + return mpnumeric(0) +end + +local stack = { } + +local function pushparameters() + local l, n = collectnames() + insert(stack,namespaces) + for i=1,n do + local n = namespaces[l[i]] + if type(n) == "table" then + namespaces = n + else + break + end + end +end + +local function popparameters() + local n = remove(stack) + if n then + namespaces = n + else + report("stack error") + end +end + +local function getparameter() + local list, n = collectnames() + local v = namespaces + for i=1,n do + local l = list[i] + local vl = v[l] + if vl == nil then + if type(l) == "number" then + vl = v[1] + if vl == nil then + return mpnumeric(0) + end + else + return mpnumeric(0) + end + end + v = vl + end + if v == nil then + return mpnumeric(0) + else + return get(v) + end +end + +local function getparameterdefault() + local list, n = collectnames() + local v = namespaces + for i=1,n-1 do + local l = list[i] + local vl = v[l] + if vl == nil then + if type(l) == "number" then + vl = v[1] + if vl == nil then + return get(list[n]) + end + else + return get(list[n]) + end + end + v = vl + end + if v == nil then + return get(list[n]) + else + return get(v) + end +end + +local function getparametercount() + local list, n = collectnames() + local v = namespaces + for i=1,n do + v = v[list[i]] + if not v then + break + end + end + return mpnumeric(type(v) == "table" and #v or 0) +end + +local validconnectors = { + [".."] = true, + ["..."] = true, + ["--"] = true, +} + +local function getparameterpath() + local list, n = collectnames() + local close = list[n] + if type(close) == "boolean" then + n = n - 1 + else + close = false + end + local connector = list[n] + if type(connector) == "string" and validconnectors[connector] then + n = n - 1 + else + connector = "--" + end + local v = namespaces + for i=1,n do + v = v[list[i]] + if not v then + break + end + end + if type(v) == "table" then + return mppath(v,connector,close) + else + return mppair(0,0) + end +end + +local function getparametertext() + local list, n = collectnames() + local strut = list[n] + if type(strut) == "boolean" then + n = n - 1 + else + strut = false + end + local v = namespaces + for i=1,n do + v = v[list[i]] + if not v then + break + end + end + if type(v) == "string" then + return mpquoted("\\strut " .. v) + else + return mpquoted("") + end +end + +metapost.registerscript("getparameters", getparameters) +metapost.registerscript("applyparameters", applyparameters) +metapost.registerscript("presetparameters", presetparameters) +metapost.registerscript("getparameter", getparameter) +metapost.registerscript("getparameterdefault", getparameterdefault) +metapost.registerscript("getparametercount", getparametercount) +metapost.registerscript("getparameterpath", getparameterpath) +metapost.registerscript("getparametertext", getparametertext) +metapost.registerscript("pushparameters", pushparameters) +metapost.registerscript("popparameters", popparameters) + +-- tex scanners + +local scanners = tokens.scanners +local scanhash = scanners.hash +local scanstring = scanners.string +local scanvalue = scanners.value +local scaninteger = scanners.integer +local scanboolean = scanners.boolean +local scanfloat = scanners.float +local scandimension = scanners.dimension + +local definitions = { } + +local bpfactor = number.dimenfactors.bp +local comma = byte(",") +local close = byte("]") + +local scanrest = function() return scanvalue(comma,close) or "" end +local scandimension = function() return scandimension() * bpfactor end + +local scanners = { + ["integer"] = scaninteger, + ["number"] = scanfloat, + ["numeric"] = scanfloat, + ["boolean"] = scanboolean, + ["string"] = scanrest, + ["dimension"] = scandimension, +} + +interfaces.implement { + name = "lmt_parameters_define", + arguments = "string", + actions = function(namespace) + local d = scanhash() + for k, v in next, d do + d[k] = scanners[v] or scanrest + end + definitions[namespace] = d + end, +} + +interfaces.implement { + name = "lmt_parameters_preset", + arguments = "string", + actions = function(namespace) + passed[namespace] = scanhash(definitions[namespace]) + end, +} + +interfaces.implement { + name = "lmt_parameters_reset", + arguments = "string", + actions = function(namespace) + passed[namespace] = nil + end, +} diff --git a/tex/context/base/mkiv/mult-aux.mkiv b/tex/context/base/mkiv/mult-aux.mkiv index d77ec82a1..b29478a56 100644 --- a/tex/context/base/mkiv/mult-aux.mkiv +++ b/tex/context/base/mkiv/mult-aux.mkiv @@ -11,17 +11,9 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -% todo: setupxxx and setupxxxs (so a plural for the root setup and -% we can consider blocking the root) - -% todo (e.g for columnsets and registers): \definexxx[parent][1] -% - -%D A generalization of \MKIV-like inheritance. Just something to play -%D with (interface might change). The code here evolved in an email -%D exchange between me and Wolgang Schuster. - -% todo: doifelse +%D A generalization of \MKIV-like inheritance. Just something to play with +%D (interface might change). The code here evolved in an email exchange between me +%D and Wolgang Schuster. \writestatus{loading}{ConTeXt Multilingual Macros / Helpers} @@ -76,15 +68,15 @@ % todo: add (relaxed) postsetup and postdefine hooks, just after the everys -% Start of experimental code: especially tables can have many assignments -% and although most time is spent in the typesetting anyway, we can squeeze -% out a little bit. Of course having 500 rows of 50 columns each with some -% setting does not happen that often. One should keep in mind that in the -% average document having some 500 assignments is no exception but there we're -% talking of neglectable runtime for them. Of course in the definitions below -% there is no real gain, only in the generated \setup* commands. Another -% situation with many assignments is \XML\ where we can pass attributes -% and normally don't do testing of them making sense. +%D Start of experimental code: especially tables can have many assignments and +%D although most time is spent in the typesetting anyway, we can squeeze out a +%D little bit. Of course having 500 rows of 50 columns each with some setting does +%D not happen that often. One should keep in mind that in the average document +%D having some 500 assignments is no exception but there we're talking of +%D neglectable runtime for them. Of course in the definitions below there is no real +%D gain, only in the generated \setup* commands. Another situation with many +%D assignments is \XML\ where we can pass attributes and normally don't do testing +%D of them making sense. % % \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s % \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s @@ -216,9 +208,9 @@ % \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par % % slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}% -% -% pre-expansion can be a bit faster but handly any effect on a normal run so let's go for -% saving some memory + +%D pre-expansion can be a bit faster but handly any effect on a normal run so let's +%D go for saving some memory \def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter} @@ -281,8 +273,7 @@ \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname chaintocurrent#2\endcsname}} -% In \MKIV\ we can probably use the english variant for all other -% languages too. +%D In \MKIV\ we can probably use the english variant for all other languages too. % todo: inline the def/let @@ -685,14 +676,14 @@ \installsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} -%D Many mechanisms have some kind of inheritance in place, and these are -%D the speed||critical ones. Therefore there is no reason to stick to -%D \type {\@@xxkey} for the sake of performance. For this reason we also -%D provide a direct variant. This permits a more consistent treatment of -%D namespaces. A \type {\whateverparameter} call is three times slower -%D and a \type {\directwhateverparameter} call two times but for some -%D 100K expansions we only loose some .1 second which is neglectable -%D given the small amount of expansions in real runs. +%D Many mechanisms have some kind of inheritance in place, and these are the +%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey} +%D for the sake of performance. For this reason we also provide a direct variant. +%D This permits a more consistent treatment of namespaces. A \type +%D {\whateverparameter} call is three times slower and a \type +%D {\directwhateverparameter} call two times but for some 100K expansions we only +%D loose some .1 second which is neglectable given the small amount of expansions in +%D real runs. %D We don't need colons for such simple cases. @@ -848,22 +839,21 @@ % \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}} % \stoptyping % -% The following variant is nicer and in principle faster but that gets -% unnoticed unless lots of expansion happens. Also, we can use long tags -% but the internal expansion will be relatively small (and unlikely more -% than 4 characters). For instance, \??xx used to expand to @@xx but now -% becomes for instance 123::. This is one character more but in quite some -% cases we had : after such a tag in the old situation. In the new situation -% we create more namespaces and don't need that : any more, so we end up -% with on the average the same amount of tokens and definitely less when -% we consider cases like \??xx:\c!align: which now is just \??somealign and -% therefore has length 5 now (instead of 4+1+5+1=10). +% The following variant is nicer and in principle faster but that gets unnoticed +% unless lots of expansion happens. Also, we can use long tags but the internal +% expansion will be relatively small (and unlikely more than 4 characters). For +% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This +% is one character more but in quite some cases we had : after such a tag in the +% old situation. In the new situation we create more namespaces and don't need that +% : any more, so we end up with on the average the same amount of tokens and +% definitely less when we consider cases like \??xx:\c!align: which now is just +% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10). % -% Eventualy we will have a verbose \blablanamespace and the difference between -% core and regular can go ... after all, \xxxparameter can already clash between -% the two prefix groups .. if users use this mechanism a lot they should use -% verbose names anyway (the old two character names were mostly an optimization -% as they also expanded to these characters). +% Eventualy we will have a verbose \blablanamespace and the difference between core +% and regular can go ... after all, \xxxparameter can already clash between the two +% prefix groups .. if users use this mechanism a lot they should use verbose names +% anyway (the old two character names were mostly an optimization as they also +% expanded to these characters). % todo: register namespaces at lua end for logging and reverse resolve % todo: move this to syst-ini so that we can use it real early @@ -936,8 +926,8 @@ \usedummystyleparameter \usedummycolorparameter -% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] -% but we don't gain much. Actually we might just inline all definitions. +% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we +% don't gain much. Actually we might just inline all definitions. % \enabletrackers[interfaces.namespaces,context.flush] % @@ -1429,74 +1419,45 @@ \installcorenamespace{commalistprocessornext} \installcorenamespace{commalistprocessoraction} -\startmkivmode - - \installcorenamespace{commalistprocessorcheck} - \installcorenamespace{commalistprocessorspace} - \installcorenamespace{commalistprocessorpickup} - \installcorenamespace{commalistprocessorfinish} - - \unexpanded\def\installcommalistprocessor#1#2% 8 macro names overhead - {\let\nexttoken\relax - \unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[% - {\futurelet\nexttoken\csname\??commalistprocessorcheck#1\endcsname}% - \unexpanded\expandafter\edef\csname\??commalistprocessorcheck#1\endcsname - {\noexpand\ifx\nexttoken]% - \noexpand\expandafter\noexpand\gobblethreearguments - \noexpand\else - \noexpand\expandafter\csname\??commalistprocessorwrap#1\endcsname - \noexpand\fi - \relax}% this one preserved the next {} - \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]% - {\csname\??commalistprocessorfirst#1\endcsname##1,]\relax}% - \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname##1% picks up \relax - {\csname\??commalistprocessornext#1\endcsname}% - \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname - {\noexpand\ifx\nexttoken\noexpand\blankspace - \noexpand\expandafter\csname\??commalistprocessorspace#1\endcsname - \noexpand\else - \noexpand\expandafter\csname\??commalistprocessorfinish#1\endcsname - \noexpand\fi}% - \unexpanded\expandafter\edef\csname\??commalistprocessorfinish#1\endcsname - {\noexpand\ifx\nexttoken]% - \noexpand\expandafter\noexpand\gobbleoneargument - \noexpand\else - \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname - \noexpand\fi}% - \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,% - {\noexpand#2{##1}% - \futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% - \let\next\:% - \unexpanded\edef \:{\csname\??commalistprocessorspace#1\endcsname}% - \unexpanded\expandafter\edef\: {\futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% - \let\:\next} - -\stopmkivmode - -\startlmtxmode - - %installcorenamespace{commalistprocessorpickup} - - \unexpanded\def\installcommalistprocessor#1#2% 5 macro names overhead - {\unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[% - % {\noexpand\futureexpandis]% - % \noexpand\gobbleoneargument - % \csname\??commalistprocessorpickup#1\endcsname} - %\unexpanded\expandafter\edef\csname\??commalistprocessorpickup#1\endcsname - {\csname\??commalistprocessorwrap#1\endcsname\relax}% \relax preserves {} - \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]% - {\csname\??commalistprocessorfirst#1\endcsname##1,]} - \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname\relax - {\csname\??commalistprocessornext#1\endcsname}% - \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname - {\noexpand\futureexpandis]% - \noexpand\gobbleoneargument - \csname\??commalistprocessoraction#1\endcsname} - \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,% - {\noexpand#2{##1}% - \csname\??commalistprocessornext#1\endcsname}} - -\stoplmtxmode +\installcorenamespace{commalistprocessorcheck} +\installcorenamespace{commalistprocessorspace} +\installcorenamespace{commalistprocessorpickup} +\installcorenamespace{commalistprocessorfinish} + +\unexpanded\def\installcommalistprocessor#1#2% 8 macro names overhead + {\let\nexttoken\relax + \unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[% + {\futurelet\nexttoken\csname\??commalistprocessorcheck#1\endcsname}% + \unexpanded\expandafter\edef\csname\??commalistprocessorcheck#1\endcsname + {\noexpand\ifx\nexttoken]% + \noexpand\expandafter\noexpand\gobblethreearguments + \noexpand\else + \noexpand\expandafter\csname\??commalistprocessorwrap#1\endcsname + \noexpand\fi + \relax}% this one preserved the next {} + \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]% + {\csname\??commalistprocessorfirst#1\endcsname##1,]\relax}% + \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname##1% picks up \relax + {\csname\??commalistprocessornext#1\endcsname}% + \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname + {\noexpand\ifx\nexttoken\noexpand\blankspace + \noexpand\expandafter\csname\??commalistprocessorspace#1\endcsname + \noexpand\else + \noexpand\expandafter\csname\??commalistprocessorfinish#1\endcsname + \noexpand\fi}% + \unexpanded\expandafter\edef\csname\??commalistprocessorfinish#1\endcsname + {\noexpand\ifx\nexttoken]% + \noexpand\expandafter\noexpand\gobbleoneargument + \noexpand\else + \noexpand\expandafter\csname\??commalistprocessoraction#1\endcsname + \noexpand\fi}% + \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,% + {\noexpand#2{##1}% + \futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% + \let\next\:% + \unexpanded\edef \:{\csname\??commalistprocessorspace#1\endcsname}% + \unexpanded\expandafter\edef\: {\futurelet\nexttoken\csname\??commalistprocessornext#1\endcsname}% + \let\:\next} \unexpanded\def\installcommalistprocessorcommand#1#2% \processor \action {\edef\p_name{\csstring#2}% diff --git a/tex/context/base/mkiv/mult-aux.mkxl b/tex/context/base/mkiv/mult-aux.mkxl new file mode 100644 index 000000000..8343fb8dd --- /dev/null +++ b/tex/context/base/mkiv/mult-aux.mkxl @@ -0,0 +1,1154 @@ +%D \module +%D [ file=mult-aux, +%D version=2010.08.2, +%D title=\CONTEXT\ Multilingual Macros, +%D subtitle=Helpers, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D A generalization of \MKIV-like inheritance. Just something to play with +%D (interface might change). The code here evolved in an email exchange between me +%D and Wolgang Schuster. + +\writestatus{loading}{ConTeXt Multilingual Macros / Helpers} + +\registerctxluafile{mult-aux}{} + +\unprotect + +\edef\??empty{\Uchar25} \letvalue{\Uchar25}\empty % hex 19 + +% \edef\s!parent{\Uchar29} % inlining  is ugly, a tiny bit faster, but neglectable on a run + +%D \starttyping +%D \unprotect +%D \def\????aa{@@@@aa} +%D +%D \installparameterhandler \????aa {whatever} +%D \installsetuphandler \????aa {whatever} +%D \installdefinehandler \????aa {whatever} \????aa % #3 == defaultroot +%D \installfontandcolorhandler\????aa {whatever} +%D +%D % \installcommandhandler \????aa {whatever} \????aa +%D \protect +%D +%D % \whateverparameter \c!test +%D % \whateverparameterhash \c!test +%D % \namedwhateverparameter \mycurrentwhatever \c!test +%D % \usewhateverstyleandcolor \c!style \c!color +%D % \everydefinewhatever (sets \currentwhatever) +%D % \everypresetwhatever (can be used to reset parameters as we can redefine) +%D % \everysetupwhatever (sets \currentwhatever) +%D +%D \starttext +%D \definewhatever[first] \definewhatever[second][first] +%D test: \def\currentwhatever{first} \whateverparameter{method} \par +%D \setupwhatever [method=unset] test: \def\currentwhatever{first} \whateverparameter{method} \par +%D \setupwhatever[first] [method=first] test: \def\currentwhatever{first} \whateverparameter{method} \par +%D test: \def\currentwhatever{second} \whateverparameter{method} \par +%D \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par +%D \stoptext +%D \stoptyping + +% problem: every* could clash +% +% There can be less {} in the following definitions if we assume \??aa and \c!somecs +% +% todo: \def\detokenized...parameter#1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2\endcsname}} % always root +% +% it might be more efficient to do this at the lua and +% +% watch the push/pop and predefinition of current .. this is needed for nested +% definitions and overloaded defines using the predefined one + +% todo: add (relaxed) postsetup and postdefine hooks, just after the everys + +%D Start of experimental code: especially tables can have many assignments and +%D although most time is spent in the typesetting anyway, we can squeeze out a +%D little bit. Of course having 500 rows of 50 columns each with some setting does +%D not happen that often. One should keep in mind that in the average document +%D having some 500 assignments is no exception but there we're talking of +%D neglectable runtime for them. Of course in the definitions below there is no real +%D gain, only in the generated \setup* commands. Another situation with many +%D assignments is \XML\ where we can pass attributes and normally don't do testing +%D of them making sense. +% +% \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s +% \testfeatureonce{100000}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s +% \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s + +\let\m_mult_interfaces_namespace\empty + +\def\mult_interfaces_get_parameters#1[#2% + {\if\noexpand#2]% + \expandafter\gobbleoneargument + \else + \def\m_mult_interfaces_namespace{#1}% + \expandafter\mult_interfaces_get_parameters_indeed + \fi#2} + +\def\mult_interfaces_get_parameters_indeed#1]% namespace already set + {\mult_interfaces_get_parameters_item#1,],^^^^0004} + +\def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before , + {\if,#1,% dirty trick for testing #1=empty + \expandafter\mult_interfaces_get_parameters_item + \orelse\if]#1% + \expandafter\gobbleoneargument + \else + \mult_interfaces_get_parameters_assign#1==\empty^^^^0004% + % \expandafter\mult_interfaces_get_parameters_item % saves skipping when at end + \fi#2} + +\def\mult_interfaces_get_parameters_error#1#2% #3% + {\mult_interfaces_get_parameters_error_indeed{#1}{#2}% + \gobbleoneargument} + +\def\mult_interfaces_get_parameters_error_indeed#1#2% + {\showassignerror{#2}{\the\inputlineno\space(#1)}} + +\def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004% + {\ifx\empty#1\empty + \expandafter\mult_interfaces_get_parameters_error + \orelse\ifx#3\empty + \expandafter\mult_interfaces_get_parameters_error + \else + \expandafter\mult_interfaces_def + \fi + \m_mult_interfaces_namespace{#1}{#2}% + \doubleexpandafter\mult_interfaces_get_parameters_item} + +\startinterface english + + % some 10% faster + + \let\mult_interfaces_get_parameters_error\undefined + + \def\mult_interfaces_get_parameters_error_one#1\csname#2#3\endcsname#4% + {\mult_interfaces_get_parameters_error_indeed{#2}{#3}\iftrue} + + \def\mult_interfaces_get_parameters_error_two#1\csname#2#3\endcsname#4% + {\mult_interfaces_get_parameters_error_indeed{#2}{#3}} + + \def\mult_interfaces_get_parameters_assign#1=#2=#3#4^^^^0004% + {\ifx\empty#1\empty + \mult_interfaces_get_parameters_error_one + \orelse\ifx#3\empty + \mult_interfaces_get_parameters_error_two + \else + \expandafter\def\csname\m_mult_interfaces_namespace#1\endcsname{#2}% + \fi + \doubleexpandafter\mult_interfaces_get_parameters_item} + +\stopinterface + +\newif\ifassignment + +\def\mult_check_for_assignment_indeed#1=#2#3^^^^0004% + {\if#2^^^^0003\assignmentfalse\else\assignmenttrue\fi} + +\def\mult_check_for_assignment_indeed_begin_#1=#2#3^^^^0004% + {\if#2^^^^0003} + +\def\mult_check_for_assignment#1% + {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=^^^^0003^^^^0003^^^^0004} + +% End of experimental code. + +\unexpanded\def\mult_interfaces_let #1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} +\unexpanded\def\mult_interfaces_lete#1#2{\expandafter\let \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname\empty} +\unexpanded\def\mult_interfaces_def #1#2{\expandafter\def \csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} +\unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} +\unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} +\unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1\ifcsname\k!prefix!#2\endcsname\csname\k!prefix!#2\endcsname\else#2\fi\endcsname} + +\startinterface english + + \unexpanded\def\mult_interfaces_let #1#2{\expandafter \let\csname#1#2\endcsname} + \unexpanded\def\mult_interfaces_lete#1#2{\expandafter \let\csname#1#2\endcsname\empty} + \unexpanded\def\mult_interfaces_def #1#2{\expandafter \def\csname#1#2\endcsname} + \unexpanded\def\mult_interfaces_edef#1#2{\expandafter\edef\csname#1#2\endcsname} + \unexpanded\def\mult_interfaces_gdef#1#2{\expandafter\gdef\csname#1#2\endcsname} + \unexpanded\def\mult_interfaces_xdef#1#2{\expandafter\xdef\csname#1#2\endcsname} + +\stopinterface + +% the commented detokenized variant that backtracks ... needs testing usage first +% +% \let\whatever\relax +% +% \definetest[oeps][bagger=\whatever] +% +% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par +% \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par +% +% slower: \def#3##1{\csname\ifcsname#1#2:##1\endcsname\expandafter\csstring\lastnamedcs\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}% + +%D pre-expansion can be a bit faster but handly any effect on a normal run so let's +%D go for saving some memory + +\def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter} + +\unexpanded\def\mult_interfaces_install_parameter_handler#1#2#3#4#5#6#7#8% inlining \csname*\endcsname is more efficient (#3 and #6 only) + {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing + \def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}% + \def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% + %\def#5##1##2{\ifx##1\relax\??empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ? + %\def#5##1##2{\ifx##1\relax\??empty\else#4##1{##2}\fi}% is {} needed around ##1 ? + \def#5##1##2{\ifx##1\relax^^^^0019\else#4##1{##2}\fi}% is {} needed around ##1 ? + \def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}% + \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack + \def#8##1{\begincsname#1#2:##1\endcsname}} + +\unexpanded\def\installparameterhandler#1#2% + {\normalexpanded + {\mult_interfaces_install_parameter_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname #2parameter\endcsname + \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter + \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter + \expandafter\noexpand\csname named#2parameter\endcsname + \expandafter\noexpand\csname detokenized#2parameter\endcsname + \expandafter\noexpand\csname direct#2parameter\endcsname}} % strict#2parameter is gone + +\unexpanded\def\mult_interfaces_install_root_parameter_handler#1#2#3% + {\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root + \def#3##1{\begincsname#1:##1\endcsname}} + +\unexpanded\def\installrootparameterhandler#1#2% + {\normalexpanded + {\mult_interfaces_install_root_parameter_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname + \expandafter\noexpand\csname root#2parameter\endcsname}} + +\unexpanded\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9% + {\ifx#2\relax\let#2\empty\fi + \def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used? + \def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% + %\def#5##1##2{\ifx##1\relax\else#4{##1}{##2}\fi}% + \def#5##1##2{\ifx##1\relax\else#4##1{##2}\fi}% + \def#6{#1#2:}% + \def#7##1{#1##1:}% + \def#8{\ifx#2\empty\else\ifcsname#1#2:\s!parent\endcsname\else\expandafter\let\csname#1#2:\s!parent\endcsname#1\fi\fi}% + \unexpanded\def#9##1{\expandafter\edef\csname#1##1:\s!parent\endcsname{#1#2}}} + +\unexpanded\def\installparameterhashhandler#1#2% + {\expandafter\let\csname#2namespace\endcsname#1% + \normalexpanded + {\mult_interfaces_install_parameter_hash_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname #2parameterhash\endcsname + \expandafter\noexpand\csname do#2parameterhash\endcsname % or : #2_parameter_hash + \expandafter\noexpand\csname do#2parentparameterhash\endcsname % or : #2_parent_parameter_hash + \expandafter\noexpand\csname current#2hash\endcsname + \expandafter\noexpand\csname named#2hash\endcsname + \expandafter\noexpand\csname check#2parent\endcsname + \expandafter\noexpand\csname chaintocurrent#2\endcsname}} + +%D In \MKIV\ we can probably use the english variant for all other languages too. + +% todo: inline the def/let + +\unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% + {\ifx#2\relax\let#2\empty\fi + \unexpanded\def#3{\mult_interfaces_def {#1#2:}}% ##1 {##2} (braces are mandate) + \unexpanded\def#4{\mult_interfaces_edef{#1#2:}}% ##1 {##2} (braces are mandate) + \unexpanded\def#5{\mult_interfaces_let {#1#2:}}% ##1 ##2 + \unexpanded\def#6{\mult_interfaces_lete{#1#2:}}}% ##1 + +\startinterface english + + \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% + {\ifx#2\relax\let#2\empty\fi + \unexpanded\def#3##1{\expandafter \def\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) + \unexpanded\def#4##1{\expandafter\edef\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) + \unexpanded\def#5##1{\expandafter \let\csname#1#2:##1\endcsname}% ##1 ##2 + \unexpanded\def#6##1{\expandafter \let\csname#1#2:##1\endcsname\empty}}% ##1 + +\stopinterface + +\unexpanded\def\installparametersethandler#1#2% + {\normalexpanded + {\mult_interfaces_install_parameter_set_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname set#2parameter\endcsname + \expandafter\noexpand\csname setexpanded#2parameter\endcsname + \expandafter\noexpand\csname let#2parameter\endcsname + \expandafter\noexpand\csname reset#2parameter\endcsname}} + +\let\dousecurrentstyleparameter\relax +\let\dousecurrentcolorparameter\relax + +\let\currentstyleparameter\empty +\let\currentcolorparameter\empty + +\unexpanded\def\mult_interfaces_install_style_and_color_handler#1#2#3#4% + {\unexpanded\def#2##1##2% style color + {\edef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline) + \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi + \edef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch) + \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}% + \unexpanded\def#3##1% style + {\edef\currentstyleparameter{#1{##1}}% this name is public + \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi}% + \unexpanded\def#4##1% color + {\edef\currentcolorparameter{#1{##1}}% this name is public + \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}} + +\unexpanded\def\installstyleandcolorhandler#1#2% + {\normalexpanded + {\mult_interfaces_install_style_and_color_handler + \expandafter\noexpand\csname #2parameter\endcsname + \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters + \expandafter\noexpand\csname use#2styleparameter\endcsname + \expandafter\noexpand\csname use#2colorparameter\endcsname}} + +\let\definehandlerparent\empty + +\def\mult_check_for_parent#1#2#3#4% + {\ifcsname#1#4:\s!parent\endcsname \else \ifx#4\empty \else + \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}% + \expandafter\edef\csname#1#4:\s!parent\endcsname{#2}% + \fi \fi} + +%def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\space\fi} +%def\getparentchain #1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi} +%def\getcurrentparentchain#1#2{\ifcsname#1#2:\s!chain\endcsname\csname#1#2:\s!chain\endcsname\fi} + +\def\mult_interfaces_chain#1#2{\ifcsname#1#2:\s!chain\endcsname\lastnamedcs\space\fi} +\def\getparentchain #1#2{\begincsname#1#2:\s!chain\endcsname} +\def\getcurrentparentchain#1#2{\begincsname#1#2:\s!chain\endcsname} + +\unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones + {\ifx#4\relax\let#4\empty\fi % see \defineregister + \unexpanded\def#2{\dotripleempty#5}% + \newtoks#6% + \newtoks#7% + \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child] + {\let#9#4% + \edef#4{##1}% + \ifthirdargument + \the#6% predefine + \edef#8{##2}% + \mult_check_for_parent{#1}{#3}#4#8% + \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% + \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% + \mult_interfaces_get_parameters{#1#4:}[##3]% + \orelse\ifsecondargument + \the#6% predefine + \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##2}=^^^^0003^^^^0003^^^^0004% + \edef#8{##2}% + \mult_check_for_parent{#1}{#3}#4#8% + \expandafter\edef\csname#1#4:\s!chain\endcsname{\mult_interfaces_chain#1{##2}##1}% + \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% + \else + \let#8\empty + \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% + \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% + \mult_interfaces_get_parameters{#1#4:}[##2]% + \fi + \else + \the#6% predefine + \let#8\empty + \expandafter\edef\csname#1#4:\s!chain\endcsname{##1}% + \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% + \fi + \the#7% + \let#4#9}} + +\unexpanded\def\installdefinehandler#1#2#3% + {\normalexpanded + {\mult_interfaces_install_define_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname define#2\endcsname + {\noexpand#3}% root + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname define_#2\endcsname % semi-public + \expandafter\noexpand\csname everypreset#2\endcsname + \expandafter\noexpand\csname everydefine#2\endcsname + \expandafter\noexpand\csname current#2parent\endcsname + \expandafter\noexpand\csname saved_defined_#2\endcsname}} + +\unexpanded\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8#9% + {\ifx#3\relax\let#3\empty\fi + \unexpanded\def#2{\dodoubleempty#4}% + \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it + \newtoks#5% + \newtoks#8% + \unexpanded\def#4[##1][##2]% maybe helper + {\let#7#3% + \ifsecondargument + \def#9####1% we will have a simple one as well + {\edef#3{####1}% + \mult_interfaces_get_parameters{#1#3:}[##2]% + \the#5}% + \processcommalist[##1]#9% + \else + \let#3\empty + \mult_interfaces_get_parameters{#1:}[##1]% + \the#5% + \fi + \let#3#7% + \the#8}} + +\unexpanded\def\installsetuphandler#1#2% + {\normalexpanded + {\mult_interfaces_install_setup_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname setup#2\endcsname + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname setup_#2\endcsname % semi-public + \expandafter\noexpand\csname everysetup#2\endcsname + \expandafter\noexpand\csname setupcurrent#2\endcsname + \expandafter\noexpand\csname saved_setup_current#2\endcsname + \expandafter\noexpand\csname everysetup#2root\endcsname + \expandafter\noexpand\csname nested_setup_current#2\endcsname}} + +\let\doingrootsetupnamed\plusone % \setuplayout[name][key=value] +\let\doingrootsetuproot \plustwo % \setuplayout [key=value] +\let\doingrootsetnamed \plusthree % \setuplayout[name] +\let\doingrootsetroot \plusfour % \setuplayout + +\unexpanded\def\mult_interfaces_install_switch_setup_handler_a#1#2#3#4#5% + {\ifx#3\relax\let#3\empty\fi + \unexpanded\def#2{\dodoubleempty#4}% + \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}} + +\unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9% + {\newtoks#5% + \newconstant#2% + \newtoks#8% + \newtoks#9% + \ifx#6\relax\let#6\empty\fi + \unexpanded\def#4[##1][##2]% maybe helper + {\ifsecondargument % no commalist here + % \setuplayout[whatever][key=value] + \let#7#3% + \let#6#3% + \edef#3{##1}% + #2\doingrootsetupnamed + \mult_interfaces_get_parameters{#1#3:}[##2]% + \the#5% + \ifx#3#6\the#8\fi % only switchsetups if previous == current + \let#3#7% + \orelse\iffirstargument + % \mult_check_for_assignment{##1}% + \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004% + % \setuplayout[whatever] + \let#6#3% % previous becomes current + \edef#3{##1}% this will catch reset so one needs to test for it + #2\doingrootsetnamed + \the#5% % we can check for previous vs current + \the#8% switchsetups + \else + % \setuplayout[key=value] + \let#7#3% + \let#6#3% + \let#3\empty + #2\doingrootsetuproot + \mult_interfaces_get_parameters{#1:}[##1]% + \the#5% + \the#8% switchsetups + \let#3#7% + \fi + \else + % \setuplayout + \let#6#3% % previous becomes current + \let#3\empty % current becomes empty + #2\doingrootsetroot + \the#5% + \the#8% switchsetups + \fi + #2\zerocount % mode is always zero at the end + \the#9}} + +\unexpanded\def\installswitchsetuphandler#1#2% + {\normalexpanded + {\mult_interfaces_install_switch_setup_handler_a + {\noexpand#1}% \??aa + \expandafter\noexpand\csname setup#2\endcsname + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname setup_#2\endcsname % semi-public + \expandafter\noexpand\csname setupcurrent#2\endcsname + \mult_interfaces_install_switch_setup_handler_b + {\noexpand#1}% \??aa + \expandafter\noexpand\csname #2setupmode\endcsname + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname setup_#2\endcsname % semi-public + \expandafter\noexpand\csname everysetup#2\endcsname + \expandafter\noexpand\csname previous#2\endcsname + \expandafter\noexpand\csname saved_setup_current#2\endcsname + \expandafter\noexpand\csname everyswitch#2\endcsname + \expandafter\noexpand\csname everysetup#2root\endcsname}} + +\unexpanded\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8#9% + {\ifx#3\relax\let#3\empty\fi + \unexpanded\def#2{\dotripleempty#4}% + \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% + \newtoks#5% + \def#4[##1][##2][##3]% + {\let#8#3% + \ifthirdargument + \def#9####1% + {\edef#3{####1}% + \expandafter\def\csname#1#3:\s!parent\endcsname{#1##2}% + \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent + \the#5}% + \processcommalist[##1]#9% + \orelse\ifsecondargument + \def#9####1% + {\edef#3{####1}% + #7% checks parent and sets if needed + \mult_interfaces_get_parameters{#1#3:}[##2]% + \the#5}% + \processcommalist[##1]#9% + \else + \let#3\empty + \mult_interfaces_get_parameters{#1:}[##1]% + \the#5% + \fi + \let#3#8}} + +\unexpanded\def\installautosetuphandler#1#2% + {\normalexpanded + {\mult_interfaces_install_auto_setup_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname setup#2\endcsname + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname setup_#2\endcsname % semi-public + \expandafter\noexpand\csname everysetup#2\endcsname + \expandafter\noexpand\csname setupcurrent#2\endcsname + \expandafter\noexpand\csname check#2parent\endcsname + \expandafter\noexpand\csname saved_setup_current#2\endcsname + \expandafter\noexpand\csname nested_setup_current#2\endcsname}} + +\unexpanded\def\installbasicparameterhandler#1#2% + {\installparameterhandler {#1}{#2}% + \installparameterhashhandler{#1}{#2}% + \installparametersethandler {#1}{#2}% + \installrootparameterhandler{#1}{#2}} + +\unexpanded\def\installbasicautosetuphandler#1#2#3% \??self name \??parent (can be \??self) + {\installbasicparameterhandler{#1}{#2}% + \installautosetuphandler {#1}{#2}} + +\unexpanded\def\installstylisticautosetuphandler#1#2#3% \??self name \??parent (can be \??self) + {\installbasicparameterhandler{#1}{#2}% + \installautosetuphandler {#1}{#2}% + \installstyleandcolorhandler {#1}{#2}} + +\unexpanded\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self) + {\installbasicparameterhandler{#1}{#2}% + \installdefinehandler {#1}{#2}{#3}% + \installsetuphandler {#1}{#2}% + \installstyleandcolorhandler {#1}{#2}} + +\unexpanded\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self) + {\installbasicparameterhandler{#1}{#2}% + \installdefinehandler {#1}{#2}{#3}% + \installswitchsetuphandler {#1}{#2}% + \installstyleandcolorhandler {#1}{#2}} + +\unexpanded\def\installautocommandhandler#1#2#3% automatically defined cloned setups + {\installbasicparameterhandler{#1}{#2}% + \installdefinehandler {#1}{#2}{#3}% + \installautosetuphandler {#1}{#2}% + \installstyleandcolorhandler {#1}{#2}} + +\unexpanded\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining + {\installbasicparameterhandler{#1}{#2}% + \installsetuphandler {#1}{#2}% + \installstyleandcolorhandler {#1}{#2}} + +%D Many mechanisms have some kind of inheritance in place, and these are the +%D speed||critical ones. Therefore there is no reason to stick to \type {\@@xxkey} +%D for the sake of performance. For this reason we also provide a direct variant. +%D This permits a more consistent treatment of namespaces. A \type +%D {\whateverparameter} call is three times slower and a \type +%D {\directwhateverparameter} call two times but for some 100K expansions we only +%D loose some .1 second which is neglectable given the small amount of expansions in +%D real runs. + +%D We don't need colons for such simple cases. + +\unexpanded\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5% +%%{\def#3##1{\csname\ifcsname#1##1\endcsname#1##1\else\s!empty\fi\endcsname}% + {\def#3##1{\begincsname#1##1\endcsname}% + \def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}% + % \def#4##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}% + \def#5##1{\begincsname#1##1\endcsname}} + +\unexpanded\def\installdirectparameterhandler#1#2% + {\normalexpanded + {\mult_interfaces_install_direct_parameter_handler + {\noexpand#1}% + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname #2parameter\endcsname + \expandafter\noexpand\csname detokenized#2parameter\endcsname + \expandafter\noexpand\csname direct#2parameter\endcsname}} + +\unexpanded\def\mult_interfaces_install_direct_setup_handler#1#2#3#4#5% + {\unexpanded\def#2{\dosingleempty#3}% + \newtoks#5% + \def#3[##1]{\mult_interfaces_get_parameters#1[##1]\the#5}% + \def#4{\mult_interfaces_get_parameters#1}} + +\unexpanded\def\installdirectsetuphandler#1#2% + {\normalexpanded + {\mult_interfaces_install_direct_setup_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname setup#2\endcsname + \expandafter\noexpand\csname setup_#2\endcsname % semi-public + \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency) + \expandafter\noexpand\csname everysetup#2\endcsname}} + +\unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% + {\unexpanded\def#2{\mult_interfaces_def #1}% + \unexpanded\def#3{\mult_interfaces_edef#1}% + \unexpanded\def#4{\mult_interfaces_let #1}% + \unexpanded\def#5{\mult_interfaces_let #1\empty}}% + +\startinterface english + + \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% + {\unexpanded\def#2##1{\expandafter \def\csname#1##1\endcsname}% + \unexpanded\def#3##1{\expandafter\edef\csname#1##1\endcsname}% + \unexpanded\def#4##1{\expandafter \let\csname#1##1\endcsname}% + \unexpanded\def#5##1{\expandafter \let\csname#1##1\endcsname\empty}}% + +\stopinterface + +\unexpanded\def\installdirectparametersethandler#1#2% + {\normalexpanded + {\mult_interfaces_install_direct_parameter_set_handler + {\noexpand#1}% \??aa + \expandafter\noexpand\csname set#2parameter\endcsname + \expandafter\noexpand\csname setexpanded#2parameter\endcsname + \expandafter\noexpand\csname let#2parameter\endcsname + \expandafter\noexpand\csname reset#2parameter\endcsname}} + +\let\installdirectstyleandcolorhandler\installstyleandcolorhandler + +\unexpanded\def\installdirectcommandhandler#1#2% + {\installdirectparameterhandler {#1}{#2}% + \installdirectsetuphandler {#1}{#2}% + \installdirectparametersethandler {#1}{#2}% + \installdirectstyleandcolorhandler{#1}{#2}} + +\unexpanded\def\installsetuponlycommandhandler#1#2% + {\installdirectparameterhandler{#1}{#2}% + \installdirectsetuphandler {#1}{#2}% + }% maybe \installdirectparametersethandler {#1}{#2}% + +% Experiment: + +% \installcorenamespace {one} +% \installcorenamespace {two} +% +% \installcommandhandler \??one {one} \??one +% \installcommandhandler \??two {two} \??two +% +% \defineone[test] \setupone[test][alpha=first] +% \definetwo[test] \setuptwo[test][beta=second] +% +% \protect +% +% \def\currentone{test} +% \def\currenttwo{test} +% +% \relateparameterhandlers {two} {test} {one} {test} +% +% yes:\oneparameter{alpha}\par +% nop:\oneparameter{beta}\par +% yes:\twoparameter{alpha}\par +% yes:\twoparameter{beta}\par + +\unexpanded\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance} + {\expandafter\edef\csname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}} + +\unexpanded\def\relateparameterhandlersbyns#1#2#3#4% {from} {instance} {to} {instance} + {\expandafter\edef\csname#1#2:\s!parent\endcsname{#3#4}} + +%D Here is another experiment: + +\unexpanded\def\installactionhandler#1% + {\normalexpanded + {\mult_interfaces_install_action_handler + {#1}% + \expandafter\noexpand\csname current#1\endcsname + \expandafter\noexpand\csname setupcurrent#1\endcsname + \expandafter\noexpand\csname #1_action\endcsname}} + +% \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4% +% {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}% +% \unexpanded\def#4[##1][##2]% +% {\begingroup +% \ifsecondargument +% \edef#2{##1}% +% #3[##2]% +% \else\iffirstargument +% \doifelseassignment{##1} +% {\let#2\empty +% #3[##1]}% +% {\edef#2{##1}}% +% \else +% \let#2\empty +% \fi\fi +% \directsetup{handler:action:#1}% +% \endgroup}} + +\unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4% + {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}% + \unexpanded\def#4[##1][##2]% + {\begingroup + \ifsecondargument + \edef#2{##1}% + #3[##2]% + \orelse\iffirstargument + \ifcondition\expandafter\mult_check_for_assignment_indeed_begin_\detokenize{##1}=^^^^0003^^^^0003^^^^0004% + \edef#2{##1}% + \else + \let#2\empty + #3[##1]% + \fi + \else + \let#2\empty + \fi + \directsetup{handler:action:#1}% + \endgroup}} + +% First we had, in tune with the regular system variables: +% +% \starttyping +% \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}} +% \stoptyping +% +% The following variant is nicer and in principle faster but that gets unnoticed +% unless lots of expansion happens. Also, we can use long tags but the internal +% expansion will be relatively small (and unlikely more than 4 characters). For +% instance, \??xx used to expand to @@xx but now becomes for instance 123::. This +% is one character more but in quite some cases we had : after such a tag in the +% old situation. In the new situation we create more namespaces and don't need that +% : any more, so we end up with on the average the same amount of tokens and +% definitely less when we consider cases like \??xx:\c!align: which now is just +% \??somealign and therefore has length 5 now (instead of 4+1+5+1=10). +% +% Eventualy we will have a verbose \blablanamespace and the difference between core +% and regular can go ... after all, \xxxparameter can already clash between the two +% prefix groups .. if users use this mechanism a lot they should use verbose names +% anyway (the old two character names were mostly an optimization as they also +% expanded to these characters). + +% todo: register namespaces at lua end for logging and reverse resolve +% todo: move this to syst-ini so that we can use it real early + +\newcount\c_mult_interfaces_n_of_namespaces + +%def\v_interfaces_prefix_template{\number \c_mult_interfaces_n_of_namespaces>} +%def\v_interfaces_prefix_template{\characters\c_mult_interfaces_n_of_namespaces>} + +%def\v_interfaces_prefix_template % consistently %03i> +% {\ifnum\c_mult_interfaces_n_of_namespaces<\plusten00\else\ifnum\c_mult_interfaces_n_of_namespaces<\plushundred0\fi\fi +% \number\c_mult_interfaces_n_of_namespaces>} + +\def\v_interfaces_prefix_template + {\number\c_mult_interfaces_n_of_namespaces>} + +\unexpanded\def\installnamespace#1% for modules and users + {\ifcsname ????#1\endcsname + \writestatus\m!system{duplicate user namespace '#1'}\wait + \else + \global\advance\c_mult_interfaces_n_of_namespaces\plusone + \expandafter\edef\csname ????#1\endcsname{\v_interfaces_prefix_template}% + \fi} + +\unexpanded\def\installcorenamespace#1% + {\ifcsname ??#1\endcsname + \writestatus\m!system{duplicate core namespace '#1'}\wait + \else + \global\advance\c_mult_interfaces_n_of_namespaces\plusone + \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template}% + \clf_registernamespace\c_mult_interfaces_n_of_namespaces{#1}% + \fi} + +\def\mult_interfaces_get_parameters_error_indeed#1#2% + {\clf_showassignerror{#1}{#2}\inputlineno} % no longer \waitonfatalerror + +% We install two core namespaces here, as we want nice error messages. Maybe +% we will reserve the first 9. + +\installcorenamespace{fontinstanceready} +\installcorenamespace{fontinstancebasic} +\installcorenamespace{fontinstanceclass} + +%D The next one is handy for local assignments. + +\installcorenamespace{dummy} + +\letvalue\??dummy\empty + + \def\dummyparameter #1{\begincsname\??dummy#1\endcsname} + \def\directdummyparameter #1{\begincsname\??dummy#1\endcsname} +\unexpanded\def\setdummyparameter #1{\expandafter\def\csname\??dummy#1\endcsname} +\unexpanded\def\setexpandeddummyparameter#1{\expandafter\edef\csname\??dummy#1\endcsname} +\unexpanded\def\letdummyparameter #1{\expandafter\let\csname\??dummy#1\endcsname} + +% \unexpanded\def\getdummyparameters +% {\mult_interfaces_get_parameters\??dummy} + +\unexpanded\def\getdummyparameters[#1% + {\if\noexpand#1]% + \expandafter\gobbleoneargument + \else + \let\m_mult_interfaces_namespace\??dummy + \expandafter\mult_interfaces_get_parameters_indeed + \fi#1} + +\mult_interfaces_install_style_and_color_handler + \directdummyparameter + \usedummystyleandcolor + \usedummystyleparameter + \usedummycolorparameter + +% Maybe a \definecorenamespace[name][directparameter,directsetup][parent] but we +% don't gain much. Actually we might just inline all definitions. + +% \enabletrackers[interfaces.namespaces,context.flush] +% +% \definenamespace +% [xy] +% [type=module, +% comment=test module, +% version=1, +% name=test, +% style=yes, +% command=yes, +% setup=list, +% set=yes, +% parent=xy] +% +% \unprotect +% \getparameters +% [\????xy] +% [text=] +% \protect +% +% \definetest[one] +% +% \starttext +% +% “\testparameter{text}” +% +% \setuptest[text=foo] +% +% “\testparameter{text}” +% +% \setuptest[one][text=bar] +% +% “\testparameter{text}” +% +% \stoptext +% +% This is a user (module) command: + +\unexpanded\def\definenamespace + {\dodoubleargument\mult_interfaces_define_name_space} + +\def\mult_interfaces_define_name_space[#1][#2]% namespace settings + {\clf_definenamespace{#1}{#2}} + +\def\listnamespaces + {\clf_listnamespaces} + +%D Helper: +%D +%D \starttyping +%D \showparentchain{@@am}{left} +%D \stoptyping + +\unexpanded\def\showparentchain#1#2% + {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}} + +% \def\mult_interfaces_show_parent_chain#1% +% {#1 => % +% \ifcsname#1:\s!parent\endcsname +% \expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname +% \fi} + +\def\mult_interfaces_show_parent_chain#1% + {#1 => % + \ifcsname#1:\s!parent\endcsname + %\expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname + \expandafter\mult_interfaces_show_parent_chain\lastnamedcs + \fi} + +%D Another helper (needs to be applied): + +\unexpanded\def\doifelsecommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifcommandhandlerelse\doifelsecommandhandler + +\unexpanded\def\doifcommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotcommandhandler#1#2% namespace name + {\ifcsname#1#2:\s!parent\endcsname + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\let\doifcommandhandlerelse\doifelsecommandhandler + +% another set of (fast) helpers (grep for usage): + +\def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \v!yy + {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3} + +\def\mult_aux_expand_namespace_parameter#1#2% \cs \v!yy + {#1\endcsname#1\else#2\fi\endcsname} + +\def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy + {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname} + +\def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname + {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}} + +\def\syst_helpers_expand_checked_value#1#2% + {#1\endcsname#1\else#2\fi\endcsname} + +%D Conventions: +%D +%D \starttyping +%D \newcount \c_class_whatever +%D \newconditional \c_class_whatever +%D \newconstant \c_class_whatever +%D \newdimen \d_class_whatever +%D \newskip \s_class_whatever +%D \newmuskip \s_class_whatever +%D \newbox \b_class_whatever +%D \newtoks \t_class_whatever +%D +%D \edef\p_class_whatever{\classparameter\c!whatever} +%D \edef\m_class_whatever{whatever} +%D \stoptyping + +% experiment: in principle this is faster but not that noticeable as we don't do that +% many assignments and mechanism that do are also slow; the advantage is mostly nicer +% in tracing + +\def\s!simple{simple} +\def\s!single{single} +\def\s!double{double} +\def\s!triple{triple} + +\let\c_mult_set\relax + +\unexpanded\def\mult_interfaces_install_definition_set#1#2#3#4#5#6#7% + {\newcount#3% + \let#6\empty + \unexpanded\def#2% + {\expandafter\let\expandafter\c_mult_set\csname #1_t_#6\endcsname + \ifx\c_mult_set\relax + \expandafter\newtoks\c_mult_set + \expandafter\let\csname #1_t_#6\endcsname\c_mult_set + \fi} + \unexpanded\def#4##1% + {\pushmacro#6% + \advance#3\plusone + \edef#6{##1}% + \unprotect}% + \unexpanded\def#5% + {\protect + \advance#3\minusone + \popmacro#6}% + \unexpanded\def#7##1% + {\edef#6{##1}% + #2% + \the\c_mult_set\relax}} + +\unexpanded\def\installdefinitionset#1#2% + {\normalexpanded + {\mult_interfaces_install_definition_set + {\noexpand#1}% \??aa + \expandafter\noexpand\csname set_#2_toks\endcsname + \expandafter\noexpand\csname #2_nesting_depth\endcsname + \expandafter\noexpand\csname push#2\endcsname + \expandafter\noexpand\csname pop#2\endcsname + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname use#2\endcsname}} + +\unexpanded\def\mult_interfaces_install_definition_set_member#1#2#3#4#5#6#7#8#9% no everysetups etc + {\let#5#2% + \unexpanded\def#2% + {\ifcase#4\relax\expandafter#5\else\expandafter#6\fi}% + \unexpanded\def#6% + {\dodoubleempty#7}% + \unexpanded\def#7[##1][##2]% + {\ifsecondargument + %#3\c_mult_set\expandafter{\the\c_mult_set#9[##1][##2]}% + #3\toksapp\c_mult_set{#9[##1][##2]}% + \orelse\iffirstargument + %#3\c_mult_set\expandafter{\the\c_mult_set#8[##1]}% + #3\toksapp\c_mult_set{#8[##1]}% + \fi}} + +\unexpanded\def\installdefinitionsetmember#1#2#3#4% + {\normalexpanded + {\mult_interfaces_install_definition_set_member + {\noexpand#3}% \??aa + \expandafter\noexpand\csname setup#4\endcsname + \expandafter\noexpand\csname set_#2_toks\endcsname + \expandafter\noexpand\csname #2_nesting_depth\endcsname + \expandafter\noexpand\csname normal_setup_#4\endcsname + \expandafter\noexpand\csname delayed_setup_#4\endcsname + \expandafter\noexpand\csname do_delayed_setup_#4\endcsname + \expandafter\noexpand\csname setup#4_\s!single\endcsname + \expandafter\noexpand\csname setup#4_\s!double\endcsname}} + +%D Another experiment: + +\unexpanded\def\mult_interfaces_install_parent_injector#1#2#3#4% + {\unexpanded\def#4##1% + {\ifx#3\empty + \expandafter\def\csname#1#2:\s!parent\endcsname{#1##1}% + \fi}} + +\unexpanded\def\installparentinjector#1#2% + {\normalexpanded{\mult_interfaces_install_parent_injector + {\noexpand#1}% + \expandafter\noexpand\csname current#2\endcsname + \expandafter\noexpand\csname current#2parent\endcsname + \expandafter\noexpand\csname inject#2parent\endcsname}} + +% Faster but not used that much to make a dent in performance. But, because it's +% cleaner anyway and also gives less tracing, we apply it a few times. + +\unexpanded\def\syst_helpers_install_macro_stack#1#2#3% + {\xdef\m_syst_helpers_push_macro{\csstring#1}% + \ifcsname#3\m_syst_helpers_push_macro\endcsname\else + \expandafter\newcount\csname#3\m_syst_helpers_push_macro\endcsname + \expandafter\edef\csname push_macro_\m_syst_helpers_push_macro\endcsname + {\noexpand\expandafter\glet + \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname + \noexpand#1% + \global\advance\csname#3\m_syst_helpers_push_macro\endcsname\plusone}% + \expandafter\edef\csname pop_macro_\m_syst_helpers_push_macro\endcsname + {\global\advance\csname#3\m_syst_helpers_push_macro\endcsname\minusone + \noexpand\expandafter#2% + \noexpand\expandafter\noexpand#1% + \noexpand\csname\m_syst_helpers_push_macro\noexpand\the\csname#3\m_syst_helpers_push_macro\endcsname\endcsname}% + \fi} + +\unexpanded\def\installmacrostack #1{\syst_helpers_install_macro_stack#1\let \??localpushedmacro } +\unexpanded\def\installglobalmacrostack#1{\syst_helpers_install_macro_stack#1\glet\??globalpushedmacro} + +% \unprotect +% +% \installcorenamespace {test} \installcommandhandler \??test {test} \??test +% \unexpanded\def\TestMeA[#1]% +% {\edef\currenttest{#1} +% \edef\p_before{\testparameter\c!before}% +% \ifx\p_before\empty \relax \else \relax \fi} +% \unexpanded\def\TestMeB[#1]% +% {\edef\currenttest{#1} +% \doifelsenothing{\testparameter\c!before}\relax\relax} +% \unexpanded\def\TestMeC[#1]% +% {\edef\currenttest{#1} +% \expandafter\expandafter\expandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi} +% \unexpanded\def\TestMeD[#1]% +% {\edef\currenttest{#1} +% \doubleexpandafter\ifx\testparameter\c!before\empty \relax \else \relax \fi} +% +% \protect +% +% \starttext +% \definetest[foo] \definetest[bar][foo] \setuptest[bar][before=indeed] +% \testfeatureonce{100000}{\TestMeA[bar]} A:\elapsedtime \par % 0.502 +% \testfeatureonce{100000}{\TestMeB[bar]} B:\elapsedtime \par % 0.530 +% \testfeatureonce{100000}{\TestMeC[bar]} C:\elapsedtime \par % 0.487 +% \testfeatureonce{100000}{\TestMeD[bar]} D:\elapsedtime \par % 0.493 +% \stoptext + +% There is no real demand for this ... even if this is two to three times as fast we +% only gain a few milliseconds: +% +% \starttyping +% \unexpanded\def\foo#1{[foo:#1]} +% +% \installcommalistprocessor {foo} \foo +% \installcommalistprocessorcommand \processfoolist \foo +% +% \infofont +% +% \commalistprocessor{foo}[a,b,c,{x,y,z},d]\par +% \processfoolist[a, b, c, {x,y,z}, d]\par +% \processcommalist[{x,y,z}]\foo\blank +% +% \commalistprocessor{foo}[{x,y,z},a]\par +% \commalistprocessor{foo}[{x,y,z}]\par +% \processfoolist[{x,y,z},a]\par +% \processfoolist[{x,y,z}]\par +% \processcommalist[{x,y,z}]\foo\blank +% +% \unexpanded\def\foo#1{} +% +% \testfeatureonce{400000}{\processfoolist [fixed,middle,bar]} \elapsedtime\quad +%%\testfeatureonce{400000}{\commalistprocessor{foo}[fixed,middle,bar]} \elapsedtime\quad +% \testfeatureonce{400000}{\processcommalist [fixed,middle,bar]\foo} \elapsedtime\quad +% \stoptyping +% +% For instance the luatex manual only has some 3000 calls. But I keep this around as one +% never knows when we might need it. + +\installcorenamespace{commalistprocessor} +\installcorenamespace{commalistprocessorwrap} +\installcorenamespace{commalistprocessorfirst} +\installcorenamespace{commalistprocessornext} +\installcorenamespace{commalistprocessoraction} + +\unexpanded\def\installcommalistprocessor#1#2% 5 macro names overhead + {\unexpanded\expandafter\edef\csname\??commalistprocessor#1\endcsname[% + % {\noexpand\futureexpandis]% + % \noexpand\gobbleoneargument + % \csname\??commalistprocessorpickup#1\endcsname} + %\unexpanded\expandafter\edef\csname\??commalistprocessorpickup#1\endcsname + {\csname\??commalistprocessorwrap#1\endcsname\relax}% \relax preserves {} + \unexpanded\expandafter\edef\csname\??commalistprocessorwrap#1\endcsname##1]% + {\csname\??commalistprocessorfirst#1\endcsname##1,]} + \unexpanded\expandafter\edef\csname\??commalistprocessorfirst#1\endcsname\relax + {\csname\??commalistprocessornext#1\endcsname}% + \unexpanded\expandafter\edef\csname\??commalistprocessornext#1\endcsname + {\noexpand\futureexpandis]% + \noexpand\gobbleoneargument + \csname\??commalistprocessoraction#1\endcsname} + \unexpanded\expandafter\edef\csname\??commalistprocessoraction#1\endcsname##1,% + {\noexpand#2{##1}% + \csname\??commalistprocessornext#1\endcsname}} + +\unexpanded\def\installcommalistprocessorcommand#1#2% \processor \action + {\edef\p_name{\csstring#2}% + \installcommalistprocessor\p_name{#2}% + \expandafter\let\expandafter#1\csname\??commalistprocessor\p_name\endcsname} + +\unexpanded\def\commalistprocessor#1{\csname\??commalistprocessor#1\endcsname} + +\protect \endinput diff --git a/tex/context/base/mkiv/mult-def.lua b/tex/context/base/mkiv/mult-def.lua index 5222ea84f..bce5f9d83 100644 --- a/tex/context/base/mkiv/mult-def.lua +++ b/tex/context/base/mkiv/mult-def.lua @@ -9560,6 +9560,10 @@ return { ["en"]="order", ["nl"]="volgorde", }, + ["anchoring"]={ + ["en"]="anchoring", + ["nl"]="verankering", + }, ["orientation"]={ ["cs"]="orientation", ["de"]="orientation", diff --git a/tex/context/base/mkiv/mult-low.lua b/tex/context/base/mkiv/mult-low.lua index 846380027..540b1cfba 100644 --- a/tex/context/base/mkiv/mult-low.lua +++ b/tex/context/base/mkiv/mult-low.lua @@ -41,7 +41,7 @@ return { "bgroup", "egroup", "endline", -- - "conditionaltrue", "conditionalfalse", + "conditionaltrue", "conditionalfalse", "quitcondition", -- "attributeunsetvalue", -- diff --git a/tex/context/base/mkiv/mult-prm.lua b/tex/context/base/mkiv/mult-prm.lua index 76c357e2e..1f0f91311 100644 --- a/tex/context/base/mkiv/mult-prm.lua +++ b/tex/context/base/mkiv/mult-prm.lua @@ -25,8 +25,6 @@ return { "fontcharht", "fontcharic", "fontcharwd", - "futureexpand", - "futureexpandis", "glueexpr", "glueshrink", "glueshrinkorder", @@ -221,6 +219,7 @@ return { "Uunderdelimiter", "Uvextensible", "adjustspacing", + "aftergrouped", "alignmark", "aligntab", "attribute", @@ -232,6 +231,7 @@ return { "boundary", "boxdirection", "boxorientation", + "boxtotal", "boxxmove", "boxxoffset", "boxymove", @@ -258,6 +258,9 @@ return { "fontid", "formatname", "frozen", + "futureexpand", + "futureexpandis", + "futureexpandisap", "gleaders", "glet", "glyphdatafield", @@ -328,7 +331,6 @@ return { "mathsurroundmode", "mathsurroundskip", "noboundary", - "noexpand", "nohrule", "nokerns", "noligs", @@ -676,6 +678,7 @@ return { "muskipdef", "newlinechar", "noalign", + "noexpand", "noindent", "nolimits", "nonscript", diff --git a/tex/context/base/mkiv/mult-sys.mkiv b/tex/context/base/mkiv/mult-sys.mkiv index bd8fc80ff..14619316e 100644 --- a/tex/context/base/mkiv/mult-sys.mkiv +++ b/tex/context/base/mkiv/mult-sys.mkiv @@ -367,6 +367,7 @@ \definesystemconstant {marker} \definesystemconstant {kernpairs} \definesystemconstant {mixedcolumn} +\definesystemconstant {orientation} \definesystemconstant {ampersand} diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index 0764ee7e3..d60727eee 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -231,163 +231,163 @@ if not nuts.has_dimensions then end -local getfield = direct.getfield -local setfield = direct.setfield - -nuts.getfield = getfield -nuts.setfield = setfield - -nuts.getnext = direct.getnext -nuts.setnext = direct.setnext - -nuts.getid = direct.getid - -nuts.getprev = direct.getprev -nuts.setprev = direct.setprev - -local get_attribute = direct.get_attribute -local set_attribute = direct.set_attribute -local unset_attribute = direct.unset_attribute - -nuts.getattr = get_attribute -nuts.setattr = set_attribute -nuts.takeattr = unset_attribute -- ? - -nuts.is_zero_glue = direct.is_zero_glue -nuts.effective_glue = direct.effective_glue - -nuts.getglue = direct.getglue -nuts.setglue = direct.setglue -nuts.getboxglue = direct.getglue -nuts.setboxglue = direct.setglue - -nuts.getdisc = direct.getdisc -nuts.setdisc = direct.setdisc -nuts.getdiscretionary = direct.getdisc -nuts.setdiscretionary = direct.setdisc - -nuts.getpre = direct.getpre -nuts.setpre = direct.setpre -nuts.getpost = direct.getpost -nuts.setpost = direct.setpost -nuts.getreplace = direct.getreplace -nuts.setreplace = direct.setreplace - -local getdata = direct.getdata -local setdata = direct.setdata - -nuts.getdata = getdata -nuts.setdata = setdata -nuts.getvalue = getdata -nuts.setvalue = setdata - -nuts.getexpansion = direct.getexpansion -nuts.setexpansion = direct.setexpansion - -nuts.getwhd = direct.getwhd -nuts.setwhd = direct.setwhd -nuts.getwidth = direct.getwidth -nuts.setwidth = direct.setwidth -nuts.getheight = direct.getheight -nuts.setheight = direct.setheight -nuts.getdepth = direct.getdepth -nuts.setdepth = direct.setdepth -nuts.getshift = direct.getshift -nuts.setshift = direct.setshift +local getfield = direct.getfield +local setfield = direct.setfield + +nuts.getfield = getfield +nuts.setfield = setfield + +nuts.getnext = direct.getnext +nuts.setnext = direct.setnext + +nuts.getid = direct.getid + +nuts.getprev = direct.getprev +nuts.setprev = direct.setprev + +local get_attribute = direct.get_attribute +local set_attribute = direct.set_attribute +local unset_attribute = direct.unset_attribute + +nuts.getattr = get_attribute +nuts.setattr = set_attribute +nuts.takeattr = unset_attribute -- ? + +nuts.is_zero_glue = direct.is_zero_glue +nuts.effective_glue = direct.effective_glue + +nuts.getglue = direct.getglue +nuts.setglue = direct.setglue +nuts.getboxglue = direct.getglue +nuts.setboxglue = direct.setglue + +nuts.getdisc = direct.getdisc +nuts.setdisc = direct.setdisc +nuts.getdiscretionary = direct.getdisc +nuts.setdiscretionary = direct.setdisc + +nuts.getpre = direct.getpre +nuts.setpre = direct.setpre +nuts.getpost = direct.getpost +nuts.setpost = direct.setpost +nuts.getreplace = direct.getreplace +nuts.setreplace = direct.setreplace + +local getdata = direct.getdata +local setdata = direct.setdata + +nuts.getdata = getdata +nuts.setdata = setdata +nuts.getvalue = getdata +nuts.setvalue = setdata + +nuts.getexpansion = direct.getexpansion +nuts.setexpansion = direct.setexpansion + +nuts.getwhd = direct.getwhd +nuts.setwhd = direct.setwhd +nuts.getwidth = direct.getwidth +nuts.setwidth = direct.setwidth +nuts.getheight = direct.getheight +nuts.setheight = direct.setheight +nuts.getdepth = direct.getdepth +nuts.setdepth = direct.setdepth +nuts.getshift = direct.getshift +nuts.setshift = direct.setshift -- lmtx compatibility -nuts.getorientation = direct.getorientation or function() end -nuts.setorientation = direct.setorientation or function() end +nuts.getorientation = direct.getorientation or function() end +nuts.setorientation = direct.setorientation or function() end -nuts.getglyphdata = direct.getglyphdata or get_attribute -nuts.setglyphdata = direct.setglyphdata or function(n,d) set_attribute(n,0,d) end +nuts.getglyphdata = direct.getglyphdata or get_attribute +nuts.setglyphdata = direct.setglyphdata or function(n,d) set_attribute(n,0,d) end -nuts.getruledata = direct.getglyphdata and getdata or function(n) return getfield(n,"transform") end -nuts.setruledata = direct.setglyphdata and setdata or function(n,d) return setfield(n,"transform",d) end +nuts.getruledata = direct.getglyphdata and getdata or function(n) return getfield(n,"transform") end +nuts.setruledata = direct.setglyphdata and setdata or function(n,d) return setfield(n,"transform",d) end -- so far -nuts.getnucleus = direct.getnucleus -nuts.setnucleus = direct.setnucleus -nuts.getsup = direct.getsup -nuts.setsup = direct.setsup -nuts.getsub = direct.getsub -nuts.setsub = direct.setsub - -nuts.getchar = direct.getchar -nuts.setchar = direct.setchar -nuts.getfont = direct.getfont -nuts.setfont = direct.setfont -nuts.getfam = direct.getfam -nuts.setfam = direct.setfam - -nuts.getboth = direct.getboth -nuts.setboth = direct.setboth -nuts.setlink = direct.setlink -nuts.setsplit = direct.setsplit - -nuts.getlist = direct.getlist -- only hlist and vlist ! -nuts.setlist = direct.setlist -nuts.getleader = direct.getleader -nuts.setleader = direct.setleader -nuts.getcomponents = direct.getcomponents -nuts.setcomponents = direct.setcomponents - -nuts.getsubtype = direct.getsubtype -nuts.setsubtype = direct.setsubtype - -nuts.getlang = direct.getlang -nuts.setlang = direct.setlang -nuts.getlanguage = direct.getlang -nuts.setlanguage = direct.setlang - -nuts.getattrlist = direct.getattributelist -nuts.setattrlist = direct.setattributelist -nuts.getattributelist = direct.getattributelist -nuts.setattributelist = direct.setattributelist - -nuts.getoffsets = direct.getoffsets -nuts.setoffsets = direct.setoffsets - -nuts.getkern = direct.getkern -nuts.setkern = direct.setkern - -nuts.getdir = direct.getdir -nuts.setdir = direct.setdir - -nuts.getdirection = direct.getdirection -nuts.setdirection = direct.setdirection - -nuts.getpenalty = direct.getpenalty -nuts.setpenalty = direct.setpenalty - -nuts.getbox = direct.getbox -nuts.setbox = direct.setbox - -nuts.ischar = direct.is_char -nuts.isglyph = direct.is_glyph - -----.is_char = nuts.ischar -----.is_glyph = nuts.isglyph - -local d_remove_node = direct.remove -local d_flush_node = direct.flush_node -local d_getnext = direct.getnext -local d_getprev = direct.getprev -local d_getid = direct.getid -local d_getlist = direct.getlist -local d_find_tail = direct.tail -local d_insert_after = direct.insert_after -local d_insert_before = direct.insert_before -local d_slide = direct.slide ------ d_copy_node = direct.copy -local d_traverse = direct.traverse -local d_setlink = direct.setlink -local d_setboth = direct.setboth -local d_getboth = direct.getboth - -local remove = (CONTEXTLMTXMODE > 0 and LUATEXFUNCTIONALITY >= 20190704) and d_remove_node or function(head,current,free_too) +nuts.getnucleus = direct.getnucleus +nuts.setnucleus = direct.setnucleus +nuts.getsup = direct.getsup +nuts.setsup = direct.setsup +nuts.getsub = direct.getsub +nuts.setsub = direct.setsub + +nuts.getchar = direct.getchar +nuts.setchar = direct.setchar +nuts.getfont = direct.getfont +nuts.setfont = direct.setfont +nuts.getfam = direct.getfam +nuts.setfam = direct.setfam + +nuts.getboth = direct.getboth +nuts.setboth = direct.setboth +nuts.setlink = direct.setlink +nuts.setsplit = direct.setsplit + +nuts.getlist = direct.getlist -- only hlist and vlist ! +nuts.setlist = direct.setlist +nuts.getleader = direct.getleader +nuts.setleader = direct.setleader +nuts.getcomponents = direct.getcomponents +nuts.setcomponents = direct.setcomponents + +nuts.getsubtype = direct.getsubtype +nuts.setsubtype = direct.setsubtype + +nuts.getlang = direct.getlang +nuts.setlang = direct.setlang +nuts.getlanguage = direct.getlang +nuts.setlanguage = direct.setlang + +nuts.getattrlist = direct.getattributelist +nuts.setattrlist = direct.setattributelist +nuts.getattributelist = direct.getattributelist +nuts.setattributelist = direct.setattributelist + +nuts.getoffsets = direct.getoffsets +nuts.setoffsets = direct.setoffsets + +nuts.getkern = direct.getkern +nuts.setkern = direct.setkern + +nuts.getdir = direct.getdir +nuts.setdir = direct.setdir + +nuts.getdirection = direct.getdirection +nuts.setdirection = direct.setdirection + +nuts.getpenalty = direct.getpenalty +nuts.setpenalty = direct.setpenalty + +nuts.getbox = direct.getbox +nuts.setbox = direct.setbox + +nuts.ischar = direct.is_char +nuts.isglyph = direct.is_glyph + +----.is_char = nuts.ischar +----.is_glyph = nuts.isglyph + +local d_remove_node = direct.remove +local d_flush_node = direct.flush_node +local d_getnext = direct.getnext +local d_getprev = direct.getprev +local d_getid = direct.getid +local d_getlist = direct.getlist +local d_find_tail = direct.tail +local d_insert_after = direct.insert_after +local d_insert_before = direct.insert_before +local d_slide = direct.slide +----- d_copy_node = direct.copy +local d_traverse = direct.traverse +local d_setlink = direct.setlink +local d_setboth = direct.setboth +local d_getboth = direct.getboth + +local remove = CONTEXTLMTXMODE > 0 and d_remove_node or function(head,current,free_too) if current then local h, c = d_remove_node(head,current) if free_too then diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua index 7d95f8c4c..b904e54d6 100644 --- a/tex/context/base/mkiv/node-rul.lua +++ b/tex/context/base/mkiv/node-rul.lua @@ -124,6 +124,9 @@ local dimenfactor = fonts.helpers.dimenfactor local splitdimen = number.splitdimen local setmetatableindex = table.setmetatableindex +local magicconstants = tex.magicconstants +local running = magicconstants.running + -- local striprange = nuts.striprange @@ -773,9 +776,9 @@ interfaces.implement { }, actions = function(t) local n = new_rule( - t.width, - t.height, - t.depth + t.width or running, + t.height or running, + t.depth or running ) setattrlist(n,true) setoffsets(n,t.xoffset,t.yoffset) -- ,t.left, t.right diff --git a/tex/context/base/mkiv/pack-rul.mkiv b/tex/context/base/mkiv/pack-rul.mkiv index 34db6eec1..8de68f248 100644 --- a/tex/context/base/mkiv/pack-rul.mkiv +++ b/tex/context/base/mkiv/pack-rul.mkiv @@ -43,24 +43,6 @@ \def\pack_framed_setup_line_width[#1]% {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}} -% %D \macros -% %D {setupscreens} -% %D -% %D Sort of obsolete: -% %D -% %D \showsetup{setupscreens} -% -% \installcorenamespace{screens} -% -% \installsetuponlycommandhandler \??screens {screens} -% -% \appendtoks -% \edef\defaultbackgroundscreen{\directscreensparameter\c!screen} -% \to \everysetupscreens -% -% \setupscreens -% [\c!screen=.90] % was .95 but that's hardly visible - %D The parameter handler: \installcorenamespace{framed} @@ -356,18 +338,6 @@ % \quad} % \stopTEXpage -%D The oval box is drawn using a special macro, depending on -%D the driver in use. - -% \def\pack_framed_background_box_gray % avoid black rules when no gray -% {\edef\p_framed_backgroundscreen{\framedparameter\c!backgroundscreen}% -% \ifx\p_framed_backgroundscreen\empty \else -% \pack_framed_background_box_gray_indeed -% \fi} -% -% \def\pack_framed_background_box_gray_indeed % can be more direct but who cares, just compatibility -% {\colored[s=\p_framed_backgroundscreen]{\pack_framed_filled_box}} - %D It won't be a surprise that we not only provide gray boxes, but also colored %D ones. Here it is: @@ -577,21 +547,6 @@ \box\b_framed_extra \egroup} -% \def\pack_framed_process_background_indeed_external#1% -% {\pack_framed_overlay_initialize -% \bgroup -% \setbox\b_framed_extra\hpack\bgroup -% \ifzeropt\framedbackgroundoffset\else -% \kern-\framedbackgroundoffset -% \fi -% \hbox\bgroup#1\egroup -% \egroup -% \wd\b_framed_extra\zeropoint -% \ht\b_framed_extra\framedbackgroundheight -% \dp\b_framed_extra\framedbackgrounddepth -% \box\b_framed_extra -% \egroup} - \def\pack_framed_process_background_indeed_external {\pack_framed_overlay_initialize \pack_framed_process_background_indeed_internal} @@ -619,13 +574,6 @@ \edef\m_overlay_region{\reservedautoregiontag}% \fi} -% \def\pack_framed_add_region % experiment -% {\ifx\m_overlay_region\v!yes -% \anch_mark_region_box\b_framed_normal -% \else -% \anch_mark_tagged_box\b_framed_normal\m_overlay_region -% \fi} - \def\pack_framed_add_region % experiment {\anch_mark_tagged_box\b_framed_normal\m_overlay_region} @@ -654,18 +602,6 @@ \hss \egroup}} -% \def\pack_framed_overlay_initialize_indeed -% {\edef\overlaywidth {\the\d_framed_target_wd\space}% -% \edef\overlayheight {\the\dimexpr\d_framed_target_ht+\d_framed_target_dp\relax\space}% -% \edef\overlaydepth {\the\d_framed_target_dp\space}% -% \edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ? -% \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers -% \edef\overlaylinewidth{\the\d_framed_linewidth\space}% -% %\edef\overlaycorner {\framedparameter\c!backgroundcorner}% -% %\edef\overlayradius {\framedparameter\c!backgroundradius}% -% \edef\overlayoffset {\the\framedbackgroundoffset\space}% \backgroundoffset % we steal this one -% \let\pack_framed_overlay_initialize\relax} - \def\pack_framed_overlay_initialize_indeed {\d_overlay_width \d_framed_target_wd \d_overlay_height \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax @@ -719,27 +655,6 @@ \box\b_framed_normal \box\b_framed_extra}} -% \def\pack_framed_stroked_box_normal -% {\setbox\scratchbox\emptyhbox -% \wd\scratchbox\d_framed_target_wd -% \ht\scratchbox\d_framed_target_ht -% \dp\scratchbox\d_framed_target_dp -% \setbox\scratchbox\vpack \bgroup -% \csname \??framedtop\p_framed_frame\framedparameter\c!topframe \endcsname -% \nointerlineskip % new (needed for fences) -% \hbox \bgroup -% \csname \??framedleft\p_framed_frame\framedparameter\c!leftframe \endcsname -% \box\scratchbox -% \csname \??framedright\p_framed_frame\framedparameter\c!rightframe \endcsname -% \egroup -% \nointerlineskip % new (needed for fences) -% \csname \??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname -% \egroup -% \wd\scratchbox\d_framed_target_wd -% \ht\scratchbox\d_framed_target_ht -% \dp\scratchbox\d_framed_target_dp -% \box\scratchbox} - \def\pack_framed_stroked_box_normal_opened {\setbox\scratchbox\vpack \bgroup \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname @@ -885,35 +800,6 @@ \newcount\c_pack_framed_nesting -% to be tested (slightly more efficient): -% -% \unexpanded\def\pack_frame_common % #1 #2 -% {\bgroup -% \advance\c_pack_framed_nesting\plusone -% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed -% \edef\currentframed{>\the\c_pack_framed_nesting}% -% \pack_framed_initialize -% \bgroup -% \doifnextoptionalcselse} % #1 #2 -% -% \unexpanded\def\framed {\pack_frame_common\pack_framed_process_framed_pickup\pack_framed_process_indeed} -% \unexpanded\def\startframed{\pack_frame_common\pack_framed_start_framed_pickup \pack_framed_start_indeed } -% -% \def\pack_framed_process_framed_pickup[#1]% -% {\setupcurrentframed[#1]% -% \pack_framed_process_indeed} -% -% \def\pack_framed_start_framed_pickup[#1]% -% {\setupcurrentframed[#1]% here ! -% \secondargumenttrue % dirty trick -% \pack_framed_start_framed_indeed} -% -% \def\pack_framed_start_framed_indeed -% {\pack_framed_process_indeed -% \bgroup} -% -% no longer .. we also accept \startframed[tag] - \unexpanded\def\pack_framed_process_framed[#1]% {\bgroup \iffirstargument % faster @@ -929,24 +815,6 @@ \pack_framed_initialize \dosingleempty\pack_framed_process_framed} -% \unexpanded\def\startframed -% {\dosingleempty\pack_framed_start_framed} -% -% \def\pack_framed_start_framed[#1]% -% {\bgroup -% \advance\c_pack_framed_nesting\plusone -% \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed -% \edef\currentframed{>\the\c_pack_framed_nesting}% -% \pack_framed_initialize -% \bgroup -% \iffirstargument -% \secondargumenttrue % dirty trick -% \setupcurrentframed[#1]% here ! -% \fi -% \pack_framed_process_indeed -% \bgroup -% \ignorespaces} - \unexpanded\def\startframed {\dosingleempty\pack_framed_start_framed} @@ -1928,30 +1796,6 @@ % \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax} % \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax} -% \def\pack_framed_start_orientation -% {\ifcase\p_framed_orientation -% \let\pack_framed_stop_orientation\relax -% \else -% \scratchcounter\p_framed_orientation % weird .. why -% \divide\scratchcounter\plustwo -% \ifodd\scratchcounter -% \let\pack_framed_stop_orientation\pack_framed_stop_orientation_odd -% \else -% \let\pack_framed_stop_orientation\pack_framed_stop_orientation_even -% \fi -% \fi} -% -% \def\pack_framed_stop_orientation_odd -% {\swapmacros\framedwidth\framedheight -% \swapmacros\localwidth\localheight -% \swapdimens\d_framed_height\d_framed_width -% \pack_framed_stop_orientation_even} -% -% \def\pack_framed_stop_orientation_even -% {\setbox\b_framed_normal\hbox{\dorotatebox\p_framed_orientation\hbox{\box\b_framed_normal}}% -% \d_framed_height\ht\b_framed_normal -% \d_framed_width \wd\b_framed_normal} - \def\pack_framed_start_orientation {\ifcase\p_framed_orientation \let\pack_framed_stop_orientation\relax @@ -2042,15 +1886,6 @@ \edef\currentmathframed{#1}% \dosingleempty\pack_framed_mathframed_indeed} -% \def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here -% {\iffirstargument -% \setupcurrentmathframed[#1]% -% \fi -% \c_framed_mstyle\mathstyle -% \doifnot{\mathframedparameter\c!location}\v!low{\let\normalstrut\pack_framed_math_strut}% -% \inheritedmathframedframed{\Ustartmath\triggermathstyle\c_framed_mstyle#2\Ustopmath}% -% \endgroup} - \newcount\c_pack_framed_mathframed \newtoks \t_pack_framed_mathframed diff --git a/tex/context/base/mkiv/pack-rul.mkxl b/tex/context/base/mkiv/pack-rul.mkxl new file mode 100644 index 000000000..e21f5f1c2 --- /dev/null +++ b/tex/context/base/mkiv/pack-rul.mkxl @@ -0,0 +1,3049 @@ +%D \module +%D [ file=pack-rul, % was core-rul, +%D version=1998.10.16, +%D title=\CONTEXT\ Packaging Macros, +%D subtitle=Ruled Content, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Packaging Macros / Ruled Content} + +%D The code here is expanded lots of time as framed is used in many places. This is +%D why the code here is (and gets) optimized as much as possible. Also, by avoiding +%D packaging and expansion we also keep tracing reasonable. For instance, multiple +%D stacked backgrounds can slow down a run if not optimized this way. + +\registerctxluafile{pack-rul}{optimize} + +\unprotect + +% \definesystemvariable {ol} % OmLijnd -> check scrn-fld too + +%D \macros +%D {linewidth, setuplinewidth} +%D +%D This module deals with rules (lines) in several ways. First we introduce two +%D macros that can be used to set some common characteristics. +%D +%D \showsetup{setuplinewidth} +%D +%D The linewidth is available in \type{\linewidth}. The preset value of .4pt equals +%D the default hard coded \TEX\ rule width. + +\newdimen\linewidth + +\unexpanded\def\setuplinewidth + {\dosingleargument\pack_framed_setup_line_width} + +\def\pack_framed_setup_line_width[#1]% + {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}} + +%D The parameter handler: + +\installcorenamespace{framed} +\installcorenamespace{framedtop} +\installcorenamespace{framedbottom} +\installcorenamespace{framedleft} +\installcorenamespace{framedright} + +\installcorenamespace{regularframed} +\installcorenamespace{simplifiedframed} + +\installcommandhandler \??framed {framed} \??framed + +\let\pack_framed_framedparameter \framedparameter +\let\pack_framed_framedparameterhash\framedparameterhash +\let\pack_framed_setupcurrentframed \setupcurrentframed + +\def\pack_framed_initialize + {\let\framedparameter \pack_framed_framedparameter + \let\framedparameterhash\pack_framed_framedparameterhash + \let\setupcurrentframed \pack_framed_setupcurrentframed + \inframedtrue} + +%D A helper: + +\def\frameddimension#1{\the\dimexpr\framedparameter{#1}\relax} + +%D Inheritance: + +\def\installinheritedframed#1% + {\normalexpanded{\doinstallinheritedframed + \expandafter\noexpand\csname current#1\endcsname + \expandafter\noexpand\csname #1parameter\endcsname + \expandafter\noexpand\csname #1parameterhash\endcsname + \expandafter\noexpand\csname do#1parameter\endcsname + \expandafter\noexpand\csname do#1parentparameter\endcsname + \expandafter\noexpand\csname do#1rootparameter\endcsname + \expandafter\noexpand\csname setupcurrent#1\endcsname + \expandafter\noexpand\csname inherited#1framed\endcsname + \expandafter\noexpand\csname inherited#1framedbox\endcsname}} % new + +\unexpanded\def\doinstallinheritedframed#1#2#3#4#5#6#7#8#9% + {\def#5##1##2{\ifx##1\relax#6{##2}\else#4{##1}{##2}\fi}% + %\def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\s!empty\fi}% root + \def#6##1{\ifcsname\??framed:##1\endcsname\??framed:##1\else\??empty\fi}% root + \unexpanded\def#8% + {\bgroup + \bgroup + \inframedtrue + \let\currentframed #1% + \let\framedparameter #2% + \let\framedparameterhash#3% + \let\setupcurrentframed #7% + \pack_framed_process_indeed}% + \unexpanded\def#9% + {\bgroup + \inframedtrue + \let\currentframed #1% + \let\framedparameter #2% + \let\framedparameterhash#3% + \let\setupcurrentframed #7% + \pack_framed_process_box_indeed}} + +\unexpanded\def\installframedcommandhandler#1#2#3% + {\installcommandhandler{#1}{#2}{#3}% + \installinheritedframed{#2}} + +\unexpanded\def\installframedautocommandhandler#1#2#3% + {\installautocommandhandler{#1}{#2}{#3}% + \installinheritedframed{#2}} + +\unexpanded\def\installsimpleframedcommandhandler#1#2#3% + {\installsimplecommandhandler{#1}{#2}{#3}% + \installinheritedframed{#2}} + +% for regular framed + +\setupframed + [\c!width=\v!fit, + \c!height=\v!broad, + %\c!minheight=\zeropoint, + %\c!lines=, + \c!offset=.25\exheight, % \defaultframeoffset + \c!empty=\v!no, + \c!frame=\v!on, + %\c!topframe=, + %\c!bottomframe=, + %\c!leftframe=, + %\c!rightframe=, + \c!radius=.5\bodyfontsize, + \c!rulethickness=\linewidth, + \c!corner=\v!rectangular, + \c!depth=\zeropoint, + %\c!foregroundcolor=, + %\c!foregroundstyle=, + %\c!background=, + %\c!backgroundcolor=, + \c!backgroundoffset=\zeropoint, + %\c!framecolor=, + \c!frameoffset=\zeropoint, + \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here + \c!backgroundradius=\framedparameter\c!radius, + \c!backgrounddepth=\framedparameter\c!depth, + \c!framecorner=\framedparameter\c!corner, + \c!frameradius=\framedparameter\c!radius, + \c!framedepth=\framedparameter\c!depth, + %\c!component=, + %\c!region=, + %\c!align=, + \c!bottom=\vss, + %\c!top=, + \c!strut=\v!yes, + \c!autostrut=\v!yes, + \c!location=\v!normal, + %\c!orientation=, + %\c!anchoring=, + \c!autowidth=\v!yes, + %\c!setups=, + \c!loffset=\zeropoint, + \c!roffset=\zeropoint, + \c!toffset=\zeropoint, + \c!boffset=\zeropoint] + +%D For backgrounds and such: + +\defineframed + [\??simplifiedframed] + [\c!frame=\v!off, + \c!depth=\zeropoint, + \c!offset=\v!overlay, + \c!component=, + \c!region=, + \c!radius=.5\bodyfontsize, + \c!rulethickness=\linewidth, + \c!corner=\v!rectangular, + \c!backgroundoffset=\zeropoint, + \c!frameoffset=\zeropoint, + \c!backgroundcorner=\framedparameter\c!corner, % use \p_ here + \c!backgroundradius=\framedparameter\c!radius, + \c!backgrounddepth=\framedparameter\c!depth, + \c!framecorner=\framedparameter\c!corner, + \c!frameradius=\framedparameter\c!radius, + \c!framedepth=\framedparameter\c!depth, + \c!location=\v!normal, + \c!loffset=\zeropoint, + \c!roffset=\zeropoint, + \c!toffset=\zeropoint, + \c!boffset=\zeropoint] + +\unexpanded\def\definesimplifiedframed[#1]% no settings + {\defineframed[#1][\??simplifiedframed]% + \expandafter\let\csname#1\endcsname\undefined} + +\expandafter\let\csname\??simplifiedframed\endcsname\undefined + +%D We will communicate through module specific variables, current framed +%D parameters and some reserved dimension registers. + +\newdimen\d_framed_target_wd +\newdimen\d_framed_target_ht +\newdimen\d_framed_target_dp +\newdimen\d_framed_linewidth \let\ruledlinewidth\d_framed_linewidth % needed at lua end + +\let\p_framed_frame \empty % \framedparameter\c!frame +\let\p_framed_backgroundoffset\empty +\let\p_framed_foregroundstyle \empty +\let\p_framed_autostrut \empty +\let\p_framed_location \empty +\let\p_framed_orientation \empty +\let\p_framed_anchoring \empty +\let\p_framed_autowidth \empty +\let\p_framed_franalyze \empty +\let\p_framed_backgroundcorner\empty +\let\p_framed_backgroundradius\empty +\let\p_framed_framecorner \empty +\let\p_framed_frameradius \empty +\let\p_framed_lines \empty +\let\p_framed_empty \empty +\let\p_framed_backgroundcolor \empty +\let\p_framed_framecolor \empty +\let\p_framed_component \empty +\let\p_framed_background \empty +\let\p_framed_rulethickness \empty +\let\p_framed_foregroundcolor \empty +\let\p_framed_setups \empty + +%D We don't have to stick to a \TEX\ drawn rule, but also can use rounded +%D or even fancier shapes, as we will see later on. + +\def\pack_framed_filled_box + {\edef\p_framed_backgroundcorner{\framedparameter\c!backgroundcorner}% + \ifx\p_framed_backgroundcorner\v!rectangular + \pack_framed_filled_box_normal + \else + \pack_framed_filled_box_radius + \fi} + +\def\pack_framed_filled_box_normal + {\vrule + \s!width \d_framed_target_wd + \s!height\d_framed_target_ht + \s!depth \d_framed_target_dp + \relax} + +\def\pack_framed_filled_box_radius + {\edef\p_framed_backgroundradius{\framedparameter\c!backgroundradius}% + \ifzeropt\dimexpr\p_framed_backgroundradius\relax % just in case of .x\bodyfontsize + \pack_framed_filled_box_normal + \else + \pack_framed_filled_box_round + \fi} + +\def\pack_framed_filled_box_round + {\frule + type fill + width \d_framed_target_wd + height \d_framed_target_ht + depth \d_framed_target_dp + line \d_framed_linewidth + radius \p_framed_backgroundradius\space + corner {\p_framed_backgroundcorner} + \relax} + +\def\pack_framed_stroked_box + {\edef\p_framed_framecorner{\framedparameter\c!framecorner}% + \ifx\p_framed_framecorner\v!rectangular + \pack_framed_stroked_box_normal + \else + \pack_framed_stroked_box_radius + \fi} + +\def\pack_framed_stroked_box_radius + {\edef\p_framed_frameradius{\framedparameter\c!frameradius}% + \ifzeropt\dimexpr\p_framed_frameradius\relax % just in case of .x\bodyfontsize + \pack_framed_stroked_box_normal + \orelse\ifx\p_framed_frame\v!on + \pack_framed_stroked_box_round + \fi} + +% \pack_framed_stroked_box_normal % later + +\def\pack_framed_stroked_box_round + {\frule + width \d_framed_target_wd + height \d_framed_target_ht + depth \d_framed_target_dp + line \d_framed_linewidth + radius \p_framed_frameradius\space + corner {\p_framed_backgroundcorner} + \relax} + +% a lot of weird corners +% +% \startTEXpage +% \dontleavehmode\framed +% [corner=0,frame=on,framecolor=green, +% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}% +% \vskip1em +% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green, +% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green, +% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \vskip1em +% \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed +% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}% +% \quad} +% \stopTEXpage + +%D It won't be a surprise that we not only provide gray boxes, but also colored +%D ones. Here it is: + +\def\pack_framed_background_box_color + {\edef\p_framed_backgroundcolor{\framedparameter\c!backgroundcolor}% + \ifx\p_framed_backgroundcolor\empty \else + \doifcolor\p_framed_backgroundcolor\pack_framed_background_box_color_indeed + \fi} + +\def\pack_framed_background_box_color_indeed + {\hpack{\dousecolorparameter\p_framed_backgroundcolor\pack_framed_filled_box}} + +%D \macros +%D {defineoverlay, doifoverlayelse, overlayoffset, +%D overlaywidth, overlayheight, overlaydepth, +%D overlaycolor, overlaylinecolor, overlaylinewidth} +%D +%D Before we define the macro that actually takes card of the backgrounds, we +%D introduce overlays. An overlay is something that contrary to its name lays {\em +%D under} the text. An example of an overlay definition is: +%D +%D \startbuffer[tmp-1] +%D \defineoverlay +%D [fancy] +%D [{\externalfigure +%D [mp-cont.502] +%D [width=\overlaywidth, +%D height=\overlayheight]}] +%D \stopbuffer +%D +%D \typebuffer[tmp-1] +%D +%D That for instance can be uses in: +%D +%D \startbuffer[tmp-2] +%D \framed[backgroundachtergrond=fancy]{How Fancy!} +%D \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!} +%D \stopbuffer +%D +%D and looks like: +%D +%D \startlinecorrection +%D \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]} +%D \stoplinecorrection +%D +%D The formal definition is: +%D +%D \showsetup{defineoverlay} +%D +%D This macro's definition is a bit obscure, due the many non||used arguments and +%D the two step call that enable the setting of the width, height and depth +%D variables. Multiple backgrounds are possible and are specified as: +%D +%D \starttyping +%D \framed[background={one,two,three}]{Three backgrounds!} +%D \stoptyping +%D +%D Most drawing packages only know width and height. Therefore the dimensions have a +%D slightly different meaning here: +%D +%D \startitemize[packed] +%D \item \type{\overlaywidth }: width of the overlay +%D \item \type{\overlayheight}: height plus depth of the overlay +%D \item \type{\overlaydepth }: depth of the overlay +%D \stopitemize +%D +%D The resulting box is lowered to the right depth. + +%def\overlaywidth {\the\hsize\space} % We preset the variables +%def\overlayheight {\the\vsize\space} % to some reasonable default +%def\overlaydepth {0pt } % values. The attributes +%let\overlayoffset \overlaydepth % of the frame can be (are) +%let\overlaylinewidth \overlaydepth % set somewhere else. +\let\overlaycolor \empty +\let\overlaylinecolor \empty + +\def\overlayradius{\framedparameter\c!frameradius} + +\newdimen\d_overlay_width +\newdimen\d_overlay_height +\newdimen\d_overlay_depth +\newdimen\d_overlay_offset +\newdimen\d_overlay_linewidth + +\let\m_overlay_region\empty + +% expandable ... in a future version the space will go (in my one can use Overlay*) + +\def\overlaywidth {\the\d_overlay_width \space} % We preset the variables +\def\overlayheight {\the\d_overlay_height \space} % to some reasonable default +\def\overlaydepth {\the\d_overlay_depth \space} % values. +\def\overlayoffset {\the\d_overlay_offset \space} % of the frame can be (are) +\def\overlaylinewidth {\the\d_overlay_linewidth\space} % set somewhere else. +\def\overlayregion {\m_overlay_region} + +% public but kind of protected + +\def\usedoverlaywidth {\dimexpr\d_overlay_width \relax} +\def\usedoverlayheight {\dimexpr\d_overlay_height \relax} +\def\usedoverlaydepth {\dimexpr\d_overlay_depth \relax} +\def\usedoverlayoffset {\dimexpr\d_overlay_offset \relax} +\def\usedoverlaylinewidth{\dimexpr\d_overlay_linewidth\relax} + +%D The next register is used to initialize overlays. + +\newtoks\everyoverlay + +%D An example of an initialization is the following (overlays can contain text +%D and be executed under an regime where interlineskip is off). + +\installcorenamespace{overlay} +\installcorenamespace{overlaybuiltin} + +\appendtoks + \oninterlineskip +\to \everyoverlay + +\prependtoks + \hsize\d_overlay_width + \vsize\d_overlay_height +\to \everyoverlay + +\unexpanded\def\defineoverlay + {\dodoubleargument\pack_framed_define_overlay} + +\def\pack_framed_define_overlay[#1][#2]% + {\def\pack_framed_define_overlay_indeed##1{\setvalue{\??overlay##1}{\executedefinedoverlay{##1}{#2}}}% + \processcommalist[#1]\pack_framed_define_overlay_indeed} + +\unexpanded\def\executedefinedoverlay#1#2% we can share the definitions + {\bgroup % redundant grouping + \setbox\scratchbox\hbox\bgroup + \ifzeropt\d_framed_target_dp + \the\everyoverlay#2% saves wrapping (and lua call) + \else + \lower\d_framed_target_dp + \hbox{\the\everyoverlay#2}% + \fi + \egroup + \setlayoutcomponentattribute{\v!overlay:#1}% + \setbox\scratchbox\hpack \layoutcomponentboxattribute + {\kern -.5\dimexpr\wd\scratchbox-\d_framed_target_wd\relax % was \d_overlay_width + \raise-.5\dimexpr\ht\scratchbox-\d_framed_target_ht\relax % not \d_overlay_height ! + \box\scratchbox}% + \wd\scratchbox\d_framed_target_wd + \ht\scratchbox\d_framed_target_ht + \dp\scratchbox\d_framed_target_dp + \box\scratchbox + \egroup} + +%D \macros +%D {overlayfakebox} + +% \unexpanded\def\overlayfakebox +% {\hpack +% {\setbox\scratchbox\emptyhbox +% \wd\scratchbox\d_overlay_width +% \ht\scratchbox\d_overlay_height +% \box\scratchbox}} + +\unexpanded\def\overlayfakebox + {\hpack % redundant but needs testing + {\novrule + \s!width \d_overlay_width + \s!height\d_overlay_height + \s!depth \zeropoint}} + +%D For testing we provide: + +\def\doifelseoverlay#1% only tests external overlays + {\ifcsname\??overlay#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifoverlayelse\doifelseoverlay + +%D The content of the box will be (temporary) saved in a box. We also have an +%D extra box for backgrounds. + +\newbox\b_framed_normal +\newbox\b_framed_extra + +\newtoks\everybackgroundbox + +\let\m_framed_background\empty % we might need a public name + +\def\pack_framed_process_background + {\ifcsname\??overlaybuiltin\m_framed_background\endcsname + \expandafter\pack_framed_process_background_indeed_internal\lastnamedcs + \orelse\ifcsname\??overlay\m_framed_background\endcsname + \expandafter\pack_framed_process_background_indeed_external\lastnamedcs + \fi} + +\def\pack_framed_process_background_indeed_internal#1% % : in name + {\bgroup + \setbox\b_framed_extra\hpack\bgroup + \ifzeropt\framedbackgroundoffset\else + \kern-\framedbackgroundoffset + \fi + \hbox\bgroup#1\egroup + \egroup + \wd\b_framed_extra\zeropoint + \ht\b_framed_extra\framedbackgroundheight + \dp\b_framed_extra\framedbackgrounddepth + \box\b_framed_extra + \egroup} + +\def\pack_framed_process_background_indeed_external + {\pack_framed_overlay_initialize + \pack_framed_process_background_indeed_internal} + +\def\pack_framed_process_backgrounds#1,#2% #2 gobbles spaces (we could avoid one catch if we have nextbackground) + {\edef\m_framed_background{#1}% + \ifx\m_framed_background\s!unknown\else + \pack_framed_process_background + \expandafter\pack_framed_process_backgrounds + \fi#2} + +%D Beware, a backgroundbox can be empty which is another reason why we set the +%D width to zero instead of back-skipping. + +\newdimen\framedbackgroundwidth +\newdimen\framedbackgroundheight +\newdimen\framedbackgrounddepth +\newdimen\framedbackgroundoffset + +\def\pack_framed_background_box_content% fuzzy but needed hack, this \vss, otherwise + {\vpack to \framedbackgroundheight{\vss\box\b_framed_normal\vss}} % vertical shift \backgroundheight + +\def\pack_framed_set_region % experiment + {\ifx\m_overlay_region\v!yes + \edef\m_overlay_region{\reservedautoregiontag}% + \fi} + +\def\pack_framed_add_region % experiment + {\anch_mark_tagged_box\b_framed_normal\m_overlay_region} + +\def\pack_framed_add_background + {\setbox\b_framed_normal\hpack % was vbox % see also *1* + {%\pack_framed_forgetall % can be relaxed + \boxmaxdepth\maxdimen + \framedbackgroundoffset\d_framed_backgroundoffset + \framedbackgroundwidth \wd\b_framed_normal + \framedbackgroundheight\ht\b_framed_normal + \framedbackgrounddepth \dp\b_framed_normal + \d_framed_target_wd\dimexpr\framedbackgroundwidth +2\framedbackgroundoffset\relax + \d_framed_target_ht\dimexpr\framedbackgroundheight+ \framedbackgroundoffset\relax + \d_framed_target_dp\dimexpr\framedbackgrounddepth + \framedbackgroundoffset+\framedparameter\c!backgrounddepth\relax + \let\pack_framed_overlay_initialize\pack_framed_overlay_initialize_indeed + \ifx\p_framed_component\empty + \resetlayoutcomponentattribute + \else + \setlayoutcomponentattribute{\v!background:\p_framed_component}% + \fi + \let\foregroundbox\pack_framed_background_box_content + \hpack \layoutcomponentboxattribute to \framedbackgroundwidth\bgroup % width in case 'foreground' is used as overlay + \the\everybackgroundbox % moved + \expandafter\pack_framed_process_backgrounds\p_framed_background,\s!unknown,\relax % hm, messy .. look into it + \box\b_framed_normal + \hss + \egroup}} + +\def\pack_framed_overlay_initialize_indeed + {\d_overlay_width \d_framed_target_wd + \d_overlay_height \dimexpr\d_framed_target_ht+\d_framed_target_dp\relax + \d_overlay_depth \d_framed_target_dp + \d_overlay_linewidth \d_framed_linewidth + \d_overlay_offset \framedbackgroundoffset\relax + \edef\overlaycolor {\framedparameter\c!backgroundcolor}% let ? + \edef\overlaylinecolor{\framedparameter\c!framecolor}% only needed for layers + %\edef\overlaycorner {\framedparameter\c!backgroundcorner}% + %\edef\overlayradius {\framedparameter\c!backgroundradius}% + \let\pack_framed_overlay_initialize\relax} + +%D One can explictly insert the foreground box. For that purpose we introduce the +%D overlay \type {foreground}. +%D +%D We predefine two already familiar backgrounds: + +%letvalue{\??overlaybuiltin\v!screen }\pack_framed_background_box_gray +\letvalue{\??overlaybuiltin\v!color }\pack_framed_background_box_color +\letvalue{\??overlaybuiltin\v!foreground}\pack_framed_background_box_content % replaces: \defineoverlay[\v!foreground][\foregroundbox] + +%D We can specify overlays as a comma separated list of overlays, a sometimes +%D handy feature. +%D +%D Besides backgrounds (overlays) we also need some macros to draw outlines (ruled +%D borders). Again we have to deal with square and round corners. The first category +%D can be handled by \TEX\ itself, the latter one depends on the driver. This macro +%D also support a negative offset. + +\def\pack_framed_add_outline + {\setbox\b_framed_normal\hpack % rules on top of box + {\d_framed_target_wd\dimexpr\wd\b_framed_normal+2\d_framed_frameoffset\relax + \d_framed_target_ht\dimexpr\ht\b_framed_normal+ \d_framed_frameoffset\relax + \d_framed_target_dp\dimexpr\dp\b_framed_normal+ \d_framed_frameoffset+\framedparameter\c!framedepth\relax + \ifdim\d_framed_target_dp<\zeropoint + \advance\d_framed_target_ht \d_framed_target_dp + \scratchdimen-\d_framed_target_dp + \d_framed_target_dp\zeropoint + \else + \scratchdimen\zeropoint + \fi + \edef\overlaylinecolor{\framedparameter\c!framecolor}% twice, also in background + \setbox\b_framed_extra\hpack + {\kern-\d_framed_frameoffset + \raise\scratchdimen + \hpack{\ifx\overlaylinecolor\empty\else\dousecolorparameter\overlaylinecolor\fi\pack_framed_stroked_box}}% + \wd\b_framed_extra\wd\b_framed_normal + \ht\b_framed_extra\ht\b_framed_normal + \dp\b_framed_extra\dp\b_framed_normal + \wd\b_framed_normal\zeropoint + \box\b_framed_normal + \box\b_framed_extra}} + +\def\pack_framed_stroked_box_normal_opened + {\setbox\scratchbox\vpack \bgroup + \csname\??framedtop\p_framed_frame\framedparameter\c!topframe\endcsname + \nointerlineskip % new (needed for fences) + \hpack \bgroup + \csname\??framedleft\p_framed_frame\framedparameter\c!leftframe\endcsname + \novrule + \s!width \d_framed_target_wd + \s!height\d_framed_target_ht + \s!depth \d_framed_target_dp + \csname\??framedright\p_framed_frame\framedparameter\c!rightframe\endcsname + \egroup + \nointerlineskip % new (needed for fences) + \csname\??framedbottom\p_framed_frame\framedparameter\c!bottomframe\endcsname + \egroup + \wd\scratchbox\d_framed_target_wd + \ht\scratchbox\d_framed_target_ht + \dp\scratchbox\d_framed_target_dp + \box\scratchbox} + +\def\pack_framed_stroked_box_normal_closed + {\hpack\bgroup + \scratchdimen.5\d_framed_linewidth + \hskip\scratchdimen + \clf_framedoutline + \dimexpr\d_framed_target_wd-\d_framed_linewidth\relax + \dimexpr\d_framed_target_ht-\scratchdimen\relax + \dimexpr\d_framed_target_dp-\scratchdimen\relax + \d_framed_linewidth + \relax + \egroup} + +\def\pack_framed_stroked_box_normal + {\ifx\p_framed_frame\v!closed + \pack_framed_stroked_box_normal_closed + \else + \pack_framed_stroked_box_normal_opened + \fi} + +\def\pack_framed_t_rule{\hrule\s!height\d_framed_linewidth\kern-\d_framed_linewidth} +\def\pack_framed_b_rule{\kern-\d_framed_linewidth\hrule\s!height\d_framed_linewidth} +\def\pack_framed_r_rule{\kern-\d_framed_linewidth\vrule\s!width\d_framed_linewidth} +\def\pack_framed_l_rule{\vrule\s!width\d_framed_linewidth\kern-\d_framed_linewidth} + +\letvalue{\??framedtop \v!on \v!on}\pack_framed_t_rule +\letvalue{\??framedtop \v!off\v!on}\pack_framed_t_rule +\letvalue{\??framedtop \v!on }\pack_framed_t_rule + +\letvalue{\??framedbottom\v!on \v!on}\pack_framed_b_rule +\letvalue{\??framedbottom\v!off\v!on}\pack_framed_b_rule +\letvalue{\??framedbottom\v!on }\pack_framed_b_rule + +\letvalue{\??framedleft \v!on \v!on}\pack_framed_l_rule +\letvalue{\??framedleft \v!off\v!on}\pack_framed_l_rule +\letvalue{\??framedleft \v!on }\pack_framed_l_rule + +\letvalue{\??framedright \v!on \v!on}\pack_framed_r_rule +\letvalue{\??framedright \v!off\v!on}\pack_framed_r_rule +\letvalue{\??framedright \v!on }\pack_framed_r_rule + +% no overlapping rules + +\def\pack_framed_t_rules{\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}\nointerlineskip\kern-\d_framed_linewidth} +\def\pack_framed_b_rules{\kern-\d_framed_linewidth\nointerlineskip\hpack{\kern\d_framed_linewidth\vrule\s!width\dimexpr\d_framed_target_wd-2\d_framed_linewidth\relax\s!height\d_framed_linewidth}} +\def\pack_framed_r_rules{\kern-\d_framed_linewidth\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth} +\def\pack_framed_l_rules{\vrule\s!height\dimexpr\d_framed_target_ht-\d_framed_linewidth\relax\s!depth-\d_framed_linewidth\s!width\d_framed_linewidth\kern-\d_framed_linewidth} + +\letvalue{\??framedtop \v!small\v!small}\pack_framed_t_rules +\letvalue{\??framedtop \v!off \v!small}\pack_framed_t_rules +\letvalue{\??framedtop \v!small }\pack_framed_t_rules + +\letvalue{\??framedbottom\v!small\v!small}\pack_framed_b_rules +\letvalue{\??framedbottom\v!off \v!small}\pack_framed_b_rules +\letvalue{\??framedbottom\v!small }\pack_framed_b_rules + +\letvalue{\??framedleft \v!small\v!small}\pack_framed_l_rules +\letvalue{\??framedleft \v!off \v!small}\pack_framed_l_rules +\letvalue{\??framedleft \v!small }\pack_framed_l_rules + +\letvalue{\??framedright \v!small\v!small}\pack_framed_r_rules +\letvalue{\??framedright \v!off \v!small}\pack_framed_r_rules +\letvalue{\??framedright \v!small }\pack_framed_r_rules + +% \framed +% [width=4cm,height=3cm,rulethickness=3mm, +% frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on] +% {} +% \framed +% [width=4cm,height=3cm,rulethickness=3mm, +% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small] +% {} +% \framed +% [width=4cm,height=3cm,rulethickness=3mm, +% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on] +% {} + +%D The next few macros are probably the most misused ones in \CONTEXT. They deal +%D with putting rules around boxes, provide backgrounds, offer alignment features, +%D and some more. We start with defining some booleans. These give an impression of +%D what we are going to take into account. + +% todo : \c_framed_hasoffset +% faster : \let\c_framed_hasoffset\falseconditional + +\newconditional\c_framed_has_offset +\newconditional\c_framed_has_width +\newconditional\c_framed_has_height +\newconditional\c_framed_has_format +\newconditional\c_framed_is_overlaid +\newconditional\c_framed_has_frame +\newconditional\c_framed_has_extra_offset +\newconditional\c_framed_text_location_none + +\newconstant \c_framed_has_strut % 0=relaxes 1=pseudostruts 2=realstruts + +%D \macros +%D {framed, setupframed} +%D +%D Ruled boxes are typeset using \type{\framed}. This command is quite versatile +%D and, although some users will probably seldom use it, one cannot overlook its +%D features. +%D +%D \showsetup{setupframed} +%D \showsetup{framed} +%D +%D This general macro is a special version of an even more general case, that can +%D easily be linked into other macros that need some kind of framing. The local +%D version is called with an extra parameter: the variable identifier. The reason +%D for passing this identifier between brackets lays in the mere fact that this way +%D we can use the optional argument grabbers. + +\def\defaultframeoffset{.25\exheight} + +\installcorenamespace{regularframedlevel} + +\unexpanded\def\installregularframed#1% + {\defineframed[#1]} + +\unexpanded\def\presetlocalframed[#1]% + {\defineframed[#1]} + +% \presetlocalframed[\??framed] + +\newcount\c_pack_framed_nesting + +\unexpanded\def\pack_framed_process_framed[#1]% + {\bgroup + \iffirstargument % faster + \setupcurrentframed[#1]% here ! + \fi + \pack_framed_process_indeed} + +\unexpanded\def\framed + {\bgroup + \advance\c_pack_framed_nesting\plusone + \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed + \edef\currentframed{>\the\c_pack_framed_nesting}% + \pack_framed_initialize + \dosingleempty\pack_framed_process_framed} + +\unexpanded\def\startframed + {\dosingleempty\pack_framed_start_framed} + +\def\pack_framed_start_framed[#1]% + {\bgroup + \doifelseassignment{#1}\pack_framed_start_framed_yes\pack_framed_start_framed_nop{#1}} + +\def\pack_framed_start_framed_yes#1% + {\advance\c_pack_framed_nesting\plusone + \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed + \iffirstargument\secondargumenttrue\fi % dirty trick + \edef\currentframed{>\the\c_pack_framed_nesting}% + \pack_framed_initialize + \bgroup + \iffirstargument + \secondargumenttrue % dirty trick + \setupcurrentframed[#1]% here ! + \fi + \pack_framed_process_indeed + \bgroup + \ignorespaces} + +\def\pack_framed_start_framed_nop#1% + {\edef\currentframed{#1}% + \dosingleempty\pack_framed_start_framed_nop_indeed} + +\def\pack_framed_start_framed_nop_indeed[#1]% + {\pack_framed_initialize + \bgroup + \iffirstargument + \setupcurrentframed[#1]% here ! + \fi + \pack_framed_process_indeed + \bgroup + \ignorespaces} + +% till here + +\unexpanded\def\stopframed + {\removeunwantedspaces + \egroup} + +\unexpanded\def\normalframedwithsettings[#1]% + {\bgroup + \advance\c_pack_framed_nesting\plusone + \expandafter\let\csname\??framed>\the\c_pack_framed_nesting:\s!parent\endcsname\??framed + \bgroup + \edef\currentframed{>\the\c_pack_framed_nesting}% + \pack_framed_initialize + \setupcurrentframed[#1]% + \pack_framed_process_indeed} + +%D \startbuffer +%D \setupframed [framecolor=yellow] \framed{A} +%D \defineframed[myframed] [framecolor=blue] \myframed{B} +%D \setupframed [myframed] [framecolor=red] \myframed{C} +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D \startbuffer +%D \presetlocalframed[myframed] +%D \localframed[myframed][framecolor=green]{oeps} +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +%D \macros +%D {ifinframed} +%D +%D The normal case first presets all parameters and next starts looking for the user +%D supplied ones. The first step is omitted in the local case, because these are +%D preset at declaration time and keep their values unless explictly changed. By +%D presetting the variables everytime the normal command is called, we can use this +%D command nested, without the unwanted side effect of inheritance. The boolean is +%D used to speed up the color stack. + +\newif\ifinframed + +%D The next one is faster on multiple backgrounds per page. No +%D dimensions can be set, only frames and backgrounds. + +\unexpanded\def\fastlocalframed[#1]#2[#3]#4% 3-4 + {\bgroup + \edef\currentframed{#1}% + \pack_framed_initialize + \setbox\b_framed_normal\hbox{#4}% + \iftrialtypesetting \else + \edef\m_overlay_region{\framedparameter\c!region}% + \ifx\m_overlay_region\empty\else + \pack_framed_set_region + \fi + \fi + \setupcurrentframed[#3]% + \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds + \d_framed_frameoffset\framedparameter\c!frameoffset\relax % also used in backgrounds + \edef\p_framed_frame{\framedparameter\c!frame}% + \edef\p_framed_background{\framedparameter\c!background}% + % not here, in calling macro: setups + \pack_framed_remove_depth + \ifx\p_framed_frame\v!overlay \else \ifx\p_framed_frame\v!none \else + \ifx\p_framed_rulethickness\empty\else + \d_framed_linewidth\p_framed_rulethickness\relax + \fi + \pack_framed_add_outline % real or invisible frame + \fi\fi + \ifx\p_framed_background\empty \else + \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}% + \d_framed_backgroundoffset + \ifx\p_framed_backgroundoffset\v!frame + \d_framed_frameoffset + \else + \p_framed_backgroundoffset + \fi + \edef\p_framed_component{\framedparameter\c!component}% + \pack_framed_add_background + \fi + \pack_framed_restore_depth + \iftrialtypesetting \else + \ifx\m_overlay_region\empty\else + \pack_framed_add_region + \fi + \fi + \box\b_framed_normal + \egroup} + +%D The next macro uses a box and takes its natural width and height so these +%D can better be correct. + +\unexpanded\def\pack_framed_process_box_indeed#1#2% component box (assumes parameters set and grouped usage) + {\setbox\b_framed_normal\box#2% could actually be \let\b_framed_normal#2 + \edef\m_overlay_region{\framedparameter\c!region}% + \ifx\m_overlay_region\empty\else + \pack_framed_set_region + \fi + \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% also used in backgrounds + \d_framed_frameoffset\framedparameter\c!frameoffset\relax % also used in backgrounds + \edef\p_framed_frame{\framedparameter\c!frame}% + \edef\p_framed_background{\framedparameter\c!background}% + \ifx\p_framed_frame\v!overlay \else \ifx\p_framed_frame\v!none \else + \ifx\p_framed_rulethickness\empty \else + \d_framed_linewidth\p_framed_rulethickness\relax + \fi + \pack_framed_add_outline % real or invisible frame + \fi\fi + \ifx\p_framed_background\empty \else + \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}% + \d_framed_backgroundoffset + \ifx\p_framed_backgroundoffset\v!frame + \d_framed_frameoffset + \else + \p_framed_backgroundoffset + \fi + \edef\p_framed_component{#1}% + \pack_framed_add_background + \fi + \ifx\m_overlay_region\empty\else + \pack_framed_add_region + \fi + \box\b_framed_normal + \egroup} + +\unexpanded\def\localbackgroundframed#1% namespace component box + {\bgroup + \edef\currentframed{#1}% + \pack_framed_initialize + \pack_framed_process_box_indeed} % group ends here + +\let\postprocessframebox\relax + +%D A nice example by Aditya: +%D +%D \starttyping +%D \setupframed +%D [loffset=\framedparameter{hoffset}, +%D roffset=\framedparameter{hoffset}, +%D hoffset=\zeropoint] +%D +%D \defineframed[test][hoffset=1cm] +%D \stoptyping + +\newdimen\d_framed_width +\newdimen\d_framed_height +\newdimen\d_framed_frameoffset +\newdimen\d_framed_backgroundoffset +\newdimen\d_framed_local_offset + +% todo: protect local \framednames + +\unexpanded\def\localframed + {\bgroup + \dodoubleempty\pack_framed_local} + +\unexpanded\def\pack_framed_local[#1][#2]% + {\bgroup + \edef\currentframed{#1}% + \pack_framed_initialize + \ifsecondargument % faster + \setupcurrentframed[#2]% here ! + \fi + \pack_framed_process_indeed} + +\unexpanded\def\directlocalframed[#1]% no optional + {\bgroup + \bgroup + \edef\currentframed{#1}% + \pack_framed_initialize + \pack_framed_process_indeed} + +\unexpanded\def\localframedwithsettings[#1][#2]% no checking (so no spaces between) + {\bgroup + \bgroup + \edef\currentframed{#1}% + \pack_framed_initialize + \setupcurrentframed[#2]% here ! + \pack_framed_process_indeed} + +% done + +\def\c!fr!analyze{fr:analyze} % private option + +\let\delayedbegstrut\relax +\let\delayedendstrut\relax +\let\delayedstrut \relax + +\let\localoffset\empty +\let\localwidth \empty +\let\localheight\empty +\let\localformat\empty +\let\localstrut \empty + +\unexpanded\def\pack_framed_process_indeed + {\d_framed_frameoffset\framedparameter\c!frameoffset + \edef\p_framed_backgroundoffset{\framedparameter\c!backgroundoffset}% + \d_framed_backgroundoffset + \ifx\p_framed_backgroundoffset\v!frame + \d_framed_frameoffset + \else + \p_framed_backgroundoffset + \fi + % new, experimental dirty hook + \framedparameter\c!extras + % to get the right spacing + \edef\p_framed_foregroundstyle{\framedparameter\c!foregroundstyle}% + \ifx\p_framed_foregroundstyle\empty\else\dousestyleparameter\p_framed_foregroundstyle\fi + % beware, both the frame and background offset can be overruled + % + \edef\p_framed_setups{\framedparameter\c!setups}% + % the next macros are visible + \edef\localoffset{\framedparameter\c!offset}% + \edef\localwidth {\framedparameter\c!width}% + \edef\localheight{\framedparameter\c!height}% + \edef\localformat{\framedparameter\c!align}% + \edef\localstrut {\framedparameter\c!strut}% + % these are not + \edef\p_framed_autostrut {\framedparameter\c!autostrut}% + \edef\p_framed_frame {\framedparameter\c!frame}% + \edef\p_framed_location {\framedparameter\c!location}% + \edef\p_framed_orientation{\framedparameter\c!orientation}% + \edef\p_framed_anchoring {\framedparameter\c!anchoring}% + % + \edef\p_framed_autowidth {\framedparameter\c!autowidth}% + \edef\p_framed_franalyze {\framedparameter\c!fr!analyze}% experimental option + % + \ifx\p_framed_frame\v!overlay % no frame, no offset, no framewidth + \setfalse\c_framed_has_frame + \let\localoffset\v!overlay + \orelse\ifx\p_framed_frame\v!none % no frame, no framewidth + \setfalse\c_framed_has_frame + \else + \settrue\c_framed_has_frame + \fi + \ifconditional\c_framed_has_frame + \edef\p_framed_rulethickness{\framedparameter\c!rulethickness}% + \ifx\p_framed_rulethickness\empty\else + \d_framed_linewidth\p_framed_rulethickness\relax + \fi + \else + \d_framed_linewidth\zeropoint + \fi + % 2013/03/12: a change of order (sizes before align + \ifx\localwidth\v!local + \setlocalhsize + \fi + % + \forgetall % should happen after \localwidth but before align + % + \ifx\localformat\empty + \setfalse\c_framed_has_format + \else + \settrue\c_framed_has_format + \dosetraggedcommand\localformat % not that fast + \fi + % + \ifcsname\??framedoffsetalternative\localoffset\endcsname + \lastnamedcs + \else + \framed_offset_alternative_unknown + \fi + \ifcsname\??framedwidthalternative\localwidth\endcsname + \lastnamedcs + \else + \framed_width_alternative_unknown + \fi + \ifcsname\??framedheightalternative\localheight\endcsname + \lastnamedcs + \else + \framed_height_alternative_unknown + \fi + % the next check could move to heightalternative + \ifconditional\c_framed_has_height + % obey user set height, also downward compatible + \else + \edef\p_framed_lines{\framedparameter\c!lines}% + \ifx\p_framed_lines\empty\else + \ifcase\p_framed_lines\else + \d_framed_height\p_framed_lines\lineheight + \edef\localheight{\the\d_framed_height}% + \settrue\c_framed_has_height + \fi + \fi + \fi + % this is now an option: width=local + % + % \ifdim\d_framed_width=\hsize + % \parindent\zeropoint + % \setlocalhsize + % \d_framed_width\localhsize + % \fi + % i.e. disable (colsetbackgroundproblemintechniek) + \advance\d_framed_width -2\d_framed_local_offset + \advance\d_framed_height -2\d_framed_local_offset + \ifcsname\??framedstrutalternative\localstrut\endcsname + \lastnamedcs + \else + \framed_offset_alternative_unknown + \fi + % the next check could move to strutalternative + \ifcase\c_framed_has_strut % none (not even noindent) + \let\localbegstrut\relax + \let\localendstrut\relax + \let\localstrut \relax + \or % no / overlay + \let\localbegstrut\pseudobegstrut + \let\localendstrut\pseudoendstrut + \let\localstrut \pseudostrut + \else + \let\localbegstrut\begstrut + \let\localendstrut\endstrut + \let\localstrut \strut + \fi + \ifx\p_framed_autostrut\v!yes + \let\delayedbegstrut\relax + \let\delayedendstrut\relax + \let\delayedstrut \relax + \else + \let\delayedbegstrut\localbegstrut + \let\delayedendstrut\localendstrut + \let\delayedstrut \localstrut + \let\localbegstrut \relax + \let\localendstrut \relax + \let\localstrut \relax + \fi + \ifconditional\c_framed_has_height + \let\\\pack_framed_vboxed_newline + \ifconditional\c_framed_has_width + \let\hairline\pack_framed_vboxed_hairline + \ifconditional\c_framed_has_format + \let\next\pack_framed_format_format_yes + \else + \let\next\pack_framed_format_format_nop + \fi + \else + \let\hairline\pack_framed_hboxed_hairline + \ifconditional\c_framed_has_format + \let\next\pack_framed_format_format_height + \else + \let\next\pack_framed_format_format_vsize + \fi + \fi + \orelse\ifconditional\c_framed_has_width + \ifconditional\c_framed_has_format + \let\hairline\pack_framed_vboxed_hairline + \let\\\pack_framed_vboxed_newline + \let\next\pack_framed_format_format_width + \else + \let\hairline\pack_framed_hboxed_hairline + \let\\\pack_framed_hboxed_newline + \let\next\pack_framed_format_format_hsize + \fi + \else + \let\hairline\pack_framed_hboxed_hairline + \let\\\pack_framed_hboxed_newline + \let\next\pack_framed_format_format_no_size + \fi + \pack_framed_check_extra_offsets + \edef\p_framed_background{\framedparameter\c!background}% +% \ifx\p_framed_background\empty +% \let\pack_framed_forgetall\forgetall +% \else +% \let\pack_framed_forgetall\relax +% \forgetall +% \fi + \edef\framedwidth {\the\ifdim\d_framed_width >\zeropoint \d_framed_width \else\zeropoint\fi}% public + \edef\framedheight{\the\ifdim\d_framed_height>\zeropoint \d_framed_height\else\zeropoint\fi}% public + \edef\framedoffset{\the\dimexpr\ifconditional\c_framed_has_offset\localoffset \else\zeropoint\fi}% public + \ifx\p_framed_orientation\empty + \let\pack_framed_stop_orientation\relax + \else + \pack_framed_start_orientation + \fi + \afterassignment\pack_framed_restart + \setbox\b_framed_normal\next} + +% alternatives for width, height, strut and offset + +\installcorenamespace{framedwidthalternative} +\installcorenamespace{framedheightalternative} +\installcorenamespace{framedstrutalternative} +\installcorenamespace{framedoffsetalternative} + +% widths + +\setvalue{\??framedwidthalternative\empty}% + {\ifconditional\c_framed_has_format + \settrue\c_framed_has_width + \d_framed_width\hsize + \else + \setfalse\c_framed_has_width + \d_framed_width\zeropoint + \fi} + +\setvalue{\??framedwidthalternative\v!fit}% + {\ifconditional\c_framed_has_format + \settrue\c_framed_has_width + \d_framed_width\hsize + \else + \setfalse\c_framed_has_width + \d_framed_width\zeropoint + \fi} + +\setvalue{\??framedwidthalternative\v!fixed}% equals \v!fit but no shapebox + {\ifconditional\c_framed_has_format + \settrue\c_framed_has_width + \d_framed_width\hsize + \else + \setfalse\c_framed_has_width + \d_framed_width\zeropoint + \fi} + +\setvalue{\??framedwidthalternative\v!broad}% + {\settrue\c_framed_has_width + \d_framed_width\hsize} + +\setvalue{\??framedwidthalternative\v!max}% idem broad + {\settrue\c_framed_has_width + \d_framed_width\hsize} + +\setvalue{\??framedwidthalternative\v!local}% + {\settrue\c_framed_has_width + %\setlocalhsize + \d_framed_width\localhsize} + +\setvalue{\??framedwidthalternative\s!unknown}% + {\settrue\c_framed_has_width + \d_framed_width\localwidth} + +\def\framed_width_alternative_unknown + {\settrue\c_framed_has_width + \d_framed_width\localwidth} + +% heights + +\setvalue{\??framedheightalternative\empty}% + {\setfalse\c_framed_has_height + \d_framed_height\zeropoint} + +\setvalue{\??framedheightalternative\v!fit}% + {\setfalse\c_framed_has_height + \d_framed_height\zeropoint} + +\setvalue{\??framedheightalternative\v!broad}% + {\setfalse\c_framed_has_height + \d_framed_height\zeropoint} + +\setvalue{\??framedheightalternative\v!max}% + {\settrue\c_framed_has_height + \d_framed_height\vsize} + +\setvalue{\??framedheightalternative\s!unknown}% + {\settrue\c_framed_has_height + \d_framed_height\localheight} + +\def\framed_height_alternative_unknown + {\settrue\c_framed_has_height + \d_framed_height\localheight} + +% struts (use let instead?) + +\setvalue{\??framedstrutalternative\v!no}% + {\c_framed_has_strut\plusone} + +\setvalue{\??framedstrutalternative\v!global}% + {\setstrut} + +\setvalue{\??framedstrutalternative\v!local}% + {\setfontstrut} + +\setvalue{\??framedstrutalternative\v!yes}% + {\setstrut} + +\setvalue{\??framedstrutalternative\s!unknown}% + {\setstrut} + +\def\framed_strut_alternative_unknown + {\setstrut} + +\setvalue{\??framedstrutalternative\v!none}% not even pseudo struts + {\c_framed_has_strut\zerocount} + +% offsets + +\setvalue{\??framedoffsetalternative\v!none}% + {\setfalse\c_framed_has_offset + \c_framed_has_strut\plusone + \setfalse\c_framed_is_overlaid + \d_framed_local_offset\d_framed_linewidth} + +\setvalue{\??framedoffsetalternative\v!overlay}% + {% \ifx\p_framed_frame\v!no \setfalse\c_framed_has_frame \fi % test first + \setfalse\c_framed_has_offset + \c_framed_has_strut\plusone + \settrue\c_framed_is_overlaid + \d_framed_local_offset\zeropoint} + +% \setvalue{\??framedoffsetalternative\v!strut}% +% {\setfalse\c_framed_has_offset +% \c_framed_has_strut\plustwo +% \settrue\c_framed_is_overlaid +% \d_framed_local_offset\zeropoint} + +\setvalue{\??framedoffsetalternative\v!default}% new per 2-6-2000 + {\settrue \c_framed_has_offset + \c_framed_has_strut\plustwo + \setfalse\c_framed_is_overlaid + \let\localoffset\defaultframeoffset + \letframedparameter\c!offset\defaultframeoffset % brrr + \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax} + +\def\framed_offset_alternative_unknown + {\settrue \c_framed_has_offset + \c_framed_has_strut\plustwo + \setfalse\c_framed_is_overlaid + \let\defaultframeoffset\localoffset + \d_framed_local_offset\dimexpr\localoffset+\d_framed_linewidth\relax} + +\letvalue{\??framedoffsetalternative\s!unknown}\framed_offset_alternative_unknown + +% so far for alternatives + +\let\pack_framed_stop_orientation\relax + +\def\pack_framed_restart + {\aftergroup\pack_framed_finish} + +\def\pack_framed_do_top + {\raggedtopcommand + \framedparameter\c!top + \edef\p_blank{\framedparameter\c!blank}% + \ifx\p_blank\v!yes\else % auto or no + \doinhibitblank + \fi} + +\def\pack_framed_do_bottom + {\framedparameter\c!bottom + \raggedbottomcommand} + +%D Careful analysis of this macro will learn us that not all branches in the last +%D conditionals can be encountered, that is, some assignments to \type{\next} will +%D never occur. Nevertheless we implement the whole scheme, if not for future +%D extensions. + +%D \macros +%D {doassigncheckedframeoffset} +%D +%D Offset helper (see menus): + +\def\doassigncheckedframeoffset#1#2% could be a fast \csname .. \endcsname + {\edef\checkedframeoffset{#2}% + #1% + \ifx\checkedframeoffset\empty \zeropoint\orelse + \ifx\checkedframeoffset\v!overlay\zeropoint\orelse + \ifx\checkedframeoffset\v!none \zeropoint\orelse + \ifx\checkedframeoffset\v!frame \zeropoint\orelse + \ifx\checkedframeoffset\v!default\zeropoint\else + #2% + \fi + \relax} + +%D \macros +%D {ifreshapeframebox} +%D +%D The last few lines tell what to do after the content of the box is collected and +%D passed to the next macro. In the case of a fixed width and centered alignment, +%D the content is evaluated and used to determine the most natural width. The rest +%D of the code deals with backgrounds and frames. + +\newif\ifreshapeframebox \reshapeframeboxtrue + +%D Beware: setting \type {top} and \type {bottom} to nothing, may +%D result in a frame that is larger that the given height! try: +%D +%D \starttyping +%D \framed +%D [height=3cm,top=,bottom=,offset=overlay] +%D {\strut test \shapefill \strut test} +%D \stoptyping +%D +%D This is intended behaviour and not a bug! One can always set +%D +%D \starttyping +%D ...,bottom=\kern0pt,... +%D \stoptyping + +% experiment ... \p_framed_franalyze -> we could support 'first' as location key +% option but then we will always do an analysis and reimplement the location +% options (btw, beware of location settings of derived functionality that bleed +% into this + +\def\pack_framed_finish_a + {\ifreshapeframebox + \pack_framed_reshape_process + \orelse\ifx\p_framed_franalyze\v!yes + \pack_framed_reshape_analyze + \else + \pack_framed_reshape_reset + \fi + \setfalse\c_framed_has_width} + +\def\pack_framed_finish_b + {\ifx\p_framed_franalyze\v!yes + \pack_framed_reshape_analyze + \else + \pack_framed_reshape_reset + \fi + \setfalse\c_framed_has_width} + +\def\pack_framed_finish_c + {\ifx\p_framed_franalyze\v!yes + \pack_framed_reshape_analyze + \else + \pack_framed_reshape_reset + \fi} + +\def\pack_framed_profile_box + {\profilegivenbox\p_profile\b_framed_normal + \setbox\b_framed_normal\vpack{\unvbox\b_framed_normal}} + +\unexpanded\def\pack_framed_finish + {%\pack_framed_stop_orientation % hm, wrong place ! should rotate the result (after reshape) .. moved down + \pack_framed_locator_before\p_framed_location + \ifconditional\c_framed_has_format + %\ifconditional\c_framed_has_height \else + % \edef\p_profile{\framedparameter\c!profile}% + % \ifx\p_profile\empty\else + % \pack_framed_profile_box + % \fi + %\fi + \ifx\p_framed_autowidth\v!force + \pack_framed_finish_a + \orelse\ifx\localwidth\v!fit + \ifx\p_framed_autowidth\v!yes + \pack_framed_finish_a + \else + \pack_framed_finish_b + \fi + \orelse\ifx\localwidth\v!fixed + \pack_framed_finish_b + \else + \pack_framed_finish_c + \fi + \ifconditional\c_framed_has_height \else + \edef\p_profile{\framedparameter\c!profile}% + \ifx\p_profile\empty\else + \pack_framed_profile_box + \fi + \fi + \ifconditional\page_postprocessors_needed_box + % quite late + \page_postprocessors_linenumbers_box\b_framed_normal + \fi + \else + \pack_framed_finish_c + \fi + \ifconditional\c_framed_has_width + \wd\b_framed_normal\d_framed_width + \fi + \ifconditional\c_framed_has_height + \ht\b_framed_normal\d_framed_height + \else + \edef\p_framed_minheight{\framedparameter\c!minheight}% + \ifx\p_framed_minheight\empty \else + \ifdim\ht\b_framed_normal<\p_framed_minheight + \ht\b_framed_normal\p_framed_minheight + \fi + \fi + \fi + \edef\p_framed_empty{\framedparameter\c!empty}% + \ifx\p_framed_empty\v!yes + \pack_framed_fake_box + \fi + \ifx\p_framed_anchoring\empty\else + \pack_framed_handle_anchoring + \fi + \pack_framed_stop_orientation % moved here at 2014-05-25 + \iftrialtypesetting \else + \edef\m_overlay_region{\framedparameter\c!region}% + \ifx\m_overlay_region\empty\else + \pack_framed_set_region + \fi + \fi + \d_framed_applied_offset + \ifconditional\c_framed_is_overlaid + \zeropoint + \else + \d_framed_linewidth + \fi + \ifconditional\c_framed_has_offset + \advance\d_framed_applied_offset\localoffset + \fi + \ifconditional\c_framed_has_extra_offset + \pack_framed_apply_extra_offsets % includes \d_framed_applied_offset + \else + \ifzeropt\d_framed_applied_offset + \else + \pack_framed_widen_box + \fi + \fi + % + \ifx\postprocessframebox\relax \else + \let\next\postprocessframebox + \let\postprocessframebox\relax % prevent nesting + \next\b_framed_normal + \fi + \iftrialtypesetting + % new + \else + \ifconditional\c_framed_has_frame % real or invisible frame + \pack_framed_add_outline + \fi + \ifx\p_framed_background\empty \else + \edef\p_framed_component{\framedparameter\c!component}% + \pack_framed_add_background + \fi + \fi + \pack_framed_locator_after\p_framed_location + \iftrialtypesetting \else + \ifx\m_overlay_region\empty\else + \pack_framed_add_region + \fi + \fi + \box\b_framed_normal + \global\frameddimensionstate % global so to be used directly afterwards ! + \ifconditional\c_framed_has_width + \ifconditional\c_framed_has_height \plusthree \else \plusone \fi + \else + \ifconditional\c_framed_has_height \plustwo \else \zerocount \fi + \fi + \egroup + \egroup} + +%D Anchoring is experimental and was prototyped around the ctx meeting in 2018 but +%D never mede it into the core yet. It operates indepedent of the orientation +%D mechanism already present. + +\let\pack_framed_handle_anchoring\relax + +\installcorenamespace{framedlocatorbefore} +\installcorenamespace{framedlocatorafter} + +\newconstant\frameddimensionstate % global state: 0=unknown 1=width 2=height 3=both + +\def\pack_framed_fake_box + {\setbox\scratchbox\emptyhbox + \wd\scratchbox\wd\b_framed_normal + \ht\scratchbox\ht\b_framed_normal + \dp\scratchbox\dp\b_framed_normal + \setbox\b_framed_normal\box\scratchbox} + +\def\installframedlocator#1#2#3% + {\setvalue{\??framedlocatorbefore#1}{#2}% + \setvalue{\??framedlocatorafter #1}{#3}} + +\def\pack_framed_locator_before#1{\begincsname\??framedlocatorbefore#1\endcsname} +\def\pack_framed_locator_after #1{\begincsname\??framedlocatorafter #1\endcsname} + +\newdimen\d_framed_locator_ht +\newdimen\d_framed_locator_dp +\newdimen\d_framed_locator_lo +\newdimen\d_framed_locator_ro + +\def\pack_framed_locator_set#1% + {\d_framed_locator_ht\dimexpr + #1+\d_framed_linewidth + \ifconditional\c_framed_has_offset + +\framedparameter\c!offset + \fi + +\framedparameter\c!toffset + \relax + \d_framed_locator_dp\dimexpr\ht\b_framed_normal-\d_framed_locator_ht\relax} + +\def\pack_framed_locator_set_lo + {\global\d_framed_locator_lo\dimexpr + \d_framed_linewidth + \ifconditional\c_framed_has_offset + +\framedparameter\c!offset + \fi + +\framedparameter\c!loffset + \relax} + +\def\pack_framed_locator_set_ro + {\global\d_framed_locator_ro\dimexpr + \d_framed_linewidth + \ifconditional\c_framed_has_offset + +\framedparameter\c!offset + \fi + +\framedparameter\c!roffset + \relax} + +% \ruledhbox +% {A +% \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging} +% \framed[width=2cm,align=middle,location=depth] {location\\equals\\depth} +% \framed[width=2cm,align=middle,location=height] {location\\equals\\height} +% B} +% \vskip2cm +% \ruledhbox +% {A +% \framed[width=2cm,align=middle,location=low] {location\\equals\\low} +% \framed[width=2cm,align=middle,location=line] {location\\equals\\line} +% \framed[width=2cm,align=middle,location=high] {location\\equals\\high} +% B} +% \vskip2cm +% \ruledhbox +% {A +% \framed[width=2cm,align=middle,location=top] {location\\equals\\top} +% \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom} +% \framed[width=2cm,align=middle,location=lohi] {location\\equals\\lohi} +% \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle} +% B} + +% \installframedlocator \v!hanging % best with strut=no +% {} +% {\dp\b_framed_normal\ht\b_framed_normal +% \ht\b_framed_normal\zeropoint} +% +% \installframedlocator \v!depth +% {} +% {\ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax +% \dp\b_framed_normal\strutdp +% \box\b_framed_normal} +% +% \installframedlocator \v!height +% {} +% {\dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax +% \ht\b_framed_normal\strutht +% \box\b_framed_normal} + +\installframedlocator \v!hanging % best with strut=no *1* / see mail to list by SB + {} + {\scratchdimen\ht\b_framed_normal + \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}% + \dp\b_framed_normal\scratchdimen + \ht\b_framed_normal\zeropoint + \box\b_framed_normal} + +\installframedlocator \v!depth % *1* + {} + {\setbox\b_framed_normal\hpack{\lower\strutdp\box\b_framed_normal}% + \ht\b_framed_normal\dimexpr\ht\b_framed_normal-\strutdp\relax + \dp\b_framed_normal\strutdp + \box\b_framed_normal} + +\installframedlocator \v!height % *1* + {} + {\scratchdimen\dimexpr \ht\b_framed_normal - \strutht \relax + \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}% + \dp\b_framed_normal\dimexpr\ht\b_framed_normal-\strutht\relax + \ht\b_framed_normal\strutht + \box\b_framed_normal} + +\installframedlocator \v!high + {} + {\pack_framed_locator_set\strutht + \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}% + \ht\b_framed_normal\strutht + \dp\b_framed_normal\strutdp + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +\installframedlocator \v!line + {} + {\setbox\b_framed_normal\hpack{\lower.5\ht\b_framed_normal\box\b_framed_normal}% + \ht\b_framed_normal.5\lineheight + \dp\b_framed_normal.5\lineheight + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +\installframedlocator \v!low + {} + {\pack_framed_locator_set\strutdp + \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}% + \ht\b_framed_normal\strutht + \dp\b_framed_normal\strutdp + \box\b_framed_normal} + +\installframedlocator \v!top + {} + {\pack_framed_locator_set\strutht + \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}% + \ht\b_framed_normal\d_framed_locator_ht + \dp\b_framed_normal\d_framed_locator_dp + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +\installframedlocator \v!middle + {} + {\scratchdimen.5\ht\b_framed_normal + \setbox\b_framed_normal\hpack{\lower\scratchdimen\box\b_framed_normal}% + \ht\b_framed_normal\scratchdimen + \dp\b_framed_normal\scratchdimen + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +\installframedlocator \v!lohi % maybe also \v!center + {\pack_framed_locator_before\v!middle} + {\pack_framed_locator_after \v!middle} + +\installframedlocator \v!bottom + {} + {\pack_framed_locator_set\strutdp + \setbox\b_framed_normal\hpack{\lower\d_framed_locator_ht\box\b_framed_normal}% + \ht\b_framed_normal\d_framed_locator_dp + \dp\b_framed_normal\d_framed_locator_ht + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +\installframedlocator \v!keep % retains height/depth + {\pack_framed_remove_depth} + {\pack_framed_restore_depth} + +\newdimen\d_framed_formula + +\installframedlocator \v!formula % private, will become a more generic name + {} + {\pack_framed_locator_set\d_framed_formula + \setbox\b_framed_normal\hpack{\lower\d_framed_locator_dp\box\b_framed_normal}% + \ht\b_framed_normal\d_framed_locator_ht + \dp\b_framed_normal\d_framed_locator_dp + \hpack{\box\b_framed_normal}} % why do we pack .. dange of loosing? + +% also used in fastlocalframed + +\newdimen\d_framed_original_wd +\newdimen\d_framed_original_ht +\newdimen\d_framed_original_dp + +\def\pack_framed_remove_depth + {\d_framed_original_wd\wd\b_framed_normal + \d_framed_original_ht\ht\b_framed_normal + \d_framed_original_dp\dp\b_framed_normal + \ifzeropt\d_framed_original_dp\else + \setbox\b_framed_normal\hpack{\raise\d_framed_original_dp\box\b_framed_normal}% + \fi + \wd\b_framed_normal\d_framed_original_wd + \ht\b_framed_normal\dimexpr\d_framed_original_ht+\d_framed_original_dp\relax + \dp\b_framed_normal\zeropoint} + +\def\pack_framed_restore_depth + {\ifzeropt\d_framed_original_dp \else + \setbox\b_framed_normal\hpack{\lower\d_framed_original_dp\box\b_framed_normal}% + \fi + \wd\b_framed_normal\d_framed_original_wd + \ht\b_framed_normal\d_framed_original_ht + \dp\b_framed_normal\d_framed_original_dp} + +% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax} +% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax} + +\def\pack_framed_start_orientation + {\ifcase\p_framed_orientation + \let\pack_framed_stop_orientation\relax + \else + \let\pack_framed_stop_orientation\pack_framed_stop_orientation_indeed + \fi} + +\def\pack_framed_stop_orientation_indeed + {\setbox\b_framed_normal\hpack{\dorotatebox\p_framed_orientation\hpack{\box\b_framed_normal}}% + \d_framed_height\ht\b_framed_normal + \d_framed_width \wd\b_framed_normal} + +%D The last conditional takes care of the special situation of in||line \inframed +%D [height=3cm] {framed} boxes. Such boxes have to be \inframed {aligned} with the +%D running text. + +\unexpanded\def\inframed + {\dosingleempty\pack_framed_inline} + +% \def\pack_framed_inline[#1]% +% {\framed[\c!location=\v!low,#1]} +% +% or: + +\def\pack_framed_inline[% + {\framed[\c!location=\v!low,} + +%D When we set \type{empty} to \type{yes}, we get ourselves a frame and/or background, +%D but no content, so actually we have a sort of phantom framed box. + +%D \macros +%D {mframed, minframed} +%D +%D When Tobias asked how to frame mathematical elements in formulas, Taco's posted the +%D next macro: +%D +%D \starttyping +%D \def\mframed#1% +%D {\relax +%D \ifmmode +%D \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}% +%D \else +%D \framed{$#1$}% +%D \fi} +%D \stoptyping +%D +%D Because \type {\ifinner} does not (always) reports what one would expect, we move the +%D test to the outer level. We also want to pass arguments, +%D +%D \starttyping +%D \def\mframed% +%D {\dosingleempty\domframed} +%D +%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ? +%D {\relax +%D \ifmmode +%D \ifinner +%D \inframed[#1]{$#2$}% +%D \else +%D \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}% +%D \fi +%D \else +%D \inframed[#1]{$#2$}% +%D \fi} +%D \stoptyping +%D +%D Still better is the next alternative, if only because it takes care of setting the super- +%D and subscripts styles + +\newcount\c_framed_mstyle + +\unexpanded\def\pack_framed_math_strut + {\Ustartmath + \triggermathstyle\c_framed_mstyle + \vphantom{(}% + \Ustopmath} + +\installcorenamespace{mathframed} + +\installframedcommandhandler \??mathframed {mathframed} \??mathframed + +\appendtoks + \setuevalue{\currentmathframed}{\pack_framed_mathframed{\currentmathframed}}% +\to \everydefinemathframed + +\unexpanded\def\pack_framed_mathframed#1% + {\begingroup + \edef\currentmathframed{#1}% + \dosingleempty\pack_framed_mathframed_indeed} + +\newcount\c_pack_framed_mathframed +\newtoks \t_pack_framed_mathframed + +\def\pack_framed_math_pos + {\global\advance\c_pack_framed_mathframed\plusone + \xdef\pack_framed_mc_one{mcf:1:\number\c_pack_framed_mathframed}% + \xdef\pack_framed_mc_two{mcf:2:\number\c_pack_framed_mathframed}% + \xypos\pack_framed_mc_two} + +\def\pack_framed_mathframed_indeed[#1]#2% no fancy nesting supported here + {\iffirstargument + \setupcurrentmathframed[#1]% + \fi + \c_framed_mstyle\mathstyle + \edef\m_framed_location{\mathframedparameter\c!location}% + \ifx\m_framed_location\v!mathematics + \let\normalstrut\pack_framed_math_pos + \orelse\ifx\m_framed_location\v!low\else + \let\normalstrut\pack_framed_math_strut + \fi + \inheritedmathframedframed\bgroup + \Ustartmath + \triggermathstyle\c_framed_mstyle + \the\t_pack_framed_mathframed + #2% + \Ustopmath + \egroup + \endgroup} + +\appendtoks + \mathraggedstatus\plustwo % makes \startalign work + \eqalignmode \zerocount % makes \startalign fit +\to \t_pack_framed_mathframed + +\installframedlocator \v!mathematics + {} + {\lower\dimexpr\MPy\pack_framed_mc_two-\MPy\pack_framed_mc_one\relax + \hpack{\xypos\pack_framed_mc_one\box\b_framed_normal}} + +\definemathframed[mframed] +\definemathframed[inmframed][\c!location=\v!low] +\definemathframed[mcframed] [\c!location=\v!mathematics] + +%D So instead of the rather versatile \type {\framed}, we use \type {\mframed}: +%D +%D \startbuffer +%D \startformula +%D x \times \mframed{y} \times y^{z_z} +%D x \times \inmframed{y} \times y^{z_z} +%D \stopformula +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D And: +%D +%D \startbuffer +%D \startformula +%D x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}} +%D \stopformula +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D As usual, one can specify in what way the text should be framed. One should be +%D aware of the fact that, inorder to preserve the proper spacing, the \type +%D {offset} is set to \type {overlay} and \type {frameoffset} is used used instead. +%D +%D \startbuffer +%D \startformula +%D x \times y^{\mframed[framecolor=red]{z}_{z}} +%D \stopformula +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D For inline use, we also provide the \type {\inmframed} alternative: we want $x +%D \times \inmframed{y}$ in inline math, right? + +%D This previous framing macros needs a lot of alternatives for putting rules around +%D boxes, inserting offsets and aligning text. Each step is handled by separate macros. + +\newdimen\d_framed_applied_offset +\newdimen\d_framed_loffset +\newdimen\d_framed_roffset +\newdimen\d_framed_toffset +\newdimen\d_framed_boffset + +\def\pack_framed_check_extra_offsets % we could check h and v indepently + {\setfalse\c_framed_has_extra_offset + \d_framed_loffset\framedparameter\c!loffset\relax + \d_framed_roffset\framedparameter\c!roffset\relax + \d_framed_toffset\framedparameter\c!toffset\relax + \d_framed_boffset\framedparameter\c!boffset\relax + \ifzeropt\d_framed_loffset\else \advance\d_framed_width -\d_framed_loffset \settrue\c_framed_has_extra_offset \fi + \ifzeropt\d_framed_roffset\else \advance\d_framed_width -\d_framed_roffset \settrue\c_framed_has_extra_offset \fi + \ifzeropt\d_framed_toffset\else \advance\d_framed_height-\d_framed_toffset \settrue\c_framed_has_extra_offset \fi + \ifzeropt\d_framed_boffset\else \advance\d_framed_height-\d_framed_boffset \settrue\c_framed_has_extra_offset \fi} + +\def\pack_framed_apply_extra_offsets + {\setbox\b_framed_normal\vpack\bgroup + \advance\d_framed_toffset\d_framed_applied_offset + \advance\d_framed_boffset\d_framed_applied_offset + \advance\d_framed_loffset\d_framed_applied_offset + \advance\d_framed_roffset\d_framed_applied_offset + \kern\d_framed_toffset + \hpack\bgroup + \kern\d_framed_loffset + \box\b_framed_normal + \kern\d_framed_roffset + \egroup + \kern\d_framed_boffset + \egroup} + +\def\pack_framed_widen_box + {\setbox\b_framed_normal\vpack + {\kern\d_framed_applied_offset + \hpack{\kern\d_framed_applied_offset\box\b_framed_normal\kern\d_framed_applied_offset}% + \kern\d_framed_applied_offset}} + +%D Let's hope that the next few examples show us enough of what needs to be +%D done by the auxiliary macros. +%D +%D \startbuffer +%D \framed[height=1cm,offset=.5cm] {rule based learning} +%D \framed[height=1cm,offset=0cm] {rule based learning} +%D \framed[height=1cm,offset=none] {rule based learning} +%D \framed[height=1cm,offset=overlay]{rule based learning} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlinecorrection +%D \hbox{\getbuffer} +%D \stoplinecorrection +%D +%D \startbuffer +%D \framed[offset=.5cm] {rule based learning} +%D \framed[offset=0cm] {rule based learning} +%D \framed[offset=none] {rule based learning} +%D \framed[offset=overlay]{rule based learning} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlinecorrection +%D \hbox{\getbuffer} +%D \stoplinecorrection +%D +%D \startbuffer +%D \framed[strut=no,offset=.5cm] {rule based learning} +%D \framed[strut=no,offset=0cm] {rule based learning} +%D \framed[strut=no,offset=none] {rule based learning} +%D \framed[strut=no,offset=overlay]{rule based learning} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlinecorrection +%D \hbox{\getbuffer} +%D \stoplinecorrection +%D +%D \startbuffer +%D \framed[width=3cm,align=left] {rule\\based\\learning} +%D \framed[width=3cm,align=middle] {rule\\based\\learning} +%D \framed[width=3cm,align=right] {rule\\based\\learning} +%D \framed[width=fit,align=middle] {rule\\based\\learning} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlinecorrection +%D \hbox{\dontcomplain\getbuffer} +%D \stoplinecorrection +%D +%D So now we're ready for the complicated stuff. We distinguish between borders with +%D straight lines and those with round corners. When using the first alternative it +%D is possible to turn off one or more lines. More fancy shapes are also possible by +%D specifying dedicated backgrounds. Turning lines on and off is implemented as +%D efficient as possible and as a result is interface language dependant. This next +%D implementation evolved from simpler ones. It puts for instance the rules on top +%D of the content and provides additional offset capabilities. The lot of calls to +%D other macros makes this mechanism not that easy to comprehend. +%D +%D We handle left, right or middle alignment as well as fixed or free widths and +%D heights. Each combination gets its own macro. +%D +%D The following code handles one-liners: \type {align={line,flushright}}. Beware, +%D since we entered a group and either or not grab the next bgroup token, we need to +%D finish the group in the oneliner mode. + +\ifdefined\raggedonelinerstate \else \newconditional\raggedonelinerstate \fi + +\def\doformatonelinerbox % beware: assumes explicit preceding bgroup + {\ifconditional\raggedonelinerstate + \expandafter\dodoformatonelinerbox + \else + \expandafter\nodoformatonelinerbox + \fi} + +\def\dodoformatonelinerbox + {\afterassignment\redoformatonelinerbox + \setbox\nextbox\hbox} % maybe \hpack + +\def\redoformatonelinerbox + {\aftergroup\dododoformatonelinerbox + \ignorespaces} + +\def\dododoformatonelinerbox + {\hpack to \hsize % was \hbox + {\ifcase\raggedstatus\or\hss\or\hss \fi + \unhbox\nextbox \removeunwantedspaces + \ifcase\raggedstatus\or \or\hss\or\hss\fi}% + \egroup} + +\def\nodoformatonelinerbox % grabs { + {\let\next=} + +%D The handlers: + +% Beware, we have a \noindent so an empty line is indeed an empty line and +% the \synchronizeinlinedirection triggers a vbox instead of a line. +% +% \startTEXpage[offset=0.5ex,align={lohi,middle}] +% +% \vbox{\hbox{x}} +% \stopTEXpage +% +% \startTEXpage[offset=0.5ex,align={lohi,middle}] +% \vbox{\hbox{x}} +% \stopTEXpage + +% \def\pack_framed_forgetall{\forgetall} + +\def\pack_framed_set_foregroundcolor + {\edef\p_framed_foregroundcolor{\framedparameter\c!foregroundcolor}% + \ifx\p_framed_foregroundcolor\empty\else\dousecolorparameter\p_framed_foregroundcolor\fi} + +\def\pack_framed_do_setups + {\ifx\p_framed_setups\empty \else + \setups[\p_framed_setups]% \texsetup (or only one!) + % \fastsetup\p_framed_setup % singular would have been better + \fi} + +\def\pack_framed_format_format_yes + {\vbox to \d_framed_height + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \oninterlineskip + \hsize\d_framed_width + \vsize\d_framed_height + \pack_framed_do_setups + \raggedcommand + \pack_framed_do_top + \bgroup + \synchronizeinlinedirection + \localbegstrut + \aftergroup\localendstrut + \aftergroup\pack_framed_do_bottom + \aftergroup\egroup + \doformatonelinerbox} + +\def\pack_framed_format_format_nop + {\vbox to \d_framed_height + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \oninterlineskip + \hsize\d_framed_width + \vsize\d_framed_height + \pack_framed_do_setups + \raggedcenter + \vss + \bgroup + \synchronizeinlinedirection + \localbegstrut + \aftergroup\localendstrut + \aftergroup\vss + \aftergroup\egroup + \doformatonelinerbox} + +\def\pack_framed_format_format_height + {\vbox to \d_framed_height + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \oninterlineskip + \pack_framed_do_setups + \raggedcommand + \vss + \bgroup + \aftergroup\localendstrut + \aftergroup\vss + \aftergroup\egroup + \synchronizeinlinedirection + \localbegstrut + \doformatonelinerbox} + +\def\pack_framed_format_format_width + {\vbox + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \oninterlineskip + \hsize\d_framed_width + \pack_framed_do_setups + \raggedcommand + \pack_framed_do_top + \bgroup + \synchronizeinlinedirection + \localbegstrut + \aftergroup\localendstrut + \aftergroup\pack_framed_do_bottom + \aftergroup\egroup + \doformatonelinerbox} + +\def\pack_framed_format_format_vsize + {\vbox to \d_framed_height % no vpack .. maybe grid + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \vsize\d_framed_height + \pack_framed_do_setups + \vss + \bgroup + \aftergroup\vss + \aftergroup\egroup + \hbox + \bgroup + \aftergroup\egroup + \synchronizeinlinedirection + \localstrut + \doformatonelinerbox} + +\def\pack_framed_format_format_hsize + {\hbox to \d_framed_width + \bgroup + \let\postprocessframebox\relax + % \pack_framed_forgetall + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \pack_framed_do_setups + \hss + \synchronizeinlinedirection + \localstrut + \bgroup + \aftergroup\hss + \aftergroup\egroup + \doformatonelinerbox} + +\def\pack_framed_format_format_no_size + {\hbox + \bgroup + \iftrialtypesetting \else + \pack_framed_set_foregroundcolor + \fi + \let\postprocessframebox\relax + \pack_framed_do_setups + \synchronizeinlinedirection + \localstrut + \doformatonelinerbox} + +%D On the next page we show some examples of how these macros come into action. The +%D examples show us how \type {fit}, \type {broad} dimensions influence the +%D formatting. Watch the visualized struts. \footnote {Here we used \type +%D {\showstruts}.} +%D +%D \startpostponing +%D \bgroup +%D \showstruts +%D \dontcomplain +%D \starttabulate[|c|c|c|c|c|c|] +%D % \HL +%D \NC \framed[width=.2\hsize, height=.2\hsize, align=] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=broad, align=] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=fit, align=] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=.2\hsize, align=] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=broad, align=] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=fit, align=] {a\endgraf b\endgraf c} +%D \NC \NR +%D % \HL +%D \NC \framed[width=.2\hsize, height=.2\hsize, align=yes] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=broad, align=yes] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=fit, align=yes] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=.2\hsize, align=yes] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=broad, align=yes] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=fit, align=yes] {a\endgraf b\endgraf c} +%D \NC \NR +%D % \HL +%D \NC \framed[width=.2\hsize, height=.2\hsize, align=right] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=broad, align=right] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=fit, align=right] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=.2\hsize, align=right] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=broad, align=right] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=fit, align=right] {a\endgraf b\endgraf c} +%D \NC \NR +%D % \HL +%D \NC \framed[width=.2\hsize, height=.2\hsize, align=left] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=broad, align=left] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=fit, align=left] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=.2\hsize, align=left] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=broad, align=left] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=fit, align=left] {a\endgraf b\endgraf c} +%D \NC \NR +%D % \HL +%D \NC \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=broad, align=middle] {a\endgraf b\endgraf c} +%D \NC \framed[width=.2\hsize, height=fit, align=middle] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=.2\hsize, align=middle] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=broad, align=middle] {a\endgraf b\endgraf c} +%D \NC \framed[width=fit, height=fit, align=middle] {a\endgraf b\endgraf c} +%D \NC \NR +%D % \HL +%D \stoptabulate +%D \egroup +%D \stoppostponing + +%D \macros +%D {framednoflines, framedlastlength} +%D +%D It is possible to let the frame macro calculate the width of a centered box +%D automatically (\type {fit}). When doing so, we need to reshape the box: + +\newcount\framednoflines +\newdimen\framedfirstheight +\newdimen\framedlastdepth +\newdimen\framedminwidth +\newdimen\framedmaxwidth +\newdimen\framedaveragewidth + +\def\pack_framed_reshape_reset + {\framednoflines \zerocount + \framedfirstheight \zeropoint + \framedlastdepth \zeropoint + \framedminwidth \zeropoint + \framedmaxwidth \zeropoint + \framedaveragewidth\zeropoint} + +\def\pack_framed_reshape_process{\ifvbox\b_framed_normal\clf_doreshapeframedbox\b_framed_normal\relax\fi} +\def\pack_framed_reshape_analyze{\ifvbox\b_framed_normal\clf_doanalyzeframedbox\b_framed_normal\relax\fi} + +% torture test / strange case (much depth) / method 2 needed +% +% \startTEXpage[frame=on] +% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula +% test outside formula +% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula +% \blank[big] +% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula +% test outside formula +% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula +% \stopTEXpage + +%D The examples on the next page show how one can give the frame as well as the +%D background an additional offset and even a bit more depth. The blue outline is +%D the frame, the red box is the background and the small black outline is the +%D visualization of the resulting box, that is, we applied \type {\ruledhbox} to +%D the result. +%D +%D \startpostponing +%D \bgroup +%D \unprotect +%D \dontcomplain +%D +%D \startbuffer +%D \unprotect +%D \vbox to \vsize +%D \bgroup +%D \startalignment[middle] +%D \vss +%D \dontleavehmode\vbox to .8\vsize +%D \bgroup +%D \hsize=300pt +%D \setupframed +%D [background=color, +%D backgroundcolorachtergrondkleur=darkred, +%D width=300pt, +%D height=60pt, +%D framecolorkaderkleur=DemoBlue, +%D rulethickness=2pt] +%D \def\status% +%D {backgroundoffset=\the\dimexpr\framedparameter\c!backgroundoffset\relax\\ +%D frameoffset=\the\dimexpr\framedparameter\c!frameoffset\relax\\ +%D depth=\the\dimexpr\framedparameter\c!depth\relax} +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}} +%D \vss +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}} +%D \vss +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}} +%D \vss +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}} +%D \vss +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}} +%D \vss +%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}} +%D \egroup +%D \vss +%D \stopalignment +%D \egroup +%D \protect +%D \stopbuffer +%D +%D \getbuffer \page +%D +%D {\setupframed[depth=4pt]\getbuffer} \page +%D +%D \protect +%D \egroup +%D \stoppostponing + +%D We can draw lines from left to right and top to bottom by using the normal \type +%D {\hairline} command. Both directions need a different treatment. +%D +%D \startbuffer +%D \framed[width=4cm] {alfa\hairline beta\hairline gamma} +%D \framed[height=2cm] {alfa\hairline beta\hairline gamma} +%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlinecorrection +%D \hbox{\getbuffer} +%D \stoplinecorrection +%D +%D These macros try to adapt their behaviour as good as possible to the circumstances +%D and act as natural as possible. + +\unexpanded\def\pack_framed_vboxed_hairline % nasty overlay mess .. needed for autowidth + {\begingroup + \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi + \scratchwidth \dimexpr\scratchoffset+\d_framed_linewidth\relax + \par + \nointerlineskip + \kern\scratchoffset + \dontleavehmode + \hrule\s!height\d_framed_linewidth\s!depth\zeropoint + \par + \kern-\d_framed_linewidth + \dontleavehmode + \hpack to \zeropoint{\hss\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth}% + \hfill + \hpack to \zeropoint{\vrule\s!height\d_framed_linewidth\s!depth\zeropoint\s!width\scratchwidth\hss}% + \par + \nointerlineskip + \kern\scratchoffset + \nointerlineskip + \endgraf + \nointerlineskip + \localbegstrut + \endgroup} + +\unexpanded\def\pack_framed_hboxed_hairline % use framed dimen + {\bgroup + \scratchoffset\ifconditional\c_framed_has_offset \localoffset \else \zeropoint \fi + \ifconditional\c_framed_has_height + \dimen\scratchheight\dimexpr\localheight/\plustwo+\strutdp-\plustwo\d_framed_linewidth\relax + \dimen\scratchdepth \dimexpr\localheight/\plustwo-\strutdp+\plustwo\d_framed_linewidth\relax + \else + \dimen\scratchheight\dimexpr\strutht+\scratchoffset\relax + \dimen\scratchdepth \dimexpr\strutdp+\scratchoffset\relax + \fi + \unskip + \setbox\scratchbox\hpack + {\kern\scratchoffset + \vrule\s!height\dimen\scratchheight\s!depth\dimen\scratchdepth\s!width\d_framed_linewidth + \kern\scratchoffset}% + \ht\scratchbox\strutht + \dp\scratchbox\strutdp + \box\scratchbox + \ignorespaces + \egroup} + +%D The argument of the frame command accepts \type{\\} as a sort of newline signal. In +%D horizontal boxes it expands to a space. + +\unexpanded\def\pack_framed_vboxed_newline + {\endgraf\ignorespaces} + +\unexpanded\def\pack_framed_hboxed_newline + {\unskip\normalspace\ignorespaces} + +%D We can set each rule on or off. The default setting is inherited from +%D \type {frame}. An earlier implementation use a bit different approach, but the new +%D one seems more natural: +%D +%D \bgroup +%D \setuptyping[margin=0pt] +%D \startlinecorrection +%D \startbuffer +%D \framed[offset=overlay,frame=on]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D +%D \startbuffer +%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D +%D \startbuffer +%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D +%D \startbuffer +%D \framed[offset=overlay,frame=off]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D +%D \startbuffer +%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D +%D \startbuffer +%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule} +%D \stopbuffer +%D \hbox{\getbuffer\vbox{\typebuffer}} +%D \stoplinecorrection +%D \egroup + +%D \macros +%D {startframedtext, setupframedtexts, defineframedtext} +%D +%D The general framing command we discussed previously, is not entirely suited for +%D what we call framed texts, as for instance used in intermezzo's. The next +%D examples show what we have in mind. +%D +%D \startbuffer[framed-0] +%D \setupframedtexts +%D [frame=off, +%D width=\hsize, +%D background=screen] +%D +%D \startframedtext +%D By default the framed text is centered \dots +%D \stopframedtext +%D +%D \startframedtext[right] +%D \dots\ but we can also align left, middle and right. +%D \stopframedtext +%D \stopbuffer +%D +%D \startbuffer[framed-1] +%D \defineframedtext +%D [Example] +%D [width=6cm, +%D height=5cm] +%D +%D \startExample +%D \typebuffer[framed-1] +%D \stopExample +%D \stopbuffer +%D +%D \startbuffer[framed-2] +%D \defineframedtext +%D [Example] +%D [width=6cm] +%D +%D \startExample +%D \typebuffer[framed-2] +%D \stopExample +%D \stopbuffer +%D +%D \startbuffer[framed-3] +%D \defineframedtext +%D [Example] +%D [height=5cm] +%D +%D \startExample +%D \typebuffer[framed-3] +%D \stopExample +%D \stopbuffer +%D +%D \startbuffer[framed-4] +%D \defineframedtext +%D [Example] +%D [width=fit,height=broad] +%D +%D \Example{a very exciting example} +%D \stopbuffer +%D +%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup +%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup +%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup +%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup +%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup +%D +%D Here we can see that we have a predefined framed text class as well as the +%D tools for defining our own. So we have: +%D +%D \showsetup{setupframedtexts} +%D +%D as well as the definition command: +%D +%D \showsetup{defineframedtext} +%D +%D that generates two commands: +%D +%D \showsetup{start<>} +%D \showsetup{<>} +%D +%D The next definition shows the defaults. + +\installcorenamespace{framedtext} +\installcorenamespace{framedtextlocation} + +\installframedcommandhandler \??framedtext {framedtext} \??framedtext + +\let\setupframedtexts\setupframedtext + +\setupframedtext + [\c!width=.75\hsize, + \c!height=\v!fit, + \c!align=\v!yes, + %\c!top=, + \c!bottom=\vfill, + \c!offset=1em, + %\c!bodyfont=, + %\c!style=, + %\c!color=, + %\c!left=, + \c!right=\hfill, + \c!before=\blank, + \c!after=\blank, + %\c!inner=, + \c!frame=\v!on, + %\c!topframe=, + %\c!bottomframe=, + %\c!leftframe=, + %\c!rightframe=, + \c!radius=.5\bodyfontsize, + \c!corner=\v!rectangular, + %\c!orientation=, + %\c!indenting=, + %\c!foregroundcolor=, + %\c!foregroundstyle=, + %\c!background=, + %\c!backgroundcolor=, + \c!linecorrection=\v!on, + \c!depthcorrection=\v!on, + \c!margin=\v!standard] + +\appendtoks + \setuevalue{\e!start\currentframedtext}{\pack_framed_text_start {\currentframedtext}}% + \setuevalue{\e!stop \currentframedtext}{\pack_framed_text_stop }% + \setuevalue {\currentframedtext}{\pack_framed_text_direct{\currentframedtext}}% +\to \everydefineframedtext + +\setvalue{\??framedtextlocation\v!left }{\letframedtextparameter\c!left \relax + \letframedtextparameter\c!right\hfill} + +\setvalue{\??framedtextlocation\v!right }{\letframedtextparameter\c!left \hfill + \letframedtextparameter\c!right\relax} + +\setvalue{\??framedtextlocation\v!middle}{\letframedtextparameter\c!left \hfill + \letframedtextparameter\c!right\hfill} + +\setvalue{\??framedtextlocation\v!none }{\letframedtextparameter\c!left \relax + \letframedtextparameter\c!right\relax + \settrue\c_framed_text_location_none} + +\unexpanded\def\pack_framed_text_start#1% + {\bgroup + \edef\currentframedtext{#1}% + \dodoubleempty\pack_framed_text_start_indeed} + +\def\pack_framed_text_start_indeed[#1][#2]% + {\doifelseassignment{#1} + {\pack_framed_text_start_continue\empty{#1}} + {\pack_framed_text_start_continue{#1}{#2}}} + +% todo: sort out first/lastline ht/dp + +\def\pack_framed_text_start_continue#1#2% + {\setupframedtexts[\currentframedtext][#2]% + \doifsomething{#1}{\setframedtextparameter\c!location{#1}}% does not listen to #3 + \setfalse\c_framed_text_location_none + \csname\??framedtextlocation\framedtextparameter\c!location\endcsname + \resetframedtextparameter\c!location + \pack_framed_text_check + \setbox\b_framed_normal\vbox % \vpack + \startboxedcontent + \hsize\localhsize + % \insidefloattrue % ? better + \usebodyfontparameter\framedtextparameter + % \edef\p_framed_text_strut{\letframedtextparameter\c!strut}% to be used + \letframedtextparameter\c!strut\v!no + \inheritedframedtextframed\bgroup + \let\\=\endgraf + \edef\p_framed_text_depthcorrection{\framedtextparameter\c!depthcorrection}% + \ifx\p_framed_text_depthcorrection\v!on + \pack_framed_text_start_depth_correction + \else + \bgroup + \fi + \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1 + \doinhibitblank + \useindentingparameter\framedtextparameter + \useframedtextstyleandcolor\c!style\c!color + \framedtextparameter\c!inner + \ignorespaces} + +% testcase 1: +% +% \showstruts +% \startframedtext[align={normal,tolerant},offset=0pt] \input tufte \stopframedtext +% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \input tufte \stopframedtext +% \startframedtext[align={normal,tolerant},offset=0pt,depthcorrection=off] \inframed{x} \stopframedtext +% \framed[align={normal,tolerant},offset=0pt]{\input tufte } + +%D The \type {none} option is handy for nested usage, as in the presentation +%D styles, where we don't want interference. + +\defineplacement[\??framedtext][\s!parent=\??framedtext\currentframedtext] + +\unexpanded\def\pack_framed_text_stop % no \baselinecorrection, see faq docs + {\endgraf + \removelastskip + \ifx\p_framed_text_depthcorrection\v!on + \pack_framed_text_stop_depth_correction + \else + \egroup + \fi + \stopboxedcontent + \ifconditional\c_framed_text_location_none + \egroup + \box\b_framed_normal + \orelse\ifinsidefloat + \egroup + \box\b_framed_normal + \else + \egroup + \placement[\??framedtext][\c!depthcorrection=\v!off]{\box\b_framed_normal}% + \fi + \egroup} + +%D We define the general (and original) case by just saying: + +\def\pack_framed_text_check % messy dependency + {\localhsize\hsize + \ifinsidefloat \orelse \ifdim\d_page_sides_vsize>\zeropoint % also possible: \c_page_sides_checks_done>\zeropoint + % \strut % rather clean way to invoke the sidefloat OTR + % \setbox0=\lastbox % and get the widths set, so from now on we + % \setlocalhsize % can have framed texts alongside sidefloats + \checksidefloat + \setlocalhsize + \fi} + +\def\pack_framed_text_start_depth_correction + {\bgroup + \ifhmode + \par + \fi + \ifvmode + \verticalstrut + % we need \nowhitespace in case of setups setting whitespace + % nb, not safe, text vs \vbox as next + \vskip-\struttotal + \nowhitespace + \fi} % na vskip ! new 20/05/2004, fails with next content being box (\scale{..}) + +\def\pack_framed_text_stop_depth_correction + {\ifhmode + \par + \fi + \ifvmode + \forgetall + \vskip-\struttotal + \verticalstrut + \egroup + \forgetall % brrr too often + \vskip-\lineheight + \verticalstrut + \else + \egroup + \fi} + +%D Placement can be ignored: +%D +%D \starttyping +%D \hbox to \hsize \bgroup +%D \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext +%D \startframedtext[none][width=.5\textwidth] \input zapf \stopframedtext +%D \egroup +%D +%D \hbox to \hsize \bgroup +%D \setupframedtexts[location=none]% +%D \startframedtext[width=.5\textwidth] \input zapf \stopframedtext +%D \startframedtext[width=.5\textwidth] \input tufte \stopframedtext +%D \egroup +%D \stoptyping + +%D The simple brace (or group) delimited case is typeset slightly different +%D and is not aligned. + +\unexpanded\def\pack_framed_text_direct#1% + {\bgroup + \edef\currentframedtext{#1}% + \dosingleempty\pack_framed_text_start_direct} + +\def\pack_framed_text_start_direct[#1]% + {\usebodyfontparameter\framedtextparameter + \iffirstargument + \setupcurrentframedtext[#1]% + \fi + \edef\p_framed_text_strut{\framedtextparameter\c!strut}% + \letframedtextparameter\c!strut\v!no + \inheritedframedtextframed\bgroup + \blank[\v!disable]% + \let\\=\endgraf + \useframedtextstyleandcolor\c!style\c!color + \vskip-\strutdp % brrr why is this needed ... needs to be sorted out, see testcase 1 + \framedtextparameter\c!inner + \ifx\p_framed_text_strut\v!no + \let\pack_framed_strut\relax + \else + \let\pack_framed_strut\strut + \fi + \bgroup + \aftergroup\pack_framed_text_stop_direct + \afterassignment\ignorespaces + \afterassignment\pack_framed_strut + \let\next=} + +\def\pack_framed_text_stop_direct + {\removelastskip + \egroup + \egroup} + +\defineframedtext + [\v!framedtext] + +%D \macros +%D {defineframed} +%D +%D One can also define simple framed texts, using: +%D +%D \showsetup{defineframed} +%D +%D As suggested by Wolfgang we can now use the new \MKIV\ inheritance model instead +%D of passing a combination of arguments. This also also simplified the \type +%D {\setupframed} command. There are certainly more places where such improvements +%D can be made. + +\appendtoks + \ifcsname\??regularframedlevel\currentframed\endcsname + % already defined, keeps settings + \else + \expandafter\newcount\csname\??regularframedlevel\currentframed\endcsname + \fi +\to \everypresetframed + +\appendtoks + \setuevalue\currentframed{\pack_framed_defined_process[\currentframed]}% +\to \everydefineframed + +\newcount\c_temp_framed_crap + +\unexpanded\def\pack_framed_defined_process[#1]% official (not much checking, todo: parent) + {\bgroup + \ifcsname\??regularframedlevel#1\endcsname + %\expandafter\let\expandafter\c_pack_framed_temp\csname\??regularframedlevel#1\endcsname + \expandafter\let\expandafter\c_pack_framed_temp\lastnamedcs + \else + \let\c_pack_framed_temp\c_temp_framed_crap + \fi + \advance\c_pack_framed_temp\plusone + \expandafter\def\csname\??framed#1>\the\c_pack_framed_temp:\s!parent\endcsname{\??framed#1}% \inheritlocalframed + \bgroup + \edef\currentframed{#1>\the\c_pack_framed_temp}% + \pack_framed_initialize + \dosingleempty\pack_framed_defined_process_indeed} + +\def\pack_framed_defined_process_indeed[#1]% + {\iffirstargument % faster + \setupcurrentframed[#1]% here ! + \fi + \pack_framed_process_indeed} + +\let\placeframed\pack_framed_defined_process % new per 2012/04/23 + +%D We can do: +%D +%D \starttyping +%D \defineframed[\v!framed] +%D \stoptyping +%D +%D but the existing one is ok as well (less csname messy too). + +%D New, for the moment private; let's see when GB finds out about this one and its +%D obscure usage. It's used in: +%D +%D \startbuffer +%D \defineframedtext +%D [tabulateframe] +%D [offset=overlay, +%D backgroundoffset=3pt, +%D background=color, +%D backgroundcolor=green] +%D +%D \setuptabulate +%D [tabulate] +%D [frame=tabulateframe] +%D +%D \setuptables +%D [frame=tabulateframe] +%D +%D \input tufte +%D +%D \starttabulate[|l|l|] +%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR +%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR +%D \stoptabulate +%D +%D \input tufte +%D +%D \starttable[|l|l|] +%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR +%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR +%D \stoptable +%D \stopbuffer +%D +%D \typebuffer + +\installcorenamespace{framedcontent} + +\installframedcommandhandler \??framedcontent {framedcontent} \??framedcontent + +\setupframedcontent + [\c!leftoffset=\zeropoint, + %\c!rightoffset=\framedcontentparameter\c!leftoffset, + \c!rightoffset=\scratchleftoffset, + \c!topoffset=\zeropoint, + %\c!bottomoffset=\framedcontentparameter\c!topoffset, + \c!bottomoffset=\scratchtopoffset, + \c!strut=\v!no, + %\c!linecorrection=\v!no, + %\c!left=, + %\c!right=, + %\c!width=\v!fit, + \c!offset=\v!overlay] + +\unexpanded\def\startframedcontent + {\dosingleempty\pack_framed_start_content} + +\def\pack_framed_start_content[#1]% + {\bgroup + \edef\currentframedcontent{#1}% + \ifx\currentframedcontent\v!off + \let\stopframedcontent\egroup + \else + \checkframedcontentparent + \let\stopframedcontent\pack_framed_stop_content_indeed + \expandafter\pack_framed_start_content_indeed + \fi} + +\def\pack_framed_start_content_indeed + {\setbox\b_framed_normal\hpack\bgroup + \setlocalhsize + \hsize\localhsize + \scratchleftoffset \framedcontentparameter\c!leftoffset \relax + \scratchrightoffset \framedcontentparameter\c!rightoffset \relax + \scratchtopoffset \framedcontentparameter\c!topoffset \relax + \scratchbottomoffset\framedcontentparameter\c!bottomoffset\relax + \advance\hsize\dimexpr-\scratchleftoffset-\scratchrightoffset \relax + \advance\vsize\dimexpr-\scratchtopoffset -\scratchbottomoffset\relax + \kern\scratchleftoffset + \vpack\bgroup + \vskip\scratchtopoffset + \vbox\bgroup + \forgetall + \blank[\v!disable]} + +\def\pack_framed_stop_content_indeed + {\removelastskip + \egroup + \vskip\scratchbottomoffset + \egroup + \kern\scratchrightoffset + \egroup + \doif{\framedcontentparameter\c!width}\v!fit + {\letframedcontentparameter\c!width\v!fixed}% no shapebox + \ifinsidefloat + \donefalse + \else + \doifelse{\framedcontentparameter\c!linecorrection}\v!yes\donetrue\donefalse + \fi + % plaats ? + \ifdone\startlinecorrection\fi + \framedcontentparameter\c!left % new + \inheritedframedcontentframed{\box\b_framed_normal}% hm + \framedcontentparameter\c!right % new + \ifdone\stoplinecorrection\fi + \egroup} + +% A shared setting. + +\setuplinewidth + [\v!medium] + +%D A Goodie: + +\def\v!unframed{unframed} + +\defineframed + [\v!unframed] + [\c!frame=\v!off, + \c!rulethickness=\zeropoint, + \c!foregroundstyle=\framedparameter\c!style, + \c!foregroundcolor=\framedparameter\c!color] + +%D Bonus (as defined in \type {pack-rul.lua}): +%D +%D \starttyping +%D \setbox\scratchbox\vbox{a\par aa\par aaa\par} +%D \the\dimexpr\themaxboxwidth\scratchbox\relax +%D \stoptyping + +\let\themaxboxwidth\clf_themaxboxwidth + +%D New: slow but ok for most cases: + +\unexpanded\def\doifelseframed#1% + {\ifcase\numexpr\zerocount + \immediateassignment\edef\tempstring{#1\c!frame }\ifx\tempstring\v!on +\plusone\fi + \immediateassignment\edef\tempstring{#1\c!topframe }\ifx\tempstring\v!on +\plusone\fi + \immediateassignment\edef\tempstring{#1\c!bottomframe}\ifx\tempstring\v!on +\plusone\fi + \immediateassignment\edef\tempstring{#1\c!leftframe }\ifx\tempstring\v!on +\plusone\fi + \immediateassignment\edef\tempstring{#1\c!rightframe }\ifx\tempstring\v!on +\plusone\fi + \immediateassignment\edef\tempstring{#1\c!background }\ifx\tempstring\empty\else+\plusone\fi + \relax\expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments\fi} + +\protect \endinput diff --git a/tex/context/base/mkiv/page-imp.mkiv b/tex/context/base/mkiv/page-imp.mkiv index 2f4e9a2f9..b65f8991a 100644 --- a/tex/context/base/mkiv/page-imp.mkiv +++ b/tex/context/base/mkiv/page-imp.mkiv @@ -162,11 +162,15 @@ \box\scratchbox \endgroup} -\ifdefined \page_shipout_box \else +%D Also in normal \MKIV\ we nos use the indirect way so that we benefit from timing and +%D tracing. - \def\page_shipout_box#1{\normalshipout\box#1\relax} % takes a number +% \def\page_shipout_box#1{\normalshipout\box#1\relax} % takes a number -\fi +\unexpanded\def\page_shipout_box#1% + {\clf_shipoutpage#1\relax + \global\setbox#1\emptybox + \global\deadcycles\zerocount} \def\page_shipouts_normal#1% {\global\advance\shippedoutpages\plusone diff --git a/tex/context/base/mkiv/scrn-wid.mkvi b/tex/context/base/mkiv/scrn-wid.mkvi index b92880f2e..6808bd0b3 100644 --- a/tex/context/base/mkiv/scrn-wid.mkvi +++ b/tex/context/base/mkiv/scrn-wid.mkvi @@ -25,6 +25,8 @@ %D As usual in \CONTEXT\ we separate the general definition (frontend) %D and the rendering (backend). +% hack: x\footnote{x\inleftmargin[scope=local]{\attachment[location=high,file=i-context.pdf]}}x + % old but stil valid method: % % \useattachment[test.tex] diff --git a/tex/context/base/mkiv/spac-ver.mkiv b/tex/context/base/mkiv/spac-ver.mkiv index c76555cba..bf9427199 100644 --- a/tex/context/base/mkiv/spac-ver.mkiv +++ b/tex/context/base/mkiv/spac-ver.mkiv @@ -2127,38 +2127,13 @@ \installcorenamespace{vspacing} -\startmkivmode - - \unexpanded\def\directvspacing#1% - {\par - \ifcsname\??vspacing#1\endcsname - \lastnamedcs - \else - \spac_vspacing_yes_preset{#1}% - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\directvspacing#1% - {\par - \ifchkdim#1\or - \spac_vspacing_dim_preset{\the\dimexpr#1}% - \else\ifcsname\??vspacing#1\endcsname - \lastnamedcs - \else - \spac_vspacing_yes_preset{#1}% - \fi\fi} - - \def\spac_vspacing_dim_preset#1% - {\ifcsname\??vspacing#1\endcsname - \lastnamedcs - \else - \spac_vspacing_yes_preset{#1}% - \fi} - -\stoplmtxmode +\unexpanded\def\directvspacing#1% + {\par + \ifcsname\??vspacing#1\endcsname + \lastnamedcs + \else + \spac_vspacing_yes_preset{#1}% + \fi} \def\spac_vspacing_yes_preset#1% {\setxvalue{\??vspacing#1}{\clf_vspacing{#1}}% diff --git a/tex/context/base/mkiv/spac-ver.mkxl b/tex/context/base/mkiv/spac-ver.mkxl new file mode 100644 index 000000000..d15105e80 --- /dev/null +++ b/tex/context/base/mkiv/spac-ver.mkxl @@ -0,0 +1,2597 @@ +%D \module +%D [ file=spac-ver, +%D version=2009.10.16, % 1997.03.31, was core-spa.tex +%D title=\CONTEXT\ Spacing Macros, +%D subtitle=Vertical, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Spacing Macros / Vertical} + +\unprotect + +\registerctxluafile{spac-ver}{optimize} + +% todo: use usernodes ? + +% todo: itemize : intro ... only when there is one or two lines preceding and then +% keep these together i.e. \blank[intro] + +% Isn't it about time to get rid of topskip i.e. make it equivalent to +% \openstrutheight so that we can remove delta code. +% +% There might be more namespace protection. + +%D There are two ways to influence the interline spacing. The most general and often +%D most consistent way is using +%D +%D \showsetup{setupinterlinespace} +%D +%D For instance +%D +%D \starttyping +%D \setupinterlinespace[line=2.8ex] +%D \stoptyping +%D +%D This setting adapts itself to the bodyfontsize, while for instance saying +%D +%D \starttyping +%D \setupinterlinespace[line=12pt] +%D \stoptyping +%D +%D sets things fixed for all sizes, which is definitely not what we want. Therefore +%D one can also say: +%D +%D \starttyping +%D \definebodyfontenvironment[9pt][interlinespace=11pt] +%D \stoptyping +%D +%D One can still use \type {\setupinterlinespace} (without arguments) to set the +%D interline space according to the current font, e.g. a \type {\bfa}. + +% will be cleaned up but it will stay messy because we accept so +% many variants + +\newif\iflocalinterlinespace + +\newskip \s_spac_vspacing_temp \s_spac_vspacing_temp\bigskipamount + +\def\skipfactor {.75} +\def\skipgluefactor{.25} + +\def\normalskipamount + {\openlineheight + \ifgridsnapping \else \ifblankflexible + \s!plus \skipgluefactor\openlineheight + \s!minus\skipgluefactor\openlineheight + \fi \fi + \relax} + +\ifdefined\bodyfontinterlinespace \else + \let\bodyfontinterlinespace\empty +\fi + +\unexpanded\def\presetnormallineheight % each bodyfont + {\edef\normallineheight{\interlinespaceparameter\c!line}% + \iflocalinterlinespace \else + \edef\m_spac_normallineheight{\bodyfontinterlinespace}% + \ifx\m_spac_normallineheight\empty \else + \let\normallineheight\m_spac_normallineheight + \fi + \fi} + +\unexpanded\def\setupspecifiedinterlinespace[#1]% + {\setupcurrentinterlinespace[#1]% + \spac_linespacing_setup_specified_interline_space} + +\def\spac_linespacing_setup_specified_interline_space + {\edef\strutheightfactor {\interlinespaceparameter\c!height }% + \edef\strutdepthfactor {\interlinespaceparameter\c!depth }% + \edef\minimumstrutheight {\interlinespaceparameter\c!minheight}% + \edef\minimumstrutdepth {\interlinespaceparameter\c!mindepth }% + \edef\minimumlinedistance {\interlinespaceparameter\c!distance }% + \edef\normallineheight {\interlinespaceparameter\c!line }% + \edef\topskipfactor {\interlinespaceparameter\c!top }% + \edef\maxdepthfactor {\interlinespaceparameter\c!bottom }% + \edef\m_spac_vertical_baseline_stretch_factor{\interlinespaceparameter\c!stretch }% + \edef\m_spac_vertical_baseline_shrink_factor {\interlinespaceparameter\c!shrink }% + % often topskip does more bad than good, so: + \ifx\topskipfactor\v!height + \let\topskipfactor\strutheightfactor + \fi + \setfontparameters % redundant, can be \setstrut, test first + \updateraggedskips} % yes indeed + +\installcorenamespace{interlinespacerelative} + +\let\setrelativeinterlinespace \relax % used elsewhere +\let\currentrelativeinterlinespace\empty + +\setvalue{\??interlinespacerelative\v!on }{\oninterlineskip} +\setvalue{\??interlinespacerelative\v!off }{\offinterlineskip} +\setvalue{\??interlinespacerelative\v!reset}{\let\currentrelativeinterlinespace\empty + \let\setrelativeinterlinespace\relax + \setfontparameters} +\setvalue{\??interlinespacerelative\v!auto }{\let\setrelativeinterlinespace\spac_linespacing_set_relative_interlinespace} + +\def\spac_linespacing_set_specified_relative_interlinespace#1% fragile? + {\doifelsedimenstring{#1} + {\setupspecifiedinterlinespace[\c!line=#1]} + {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}% + \spacing\currentrelativeinterlinespace}} + +\unexpanded\def\setuprelativeinterlinespace[#1]% + {\processcommalist[#1]\spac_linespacing_setup_relative_interlinespace} + +\def\spac_linespacing_setup_relative_interlinespace#1% + {\ifcsname\??interlinespacerelative#1\endcsname + \lastnamedcs + \else + \spac_linespacing_set_specified_relative_interlinespace{#1}% + \fi} + +\def\spac_linespacing_set_relative_interlinespace + {\ifx\currentrelativeinterlinespace\empty\else + \spacing\currentrelativeinterlinespace + \fi} + +\unexpanded\def\spac_linespacing_setup_use + {\ifcsname\namedinterlinespacehash\m_spac_interlinespace\s!parent\endcsname + \let\currentinterlinespace\m_spac_interlinespace + \spac_linespacing_setup_specified_interline_space + % \else + % we only support named interlinespaces + \fi} + +\unexpanded\def\useinterlinespaceparameter#1% see footnotes + {\edef\m_spac_interlinespace{#1\c!interlinespace}% + \ifx\m_spac_interlinespace\empty \else + \spac_linespacing_setup_use + \fi} + +\newtoks\everysetupglobalinterlinespace +\newtoks\everysetuplocalinterlinespace + +\newconditional\interlinespaceisset + +\installcorenamespace{interlinespace} + +\installcommandhandler \??interlinespace {interlinespace} \??interlinespace + +\installmacrostack\currentinterlinespace + +\unexpanded\def\setupinterlinespace + {\dodoubleempty\spac_linespacing_setup} + +\ifdefined\setupinterlinespace_double \else + \let\setupinterlinespace_double\setup_interlinespace % for a while +\fi + +\def\spac_linespacing_setup[#1][#2]% + {\settrue\interlinespaceisset % reset has to be done when needed + \ifsecondargument + \setupinterlinespace_double[#1][#2]% + \orelse\iffirstargument + \ifcsname\namedinterlinespacehash{#1}\s!parent\endcsname + \edef\currentinterlinespace{#1}% + \spac_linespacing_setup_specified_interline_space + %\dosetupspecifiedinterlinespaceindeed + \else + \spac_linespacing_setup_specified_or_relative[#1]% + \fi + \else + \let\currentinterlinespace\empty + \spac_linespacing_synchronize_local + \fi} + +\def\spac_linespacing_setup_specified_or_relative[#1]% + {\doifelseassignment{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]% + \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi} + +\def\spac_linespacing_synchronize_local % adapts to the font + {\localinterlinespacetrue + \setfontparameters + \updateraggedskips % funny one here + \the\everysetuplocalinterlinespace + \localinterlinespacefalse} + +\unexpanded\def\dosetupcheckedinterlinespace#1% often a chain + {\edef\p_spac_checked_interlinespace{#1}% + \ifx\p_spac_checked_interlinespace\empty + \spac_linespacing_synchronize_local + \orelse\ifcsname\namedinterlinespacehash\p_spac_checked_interlinespace\s!parent\endcsname % we could have a \s!check + \push_macro_currentinterlinespace + \let\currentinterlinespace\p_spac_checked_interlinespace + \spac_linespacing_setup_specified_interline_space % \dosetupspecifiedinterlinespaceindeed + \iflocalinterlinespace + \the\everysetuplocalinterlinespace + \else + \localinterlinespacetrue + \the\everysetuplocalinterlinespace + \localinterlinespacefalse + \fi + \pop_macro_currentinterlinespace + \else + \normalexpanded{\noexpand\doifelseassignment{\p_spac_checked_interlinespace}% + \setupspecifiedinterlinespace\setuprelativeinterlinespace[\p_spac_checked_interlinespace]}% + \iflocalinterlinespace + \the\everysetuplocalinterlinespace + \else + \localinterlinespacetrue + \the\everysetuplocalinterlinespace + \localinterlinespacefalse + \fi + \fi} + +\unexpanded\def\setuplocalinterlinespace[#1]% + {\localinterlinespacetrue + \push_macro_currentinterlinespace + \setupinterlinespace[#1]% + \pop_macro_currentinterlinespace + \localinterlinespacefalse} + +\let\switchtointerlinespace\setuplocalinterlinespace + +%D Helpers + +\newskip \s_spac_lastskip +\newdimen\d_spac_prevdepth +\newcount\c_spac_spacefactor +\newdimen\d_spac_prevcontent % set by lua + +\unexpanded\def\removelastskip + {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi} + +\def\doifoutervmode + {\ifvmode + \ifinner + \doubleexpandafter\gobbleoneargument + \else + \doubleexpandafter\firstofoneargument + \fi + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\dosomebreak#1% + {\doifoutervmode + {\s_spac_lastskip\lastskip + \removelastskip + #1\relax + \ifdim\s_spac_lastskip=\zeropoint + % avoid interference with footnotes + \else + \vskip\s_spac_lastskip + \fi}} + +\unexpanded\def\packed + {\nointerlineskip} + +\unexpanded\def\godown[#1]% + {\relax + \ifhmode\endgraf\fi + \ifvmode\nointerlineskip\vskip#1\relax\fi} + +\unexpanded\def\smallskip{\vskip\smallskipamount} +\unexpanded\def\medskip {\vskip\medskipamount} +\unexpanded\def\bigskip {\vskip\bigskipamount} + +\unexpanded\def\smallbreak + {\par + \ifvmode\ifdim\lastskip<\smallskipamount + \removelastskip + \penalty-\plusfifty + \smallskip + \fi\fi} + +\unexpanded\def\medbreak + {\par + \ifvmode\ifdim\lastskip<\medskipamount + \removelastskip + \penalty-\plusonehundred + \medskip + \fi\fi} + +\unexpanded\def\bigbreak + {\par + \ifvmode\ifdim\lastskip<\bigskipamount + \removelastskip + \penalty-\plustwohundred + \bigskip + \fi\fi} + +\unexpanded\def\break {\penalty-\plustenthousand} % can be hmode or vmode +\unexpanded\def\nobreak {\penalty \plustenthousand} % can be hmode or vmode +\unexpanded\def\allowbreak{\penalty \zerocount} % can be hmode or vmode + +\unexpanded\def\goodbreak {\par\ifvmode\penalty-\plusfivehundred\relax\fi} % forces vmode +\unexpanded\def\filbreak {\par\ifvmode\vfil\penalty-\plustwohundred\vfilneg\fi} % forces vmode + +%D Made slightly more readable: + +\unexpanded\def\vglue {\afterassignment\spac_helpers_vglue_indeed\s_spac_lastskip=} +\unexpanded\def\hglue {\afterassignment\spac_helpers_hglue_indeed\s_spac_lastskip=} +\unexpanded\def\topglue{\par\ifvmode\nointerlineskip\vglue-\topskip\vglue\fi} + +\def\spac_helpers_vglue_indeed + {\par + \ifvmode + \d_spac_prevdepth\prevdepth + \hrule\s!height\zeropoint + \nobreak + \vskip\s_spac_lastskip + \prevdepth\d_spac_prevdepth + \fi} + +\def\spac_helpers_hglue_indeed + {\dontleavehmode + \c_spac_spacefactor\spacefactor + \vrule\s!width\zeropoint + \nobreak + \hskip\s_spac_lastskip + \spacefactor\c_spac_spacefactor} + +%D We adapt plain's \type {\removelastskip} a bit: + +\unexpanded\def\removelastskip % also in supp-box + {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi} + +% The whitespace handler. We could cache settings but normally there are not +% that many in a set. + +\installcorenamespace{whitespacemethod} + +\newskip \s_spac_whitespace_parskip \s_spac_whitespace_parskip\zeropoint +\newconditional\c_spac_whitespace_flexible \settrue\c_spac_whitespace_flexible +\newconstant \c_spac_whitespace_grid_mode % option in layout / 1=permit_half_lines + +%def\v_spac_whitespace_current{\zeropoint} +\let\v_spac_whitespace_current\v!none + +\unexpanded\def\setupwhitespace + {\doifelsenextoptionalcs\spac_whitespace_setup_yes\spac_whitespace_setup_nop} + +\def\spac_whitespace_setup_nop + {\ifx\v_spac_whitespace_current\v!none\else + \spac_whitespace_setup + \fi} + +\let\synchronizewhitespace\spac_whitespace_setup_nop + +\def\spac_whitespace_setup_yes[#1]% + {\edef\m_spac_whitespace_asked{#1}% + \ifx\m_spac_whitespace_asked\empty + \spac_whitespace_setup_nop + \else + \let\v_spac_whitespace_current\m_spac_whitespace_asked + \spac_whitespace_setup + \fi} + +\def\spac_whitespace_setup % quick test for no list + {\ifcsname\??whitespacemethod\v_spac_whitespace_current\endcsname + \lastnamedcs + \else + \expandafter\processcommalist\expandafter[\v_spac_whitespace_current]\spac_whitespace_setup_method % can be raw + \fi\relax + \ifgridsnapping + \spac_whitespace_setup_grid + \else + \spac_whitespace_setup_normal + \fi + \parskip\s_spac_whitespace_parskip} + +\def\spac_whitespace_setup_normal + {\ifconditional\c_spac_whitespace_flexible \else + \s_spac_whitespace_parskip\plusone\s_spac_whitespace_parskip + \fi} + +\def\spac_whitespace_setup_grid + {\setfalse\c_spac_whitespace_flexible + \ifdim\s_spac_whitespace_parskip>\zeropoint + \s_spac_whitespace_parskip + \ifcase\c_spac_whitespace_grid_mode + \baselineskip + \or + \ifdim\scratchdimen=\baselineskip % maybe range + \baselineskip + \else + \numexpr\s_spac_whitespace_parskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax + \fi + \else + \baselineskip + \fi + \fi} + +\unexpanded\def\installwhitespacemethod#1#2% + {\setvalue{\??whitespacemethod#1}{#2}} + +\installwhitespacemethod \v!fix {} +\installwhitespacemethod \v!fixed {\setfalse\c_spac_whitespace_flexible} +\installwhitespacemethod \v!flexible {\settrue \c_spac_whitespace_flexible} + +\installwhitespacemethod \v!line {\s_spac_whitespace_parskip \baselineskip} +\installwhitespacemethod \v!halfline {\s_spac_whitespace_parskip .5\baselineskip} +\installwhitespacemethod \v!quarterline {\s_spac_whitespace_parskip.25\baselineskip} +\installwhitespacemethod \v!none {\s_spac_whitespace_parskip \zeropoint} +\installwhitespacemethod \v!big {\s_spac_whitespace_parskip \bigskipamount} +\installwhitespacemethod \v!medium {\s_spac_whitespace_parskip \medskipamount} +\installwhitespacemethod \v!small {\s_spac_whitespace_parskip \smallskipamount} + +\installwhitespacemethod \s!default {\spac_whitespace_setup_nop} % also covers none + +\def\spac_whitespace_setup_method#1% + {\ifcsname\??whitespacemethod#1\endcsname + \lastnamedcs + \else + \s_spac_whitespace_parskip#1\fi + \relax} + +\unexpanded\def\forgetparskip + {\s_spac_whitespace_parskip\zeropoint + \parskip\zeropoint + \let\v_spac_whitespace_current\v!none} + +\appendtoks + \forgetparskip +\to \everyforgetall + +% \installwhitespacemethod \s!unknown {\s_spac_whitespace_parskip\commalistelement\relax} +% +% \def\spac_whitespace_setup_method#1% +% {\csname\??whitespacemethod\ifcsname\??whitespacemethod#1\endcsname#1\else\s!unknown\endcsname\relax} + +\unexpanded\def\nowhitespace{\directcheckedvspacing\v!nowhite} % {\vspacing[\v!nowhite]} +\unexpanded\def\whitespace {\directcheckedvspacing\v!white} % {\vspacing[\v!white]} + +\setupwhitespace + [\v!none] + +% Packed: + +% todo: when packed blocks blank, we need to enable forced + +\newconditional\c_spac_packed_blank \settrue\c_spac_packed_blank +\newcount \c_spac_packed_level + +\unexpanded\def\startpacked + {\dosingleempty\spac_packed_start} + +\def\spac_packed_start[#1]% nesting afvangen + {\global\advance\c_spac_packed_level\plusone + \par + \ifnum\c_spac_packed_level=\plusone \ifvmode + \begingroup + \whitespace % not combined + \directcheckedvspacing\v!disable % \blank[\v!disable]% or \inhibitblank + \doifelse{#1}\v!blank\settrue\setfalse\c_spac_packed_blank + \setupwhitespace[\v!none]% or \forgetparskip + \fi \fi} + +\unexpanded\def\stoppacked + {\par + \ifnum\c_spac_packed_level=\plusone \ifvmode + \endgroup + \fi \fi + \global\advance\c_spac_packed_level\minusone} + +\unexpanded\def\startunpacked + {\directdefaultvspacing % \blank + \begingroup} + +\unexpanded\def\stopunpacked + {\endgroup + \directdefaultvspacing}% \blank} + +% \prevdepth crosses pageboundaries! +% +% todo: a version that works ok inside a box + +% global : outer hsize + keep skips +% local : inner hsize + reset skips + +\installcorenamespace{linesaround} + +\let\spac_lines_vbox\vbox + +\installtextracker + {linecorrection.boxes} + {\let\spac_lines_vbox\ruledvbox} + {\let\spac_lines_vbox\vbox} + +\let\v_spac_lines_around_action_set\relax +\let\m_spac_lines_around \empty + +\newconstant\c_spac_lines_correction_mode + +\setvalue{\??linesaround\v!blank }{\blank} +\letvalue{\??linesaround\empty }\relax +\setvalue{\??linesaround\s!unknown}{\directcheckedvspacing\m_spac_lines_around} % \blank[\m_spac_lines_around]} + +\def\spac_lines_action_around % we used to let this one but it's cleaner this way + {\csname\??linesaround % i.e. do it twice + \ifcsname\??linesaround\m_spac_lines_around\endcsname\m_spac_lines_around\else\s!unknown\fi + \endcsname} + +\unexpanded\def\startlinecorrection + {\endgraf + \begingroup + \setconstant\c_spac_lines_correction_mode\plusone + \dosingleempty\spac_lines_start_correction} + +\unexpanded\def\startlocallinecorrection + {\endgraf + \begingroup + \setconstant\c_spac_lines_correction_mode\plustwo + \dosingleempty\spac_lines_start_correction} + +\unexpanded\def\spac_lines_start_correction[#1]% + {\edef\m_spac_lines_around{#1}% + \spac_lines_action_around + \d_spac_prevdepth\prevdepth + \spac_lines_initialize_corrections + \offbaselinecorrection % ??? + \setbox\scratchbox\spac_lines_vbox\bgroup + \ifcase\c_spac_lines_correction_mode + % nothing + \or + % global + \or + % local + \setlocalhsize + \hsize\localhsize + \forgetbothskips + \fi + \ignorespaces} + +\unexpanded\def\spac_lines_stop_correction + {\removeunwantedspaces + \egroup + \ifgridsnapping + \spac_lines_stop_correction_ongrid + \else + \spac_lines_stop_correction_normal + \fi + \endgroup} + +\unexpanded\def\spac_lines_stop_correction_ongrid + {\directcheckedvspacing\v!white % \blank[\v!white]% + \spac_lines_action_around + \snaptogrid\hpack{\box\scratchbox}% + \directcheckedvspacing\v!white + \spac_lines_action_around} + +\unexpanded\def\spac_lines_stop_correction_normal + {\directcheckedvspacing\v!nowhite % \blank[\v!nowhite]% + \ifdim\parskip>\zeropoint + % too fuzzy otherwise + \else + % doesn't like whitespace + \ifdim\d_spac_prevdepth<\maxdimen + \unless\ifdim\d_spac_prevdepth<\zeropoint + \ifdim\d_spac_prevdepth<\strutdp \relax + \pushlastnode + \ifdim\d_spac_prevdepth>\zeropoint + \kern-\d_spac_prevdepth + \fi + \kern\strutdp + \prevdepth\strutdp + \poplastnode + \fi + \fi + \fi + \fi + \ifdim\pagegoal<\maxdimen + % \blank[\v!white,\the\d_spac_lines_correction_before]% \blank[\v!white]\dotopbaselinecorrection + \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_before}% \blank[\v!white]\dotopbaselinecorrection + \fi + \nointerlineskip % new + \noindent % not \dontleavehmode ! + \ifcase\c_spac_lines_correction_mode + % nothing + \or + % global + \hskip-\leftskip % more tricky would be hangindent so we ignore that one + \or + % local + \fi + \box\scratchbox + \endgraf + % + % eventually i'll get it right ... (i also need to check all whitespace code elsewhere) + % + % \blank[\the\d_spac_lines_correction_after]% \dobotbaselinecorrection + % \directcheckedvspacing{\the\d_spac_lines_correction_after}% \dobotbaselinecorrection + \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_after}% \dobotbaselinecorrection + % \allowbreak % new, otherwise problems when many in a row + \prevdepth\strutdp + \spac_lines_action_around} + +\let\stoplinecorrection \spac_lines_stop_correction +\let\stoplocallinecorrection\spac_lines_stop_correction + +% todo: + +\unexpanded\def\correctwhitespace + {\dowithnextboxcs\correctwhitespacefinish\vbox} + +\unexpanded\def\correctwhitespacefinish + {\startbaselinecorrection + \flushnextbox + \stopbaselinecorrection} + +\unexpanded\def\verticalstrut {\vpack{\hsize\zeropoint\forgetall\strut}} +\unexpanded\def\horizontalstrut{\hpack {\strut}} + +%D Here follow some presets related to interline spacing and therefore also struts. +%D The values 2.8, 0.07, 0.72 and 0.28 originate in \INRSTEX, a package that we used +%D a while after we decided that \LATEX\ was not flexible enough. After that +%D \CONTEXT\ evolved, from some wrapper code around (old) \LATEX\ (on a floppy +%D disk), to using modules from \INRSTEX\ (which also fit on a floppy) and finally +%D all written from scratch. I simply didn't understand all that \TEX\ code at that +%D time, and it was easier to figure it out myself. But \unknown\ some settings +%D stayed, as the height|/|depth ratios, and they never proved to be bad ones! The +%D same is true for the font size relations. + +%D \starttabulate +%D \NC \type {\lineheight} \NC the height of a line \NC \NR +%D \NC \type {\spacing{number}} \NC adapting the interline space \NC \NR +%D \NC \type {\normalbaselines} \NC initialize the interline spacing \NC \NR +%D \NC \type {\setstrut} \NC initialize \type {\strut} \NC \NR +%D \NC \type {\setnostrut} \NC disable the \type {\strut}, \type {\endstrut}, \type {\begstrut} \NC \NR +%D \NC \type {\setteststrut} \NC initialize the visual \type {\strut} \NC \NR +%D \NC \type {\resetteststrut} \NC disable the visual \type {\strut} \NC \NR +%D \NC \type {\setfontparameters} \NC synchronize parameters with foints \NC \NR +%D \stoptabulate +%D +%D \unknown\ and many more (this is a decades old list). +%D +%D The lineheight is the sum of the height and depth of \type {strut}, which is +%D an invisible blob that can be used to enforce the proper dimensions. +%D +%D Such a blob, when placed at the beginning of a paragraph can have side effects +%D that can be prevented with \type {\dontleavehmode}. Never use \type +%D {\leavevmode}! + +\newdimen\strutdimen +\newdimen\lineheight +\newdimen\openlineheight +\newdimen\openstrutheight +\newdimen\openstrutdepth +\newdimen\topskipgap +\newdimen\struttotal + +\def\strutheightfactor {.72} +\def\strutdepthfactor {.28} + +\def\baselinefactor {2.8} + +\let\m_spac_vertical_baseline_stretch_factor \zerocount +\let\m_spac_vertical_baseline_shrink_factor \zerocount + +\def\minimumstrutheight {\zeropoint} +\def\minimumstrutdepth {\zeropoint} + +\def\normallineheight {\baselinefactor\exheight} +\def\minimumlinedistance {\lineskip} + +\def\strutheight {\zeropoint} +\def\strutdepth {\zeropoint} +\def\strutwidth {\zeropoint} + +\let\spacingfactor \plusone + +\def\topskipfactor {1.0} +\def\maxdepthfactor {0.5} + +\def\systemtopskipfactor {\topskipfactor} +\def\systemmaxdepthfactor {\maxdepthfactor} + +\ifdefined\globalbodyfontsize \else + \newdimen\globalbodyfontsize + \globalbodyfontsize=12pt +\fi + +\ifdefined\normalizedbodyfontsize \else + \def\normalizedbodyfontsize{12pt} +\fi + +\unexpanded\def\topskipcorrection + {\simpletopskipcorrection + \vskip-\struttotal + \verticalstrut} + +\unexpanded\def\simpletopskipcorrection + {\ifdim\topskip>\openstrutheight + % == \vskip\topskipgap + \vskip\topskip + \vskip-\openstrutheight + \fi} + +\unexpanded\def\settopskip % the extra test is needed for the lbr family + {\topskip + \ifgridsnapping + \zeropoint + \else + \systemtopskipfactor\globalbodyfontsize + \ifcase\bottomraggednessmode % ragged bottom + \s!plus5\globalbodyfontsize + \fi + \fi + %\relax + \topskipgap\topskip + \advance\topskipgap -\openstrutheight\relax + \ifdim\minimumstrutheight>\zeropoint + \ifdim\topskip<\minimumstrutheight + \topskip\minimumstrutheight\relax + \fi + \else + \ifdim\topskip<\strutheightfactor\openlineheight + \topskip\strutheightfactor\openlineheight\relax + \fi + \fi} + +\unexpanded\def\setmaxdepth + {\maxdepth\systemmaxdepthfactor\globalbodyfontsize} + +\let\normalbaselineskip \relax \newskip \normalbaselineskip % these got lost in the transition to mkiv due +\let\normallineskip \relax \newskip \normallineskip % to auto-\normal* definitions and registers +\let\normallineskiplimit\relax \newdimen\normallineskiplimit % being protected + +\unexpanded\def\normalbaselines + {\baselineskip \normalbaselineskip + \lineskip \normallineskip + \lineskiplimit\normallineskiplimit} + +\unexpanded\def\flexiblebaselines + {\baselineskip \normalbaselineskip + \lineskip 1\normallineskip \s!plus 1\s!fill + \lineskiplimit\normallineskiplimit} + +\unexpanded\def\setnormalbaselines + {\ifdim\normallineheight>\zeropoint + \lineheight\normallineheight + \fi + \openlineheight\spacingfactor\lineheight + \openstrutheight \ifdim\minimumstrutheight>\zeropoint + \minimumstrutheight % new + \else + \strutheightfactor\openlineheight + \fi + \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint + \minimumstrutdepth % new + \else + \strutdepthfactor \openlineheight + \fi + \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint + \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new + \fi + \normalbaselineskip\openlineheight + \ifgridsnapping\else + \s!plus \m_spac_vertical_baseline_stretch_factor\openlineheight + \s!minus\m_spac_vertical_baseline_shrink_factor \openlineheight + \fi + \normallineskip\minimumlinedistance\relax % \onepoint\relax + \normallineskiplimit\zeropoint\relax + \normalbaselines} + +\unexpanded\def\spacing#1% vertical + {\ifgridsnapping + \let\spacingfactor\plusone + \else + \edef\spacingfactor{#1}% + \fi + \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}% + \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}% + \setnormalbaselines + \setstrut} + +% \unexpanded\def\forgetverticalstretch % \forgetspacing +% {\spacing\plusone} + +\unexpanded\def\forgetverticalstretch + {\let\spacingfactor \plusone + \let\systemtopskipfactor \topskipfactor + \let\systemmaxdepthfactor\maxdepthfactor + \setnormalbaselines + \setstrut} + +\appendtoks + \forgetverticalstretch +\to \everyforgetall % needed in otr + +%D Sometimes one needs to freeze the interlinespacing +%D +%D \starttyping +%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf} +%D \stoptyping + +\let\restoreinterlinespace\relax + +\unexpanded\def\saveinterlinespace + {\unexpanded\edef\restoreinterlinespace + {\lineheight \the\lineheight + \openstrutheight \the\openstrutheight + \openstrutdepth \the\openstrutdepth + \openlineheight \the\openlineheight + \normalbaselineskip \the\normalbaselineskip + \normallineskip \the\normallineskip + \normallineskiplimit\the\normallineskiplimit + \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}% + \noexpand\normalbaselines}} + +%D This is the plain definition: +%D +%D \starttyping +%D \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi} +%D \stoptyping +%D +%D which could be: +%D +%D \starttyping +%D \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox} +%D \stoptyping +%D +%D But we do things differently. + +\newbox\strutbox + +\setbox\strutbox\hpack{\vrule\s!height8.5pt\s!depth3.5pt\s!width\zeropoint} % just a start + +\def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox} + +% \unexpanded\def\strut +% {\relax +% \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox} + +\let\normalstrut\strut + +%D The double \type {\hbox} construction enables us to backtrack boxes. + +\let\strutht\undefined \newdimen\strutht +\let\strutdp\undefined \newdimen\strutdp + +\unexpanded\def\setstrut + {\ifgridsnapping + \setstrutgridyes + \else + \setstrutgridnop + \fi} + +\unexpanded\def\setstrutgridyes + {\strutht\spacingfactor\dimexpr + \ifdim\minimumstrutheight>\zeropoint + \minimumstrutheight + \else + \strutheightfactor\dimexpr\normallineheight + \fi + \strutdp\dimexpr + \ifdim\minimumstrutdepth>\zeropoint + \minimumstrutdepth + \else + \normallineheight-\strutht + \fi + \dosetstrut} + +\unexpanded\def\setstrutgridnop + {\strutht\spacingfactor\dimexpr + \ifdim\minimumstrutheight>\zeropoint + \minimumstrutheight + \else + \strutheightfactor\dimexpr\normallineheight + \fi + \strutdp\spacingfactor\dimexpr + \ifdim\minimumstrutdepth>\zeropoint + \minimumstrutdepth + \else + \strutdepthfactor\dimexpr\normallineheight + \fi + \dosetstrut} + +\unexpanded\def\setcharstrut#1% + {\setbox\strutbox\hbox{#1}% no \hpack, in case we have smallcaps + \strutht\ht\strutbox + \strutdp\dp\strutbox + \dosetstrut} + +\unexpanded\def\settightstrut + {\setcharstrut{(}} + +\unexpanded\def\setfontstrut + {\setcharstrut{(gplQT}} + +\unexpanded\def\setcapstrut% could be M, but Q has descender + {\setcharstrut{Q}} + +%D Handy for math (used in mathml): + +\unexpanded\def\charhtstrut + {\begingroup + \setcharstrut{GJY}% + \vrule\s!width\zeropoint\s!depth\zeropoint\s!height\strutht + \endgroup} + +\unexpanded\def\chardpstrut + {\begingroup + \setcharstrut{gjy}% + \vrule\s!width\zeropoint\s!depth\strutdp\s!height\zeropoint + \endgroup} + +%D Because of all the callbacks in mkiv, we avoid unnecessary boxes ... maybe use an +%D attribute so that we can tag boxes that don't need a treatment; tests with using +%D an attribute so far have shown that it's slower because testing the attribute +%D takes time too. + +\unexpanded\def\dosetstrut + {\let\strut\normalstrut + \ifabsnum\dimexpr\strutht+\strutdp-\lineheight\relax<\plustwo + % compensate rounding error /- 1sp to avoid too many + % 1sp baselineskips in for instance verbatim + % \strutht\dimexpr\lineheight-\strutdp\relax + % better: + \strutdp\dimexpr\lineheight-\strutht\relax + \struttotal\lineheight + \else + \struttotal\dimexpr\strutht+\strutdp\relax + \fi + \edef\strutheight{\the\strutht}% + \edef\strutdepth {\the\strutdp}% + \ifdim\strutwidth=\zeropoint + \spac_struts_set_hide + \else + \spac_struts_set_vide + \fi} + +\def\spac_struts_set_hide + {\setbox\strutbox\hpack + {\vrule + \s!width \zeropoint + \s!height\strutht + \s!depth \strutdp}} + +\newconstant\c_strut_visual_mode + +\def\spac_struts_set_vide + {\setbox\strutbox\hpack % at some time this extra wrapping was needed + {\spac_struts_vide_hbox to \zeropoint + {\ifcase\c_strut_visual_mode + \spac_struts_black + \or + \spac_struts_color + \else + \spac_struts_black + \fi}}} + +\def\spac_struts_black + {\vrule + \s!width \strutwidth + \s!height\strutht + \s!depth \strutdp + \hss} + +\def\spac_struts_color + {\hss % new, will be option + \scratchwidth.1\struthtdp + \begingroup + \directcolor[f:b:t]% + \vrule + \s!width \scratchwidth + \s!height\strutht + \s!depth \strutdp + \kern-\scratchwidth + \vrule + \s!width \scratchwidth + \s!height\zeropoint + \s!depth \strutdp + \endgroup + \kern-.625\scratchwidth + \vrule + \s!width .25\scratchwidth + \s!height\strutht + \s!depth \strutdp + \hss} + +\let\spac_struts_vide_hbox\hbox % overloaded in trac-vis.mkiv + +%D The dimen \type {\struttotal} holds the exact size of the strut; occasionally a +%D one scaled point difference can show up with the lineheight. This is more +%D efficient (less callbacks): + +\newbox\b_spac_struts_empty \setbox\b_spac_struts_empty\emptyhbox + +\def\spac_struts_set_hide + {\setbox\strutbox\copy\b_spac_struts_empty + \ht\strutbox\strutht + \dp\strutbox\strutdp} + +\unexpanded\def\strut % still callbacks for \hbox{\strut} + {\relax + \dontleavehmode + \copy\strutbox} + +% \unexpanded\def\strut % slightly faster +% {\relax +% \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox} + +\let\normalstrut\strut + +\unexpanded\def\halfstrut + {\relax + \dontleavehmode + \begingroup + \setbox\scratchbox\copy\strutbox + \ht\scratchbox\dimexpr\strutht/\plustwo\relax + \dp\scratchbox\dimexpr\strutdp/\plustwo\relax + \box\scratchbox + \endgroup} + +\unexpanded\def\quarterstrut + {\relax + \dontleavehmode + \begingroup + \setbox\scratchbox\copy\strutbox + \ht\scratchbox\dimexpr\strutht/\plusfour\relax + \dp\scratchbox\dimexpr\strutdp/\plusfour\relax + \box\scratchbox + \endgroup} + +\unexpanded\def\depthstrut + {\relax + \dontleavehmode + \begingroup + \setbox\scratchbox\copy\strutbox + \ht\scratchbox\dimexpr\strutht-\struthtdp/\plustwo\relax % assumes that ht > lineheight/2 + \box\scratchbox + \endgroup} + +\unexpanded\def\halflinestrut + {\relax + \dontleavehmode + \begingroup + \setbox\scratchbox\copy\strutbox + \ht\scratchbox\dimexpr\strutht-.5\strutht-.5\strutdp\relax + \box\scratchbox + \endgroup} + +\unexpanded\def\noheightstrut + {\relax + \dontleavehmode + \begingroup + \setbox\scratchbox\copy\strutbox + \ht\scratchbox\zeropoint + \box\scratchbox + \endgroup} + +%D Sometimes a capstrut comes in handy +%D +%D \starttabulate[|Tl|l|l|] +%D \NC yes \NC normal strut \NC {\showstruts\setupstrut[yes]\strut} \NC \NR +%D \NC no \NC no strut \NC {\showstruts\setupstrut[no]\strut} \NC \NR +%D \NC kap \NC a capital strut (i.e. Q) \NC {\showstruts\setupstrut[cap]\strut} \NC \NR +%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR +%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR +%D \stoptabulate +%D +%D Beware: using an unknown value results in char struts. + +\installcorenamespace{struts} + +\unexpanded\def\setupstrut + {\dosingleempty\spac_struts_setup} + +\def\spac_struts_setup[#1]% + {\edef\m_strut{#1}% + \ifcsname\??struts\m_strut\endcsname + \lastnamedcs + \else + \setcharstrut\m_strut + \fi} + +\unexpanded\def\synchronizestrut#1% no [] parsing, faster for internal + {\edef\m_strut{#1}% + \ifcsname\??struts\m_strut\endcsname + \lastnamedcs + \else + \setcharstrut\m_strut + \fi} + +\unexpanded\def\dosynchronizestrut#1% no [] parsing, faster for internal + {\ifcsname\??struts#1\endcsname + \lastnamedcs + \else + \setcharstrut{#1}% + \fi} + +\unexpanded\def\showstruts % adapts .. is wrong + {\c_strut_visual_mode\zerocount + \setteststrut + \settestcrlf} + +\unexpanded\def\showcolorstruts % adapts .. is wrong + {\c_strut_visual_mode\plusone + \setteststrut + \settestcrlf} + +\unexpanded\def\setteststrut + {\def\strutwidth{.8pt}% + \setstrut} + +\unexpanded\def\dontshowstruts + {\unsetteststrut + \settestcrlf} + +\unexpanded\def\unsetteststrut + {\let\strutwidth\zeropoint + \setstrut} + +\def\autostrutfactor{1.1} + +\unexpanded\def\setautostrut + {\begingroup + \setbox\scratchbox\copy\strutbox + \setstrut + \ifdim\strutht>\autostrutfactor\ht\scratchbox + \endgroup \setstrut + \orelse\ifdim\strutdp>\autostrutfactor\dp\scratchbox + \endgroup \setstrut + \else + \endgroup + \fi} + +\newbox\nostrutbox \setbox\nostrutbox\emptyhbox + +\newtoks\everysetnostrut + +\unexpanded\def\setnostrut + {\the\everysetnostrut} + +\appendtoks + \setbox\strutbox\copy\nostrutbox + \let\strut\empty + \let\endstrut\empty + \let\begstrut\empty +\to \everysetnostrut + +%D When enabled, sigstruts will remove themselves if nothing goes inbetween. For +%D practical reasons we define some boundary characters here. + +\unexpanded\def\leftboundary {\protrusionboundary\plusone} +\unexpanded\def\rightboundary {\protrusionboundary\plustwo} +\unexpanded\def\signalcharacter{\boundary\plusone\char\zerocount\boundary\plustwo} % not the same as strut signals + +\newsignal\strutsignal \setfalse\sigstruts + +\unexpanded\def\begstrut + {\relax\ifcase\strutht + % \ignorespaces % maybe + \else + \spac_struts_beg + \fi} + +\def\spac_struts_beg + {\ifconditional\sigstruts + \spac_struts_beg_signal + \else + \spac_struts_beg_normal + \fi + \ignorespaces} + +\def\spac_struts_beg_signal + {\noindent\horizontalstrut + \penalty\plustenthousand + \hskip-\strutsignal + \hskip\strutsignal} + +\def\spac_struts_beg_normal + {\boundary\plusone + \strut + %\boundary\plusone + \penalty\plustenthousand + %\boundary\plusone + \hskip\zeropoint} + +\unexpanded\def\endstrut + {\relax\ifhmode + \ifcase\strutht + % \removeunwantedspaces % maybe + \else + \spac_struts_end + \fi + \fi} + +\def\spac_struts_end + {\ifconditional\sigstruts + \spac_struts_end_signal + \else + \spac_struts_end_normal + \fi} + +\def\spac_struts_end_signal + {\ifdim\lastskip=\strutsignal + \unskip + \unskip + \unpenalty + \setbox\scratchbox\lastbox + \else + \penalty\plustenthousand + \hskip\zeropoint + \strut + \fi} + +\def\spac_struts_end_normal + {\removeunwantedspaces + \penalty\plustenthousand + %\boundary\plustwo + \hskip\zeropoint + %\boundary\plustwo + \strut + \boundary\plustwo} + +% unsave: +% +% \def\pseudostrut +% {\bgroup +% \setnostrut +% \normalstrut +% \egroup} +% +% try: +% +% \startchemie +% \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C] +% \stopchemie +% +% so: + +\unexpanded\def\pseudostrut + {\noindent} % better: \dontleavehmode + +\let\pseudobegstrut\pseudostrut +\let\pseudoendstrut\removeunwantedspaces + +\unexpanded\def\resetteststrut + {\def\strutwidth{\zeropoint}% no let + \setstrut} + +\ifdefined\setfontparameters \else + \def\setfontparameters{\the\everybodyfont} +\fi + +%D Keyword based strutting: + +\letvalue{\??struts\v!yes }\setstrut +\letvalue{\??struts\v!auto }\setautostrut +\letvalue{\??struts\v!no }\setnostrut +\letvalue{\??struts\v!cap }\setcapstrut +\letvalue{\??struts\v!fit }\setfontstrut +\letvalue{\??struts\v!line }\setstrut +\letvalue{\??struts\s!default}\setstrut +\letvalue{\??struts\empty }\setstrut + +%D Handy: + +\def\baselinedistance{\the\lineheight} + +%D We need \type {\normaloffinterlineskip} because the new definition contains an +%D assignment, and |<|don't ask me why|>| this assignment gives troubles in for +%D instance the visual debugger. + +\unexpanded\def\offinterlineskip + {\baselineskip-\thousandpoint + \lineskip \zeropoint + \lineskiplimit\maxdimen + % We also need this here now; thanks to taco for figuring that out! + \def\minimumlinedistance{\zeropoint}} + +\unexpanded\def\nointerlineskip + {\prevdepth-\thousandpoint} + +\let\normaloffinterlineskip\offinterlineskip % knuth's original + +%D This is tricky. The prevdepth value is still set to the last one even if there is +%D nothing on the page. The same is true for prevgraf, which doesn't resemble the +%D value on the current page. +%D +%D So, here we kick in a checker but it has to happen after the output group and it +%D only has to be done once (output can trigger itself!). +%D +%D However, prevgraf is somehow bound to hangindent so we can get very nasty side +%D effects. So, in tne end we use our own variable! + +\ifdefined\getnofpreviouslines + % defined public at the lua end +\else + \let\getnofpreviouslines\!!zerocount +\fi + +\unexpanded\def\page_otr_synchronize_page_yes + {\aftergroup\page_otr_synchronize_page_indeed + \glet\page_otr_synchronize_page\relax} + +% \unexpanded\def\page_otr_synchronize_page_indeed +% {\clf_synchronizepage +% \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes} +% +% This has to become an otr method: \s!page_otr_command_synchonize_page + +\unexpanded\def\page_otr_synchronize_page_indeed + {\ifx\currentoutputroutine\s!multicolumn\else\clf_synchronizepage\fi + \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes} + +\let\page_otr_synchronize_page\page_otr_synchronize_page_yes + +\appendtoks + \page_otr_synchronize_page +\to \everyaftershipout + +%D My own one: + +\unexpanded\def\spac_helpers_push_interlineskip_yes + {\edef\oninterlineskip + {\baselineskip \the\baselineskip + \lineskip \the\lineskip + \lineskiplimit\the\lineskiplimit + \noexpand\edef\noexpand\minimumlinedistance{\the\dimexpr\minimumlinedistance}% + \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}} % \noexpand not needed + +\unexpanded\def\spac_helpers_push_interlineskip_nop + {\let\oninterlineskip\setnormalbaselines} + +\unexpanded\def\offinterlineskip + {\ifdim\baselineskip>\zeropoint + \spac_helpers_push_interlineskip_yes + \else + \spac_helpers_push_interlineskip_nop + \fi + \normaloffinterlineskip} + +\let\oninterlineskip\relax + +\unexpanded\def\leaveoutervmode + {\ifvmode\ifinner\else + \leavevmode + \fi\fi} + +\unexpanded\def\resetpenalties#1% + {\ifdefined#1% + #1\minusone + \fi} + +\unexpanded\def\setpenalties#1#2#3% + {\ifdefined#1% space before #3 prevents lookahead problems, needed when #3=text + #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax + \fi} + +%D \macros +%D {keeplinestogether} +%D +%D Dirty hack, needed in margin content that can run of a page. + +% just before margintexts ... will eventually be done differently in mkiv using +% attributes + +\newcount\c_spac_keep_lines_together +\let\restoreinterlinepenalty\relax + +\unexpanded\def\spac_penalties_restore + {\glet\restoreinterlinepenalty\relax + \global\resetpenalties\interlinepenalties + \global\c_spac_keep_lines_together\zerocount} + +\unexpanded\def\keeplinestogether#1% + {\ifnum#1>\c_spac_keep_lines_together + \global\c_spac_keep_lines_together#1% + \global\setpenalties\interlinepenalties\c_spac_keep_lines_together\plustenthousand + \glet\restoreinterlinepenalty\spac_penalties_restore + \fi} + +\def\defaultdisplaywidowpenalty {50} +\def\defaultwidowpenalty {2000} % was: 1000 +\def\defaultclubpenalty {2000} % was: 800 +\def\defaultbrokenpenalty {100} +\def\defaultdoublehyphendemerits {10000} +\def\defaultfinalhyphendemerits {5000} +\def\defaultadjdemerits {10000} + +\def\defaultgriddisplaywidowpenalty {0} +\def\defaultgridwidowpenalty {0} +\def\defaultgridclubpenalty {0} +\def\defaultgridbrokenpenalty {0} +\def\defaultgriddoublehyphendemerits{10000} % always was so +\def\defaultgridfinalhyphendemerits {5000} % always was so +\def\defaultgridadjdemerits {10000} % always was so + +\unexpanded\def\nopenalties + {\widowpenalty \zerocount + \clubpenalty \zerocount + \brokenpenalty \zerocount + \doublehyphendemerits\zerocount + \finalhyphendemerits \zerocount + \adjdemerits \zerocount} + +\unexpanded\def\setdefaultpenalties + {\directsetup{\systemsetupsprefix\s!default}} + +\startsetups [\systemsetupsprefix\s!reset] + \resetpenalties\widowpenalties + \resetpenalties\clubpenalties + \resetpenalties\interlinepenalties +\stopsetups + +%D We use \directsetup because it's faster and we know there is no csl: + +\startsetups [\systemsetupsprefix\s!default] + + \directsetup{\systemsetupsprefix\s!reset} + + \widowpenalty \defaultwidowpenalty + \clubpenalty \defaultclubpenalty + \displaywidowpenalty \defaultdisplaywidowpenalty + \brokenpenalty \defaultbrokenpenalty + \doublehyphendemerits\defaultdoublehyphendemerits + \finalhyphendemerits \defaultfinalhyphendemerits + \adjdemerits \defaultadjdemerits + +\stopsetups + +\startsetups [\v!grid] [\systemsetupsprefix\s!default] + + \directsetup{\systemsetupsprefix\s!reset} + + \widowpenalty \defaultgridwidowpenalty + \clubpenalty \defaultgridclubpenalty + \displaywidowpenalty \defaultgriddisplaywidowpenalty + \brokenpenalty \defaultgridbrokenpenalty + \doublehyphendemerits\defaultgriddoublehyphendemerits + \finalhyphendemerits \defaultgridfinalhyphendemerits + \adjdemerits \defaultgridadjdemerits + +\stopsetups + +%D As an illustration: + +\startsetups [\systemsetupsprefix\v!strict] + + \directsetup{\systemsetupsprefix\s!reset} + + \setpenalties \widowpenalties \plustwo \maxdimen + \setpenalties \clubpenalties \plustwo \maxdimen + \brokenpenalty \maxdimen + \doublehyphendemerits \defaultdoublehyphendemerits + \finalhyphendemerits \defaultfinalhyphendemerits + \adjdemerits \defaultadjdemerits + +\stopsetups + +\setdefaultpenalties % will happen later in \setuplayout + +%D To be checked: + +\newbox\b_spac_struts_saved + +\unexpanded\def\savestrut {\setbox\b_spac_struts_saved\copy\strutbox} +\unexpanded\def\savedstrut{\copy \b_spac_struts_saved} + +%D Good old blank redone: + +%definesystemattribute[kernchars] [public] +\definesystemattribute[skipcategory] [public] +\definesystemattribute[skippenalty] [public] +\definesystemattribute[skiporder] [public] +\definesystemattribute[snapmethod] [public] +\definesystemattribute[snapvbox] [public] +%definesystemattribute[snapcategory] [public] + +% TODO: NAMED SNAPPERS + +\installcorenamespace{gridsnappers} +\installcorenamespace{gridsnapperattributes} +\installcorenamespace{gridsnappersets} + +\newskip \bodyfontlineheight +\newdimen \bodyfontstrutheight +\newdimen \bodyfontstrutdepth + +\newskip \globalbodyfontlineheight % why a skip +\newdimen \globalbodyfontstrutheight +\newdimen \globalbodyfontstrutdepth + +\def\snappedvboxattribute{\ifgridsnapping attr \snapvboxattribute \attribute\snapmethodattribute\fi} +\def\setlocalgridsnapping{\ifgridsnapping \attribute \snapvboxattribute \attribute\snapmethodattribute\fi} + +\def\spac_grids_set_local_snapping#1% + {\ifgridsnapping + \doifsomething{#1}% + {\spac_grids_snap_value_set{#1}% + \attribute \snapvboxattribute \attribute\snapmethodattribute}% + \fi} + +\def\spac_grids_expand_snapper#1% + {\edef\m_spac_snapper + {\ifx\m_spac_snapper\empty\else\m_spac_snapper,\fi + \ifcsname\??gridsnappersets#1\endcsname + \lastnamedcs\else#1% + \fi}} + +\unexpanded\def\installsnapvalues#1#2% + {\let\m_spac_snapper\empty + \rawprocesscommacommand[#2]\spac_grids_expand_snapper + \edef\currentsnapper{#1:\m_spac_snapper}% + \ifcsname\??gridsnapperattributes\currentsnapper\endcsname + \scratchcounter\lastnamedcs % already defined + \else + \scratchcounter\clf_definesnapmethod{#1}{\m_spac_snapper}% + \setevalue{\??gridsnapperattributes\currentsnapper}{\the\scratchcounter}% + \fi + \setevalue{\??gridsnappers#1}{\attribute\snapmethodattribute\the\scratchcounter\relax}% + \letvalue{\??gridsnappersets#1}\m_spac_snapper} + +\def\theexpandedsnapperset#1{\begincsname\??gridsnappersets#1\endcsname} % only for manuals + +\unexpanded\def\usegridparameter#1% no checking here + {\edef\m_spac_grid_asked{#1\c!grid}% + \ifx\m_spac_grid_asked\empty + \attribute \snapvboxattribute\attributeunsetvalue + \else + \spac_grids_snap_value_set\m_spac_grid_asked + \attribute \snapvboxattribute\attribute\snapmethodattribute + \fi} + +\unexpanded\def\definegridsnapping + {\dodoubleargument\spac_grids_define} + +\def\spac_grids_define[#1][#2]% + {\installsnapvalues{#1}{#2}} + +\edef\spac_grids_snap_value_reset + {%\gridsnappingfalse + \attribute\snapmethodattribute\attributeunsetvalue} + +\def\spac_grids_snap_value_set#1% + {%\gridsnappingtrue + \begincsname\??gridsnappers#1\endcsname} + +% maybe: +% +% \def\spac_grids_snap_value_set#1% +% {%\gridsnappingtrue +% \ifcsname\??gridsnappers#1\endcsname +% \lastnamedcs +% \else +% \definegridsnapping[#1][#1]% +% \begincsname\??gridsnappers#1\endcsname +% \fi} + +\def\spac_grids_snap_value_auto#1% + {\ifcsname\??gridsnappers#1\endcsname + \lastnamedcs + \else + \installsnapvalues\s!dummy{#1}% + \csname\??gridsnappers\s!dummy\endcsname + \fi} + +% \installsnapvalues{loose} {\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut} +% \installsnapvalues{normal}{\v!maxdepth:1.0,\v!maxheight:1.0,\v!strut} +% \installsnapvalues{tight} {\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut} + +% none don't enlarge +% halfline enlarge by halfline/halfline +% line enlarge by line/line +% strut enlarge by ht/dp (default) +% first align to top line +% last align to bottom line +% mindepth round depth down +% maxdepth round depth up +% minheight round height down +% maxheight round height up +% local use local interline space +% offset:-3tp vertical shift within box +% bottom:lines +% top:lines +% box centers a box rounded upwards (box:.5 -> tolerance) +% min centers a box rounded downwards +% max centers a box rounded upwards + +%D We're not downward compatible with \MKII ! Not yet in interface file: + +\definegridsnapping[\v!normal] [\v!maxheight,\v!maxdepth,\v!strut] +\definegridsnapping[\v!standard] [\v!maxheight,\v!maxdepth,\v!strut] +\definegridsnapping[\v!yes] [\v!maxheight,\v!maxdepth,\v!strut] + +\definegridsnapping[\v!strict] [\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut] +\definegridsnapping[\v!tolerant] [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut] +\definegridsnapping[\v!verytolerant] [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut] + +\definegridsnapping[\v!tolerant:10] [\v!maxdepth:1.1,\v!maxheight:1.1,\v!strut] % 10 pct tolerance +\definegridsnapping[\v!tolerant:20] [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut] % 20 pct tolerance +\definegridsnapping[\v!tolerant:30] [\v!maxdepth:1.3,\v!maxheight:1.3,\v!strut] % 30 pct tolerance +\definegridsnapping[\v!tolerant:40] [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut] % 40 pct tolerance + +\definegridsnapping[\v!top] [\v!minheight,\v!maxdepth,\v!strut] +\definegridsnapping[\v!bottom] [\v!maxheight,\v!mindepth,\v!strut] +\definegridsnapping[\v!both] [\v!minheight,\v!mindepth,\v!strut] + +\definegridsnapping[\v!broad] [\v!maxheight,\v!maxdepth,\v!strut,0.8] % maybe 0.85 +\definegridsnapping[\v!fit] [\v!maxheight,\v!maxdepth,\v!strut,1.2] % tight 0.15 + +\definegridsnapping[\v!first] [\v!first] +\definegridsnapping[\v!last] [\v!last] +\definegridsnapping[\v!high] [\v!minheight,\v!maxdepth,\v!none] +\definegridsnapping[\v!one] [\v!minheight,\v!mindepth] +\definegridsnapping[\v!low] [\v!maxheight,\v!mindepth,\v!none] +\definegridsnapping[\v!none] [\v!none] +\definegridsnapping[\v!line] [\v!line] +\definegridsnapping[\v!strut] [\v!strut] +\definegridsnapping[\v!box] [\v!box] +\definegridsnapping[\v!min] [\v!min] +\definegridsnapping[\v!max] [\v!max] + +\definegridsnapping[\v!middle] [\v!maxheight,\v!maxdepth] % used in placement + +\definegridsnapping[\v!math] [\v!maxdepth:1.05,\v!maxheight:1.05,\v!strut] % experimental, maybe 1.1 +\definegridsnapping[\v!math:\v!line] [\v!math,\v!line,\v!split] +\definegridsnapping[\v!math:\v!halfline] [\v!math,\v!halfline,\v!split] +\definegridsnapping[\v!math:-\v!line] [\v!math,-\v!line,\v!split] +\definegridsnapping[\v!math:-\v!halfline][\v!math,-\v!halfline,\v!split] + +\unexpanded\def\synchronizelocallinespecs + {\bodyfontlineheight \normallineheight + \bodyfontstrutheight\strutht + \bodyfontstrutdepth \strutdp} + +\unexpanded\def\synchronizegloballinespecs + {\global\globalbodyfontlineheight \normallineheight + \global\globalbodyfontstrutheight\strutht + \global\globalbodyfontstrutdepth \strutdp} + +\appendtoks + \synchronizegloballinespecs + \synchronizelocallinespecs +\to \everysetupglobalinterlinespace + +\appendtoks + \synchronizelocallinespecs +\to \everysetuplocalinterlinespace + +%D We still have to synchronize these: + +\unexpanded\def\synchronizeskipamounts + {\bigskipamount + \skipfactor\baselineskip + \s!plus\skipgluefactor\baselineskip + \s!minus\skipgluefactor\baselineskip + \relax + \medskipamount \bigskipamount \divide\medskipamount \plustwo + \smallskipamount\bigskipamount \divide\smallskipamount\plusfour} + +%D Snapping. + +\newif\ifgridsnapping + +%unexpanded\def\moveongrid {\dosingleempty\spac_grids_move_on} +\unexpanded\def\snaptogrid {\dosingleempty\spac_grids_snap_to} +\unexpanded\def\placeongrid{\dosingleempty\spac_grids_place_on} + +\unexpanded\def\startgridsnapping + {\dosingleempty\spac_grids_start_snapping} + +\unexpanded\def\spac_grids_start_snapping[#1]% + {\snaptogrid[#1]\vbox\bgroup} + +\unexpanded\def\stopgridsnapping + {\egroup} + +% \def\spac_grids_move_on[#1]% +% {[obsolete]} % gone, unless we set an attribute + +\def\spac_grids_place_on[#1]% + {\snaptogrid[#1]\vbox} % mark as done + +\def\spac_grids_snap_to[#1]% list or predefined + {\ifgridsnapping + \expandafter\spac_grids_snap_to_indeed + \else + \expandafter\gobbleoneargument + \fi{#1}} + +\def\spac_grids_snap_to_indeed#1% + {\bgroup + \spac_grids_snap_value_reset + \dowithnextbox{\spac_grids_snap_to_finish{#1}}} + +% eventually there will always be a line snap + +\def\spac_grids_snap_to_finish#1% + {\ifvbox\nextbox % this will go away + \clf_vspacingcollapse\nextbox\relax % isn't that already done? + \fi + \doifelsenothing{#1}{\spac_grids_snap_value_set\v!normal}{\spac_grids_snap_value_set{#1}}% + \clf_vspacingsnap\nextbox\attribute\snapmethodattribute\relax + \ifvbox\nextbox\vbox\else\hbox\fi attr \snapmethodattribute \zerocount {\box\nextbox}% no pack (?), we snap + \egroup} + +\def\spac_grids_check_nop + {\gridsnappingfalse + \resetsystemmode\v!grid + \spac_grids_snap_value_reset} + +\def\spac_grids_check_yes + {\gridsnappingtrue + \setsystemmode\v!grid + \spac_grids_snap_value_set\askedgridmode} + +\unexpanded\def\synchronizegridsnapping + {\edef\askedgridmode{\layoutparameter\c!grid}% + \ifx\askedgridmode\v!no % official + \spac_grids_check_nop + \orelse\ifx\askedgridmode\v!off % for taco and luigi + \spac_grids_check_nop + \orelse\ifx\askedgridmode\empty % to be sure + \spac_grids_check_nop + \else + \spac_grids_check_yes + \fi} + +\unexpanded\def\setupgridsnapping[#1]% less overhead than setuplayout (needs testing) + {\setlayoutparameter\c!grid{#1}\synchronizegridsnapping} + +\unexpanded\def\checkgridmethod#1% + {\edef\p_grid{#1}% + \ifx\p_grid\empty + \let\checkedgridmethod\empty + \let\checkedgridscope \v!local + \else + \splitatcolon\p_grid\checkedgridscope\checkedgridmethod + \ifx\checkedgridmethod\empty + \ifx\checkedgridscope\v!local\orelse\ifx\checkedgridscope\v!global\else + \let\checkedgridmethod\checkedgridscope + \let\checkedgridscope \v!local + \fi + \fi + \fi} + +\unexpanded\def\applygridmethod#1#2#3% content localsettings (used in head rendering) + {\checkgridmethod{#1}% + \ifx\checkedgridscope\v!global + \ifx\checkedgridmethod\empty \else + % we assume that the call is grouped because grouping here has the side + % effect that the eventually constructed line will get the value outside + % the group + % + % overkill: \setupgridsnapping[\checkedgridmethod]% + % maybe : \spac_grids_snap_value_auto\checkedgridmethod + \spac_grids_snap_value_set\checkedgridmethod + \fi + \hbox{#3}% + \else + % the extra hbox will trigger the global snapper on top of the local and + % we really need that in this case (compatibility etc etc) so here we don't + % het an already done hit (otherwise we would not snap) + \hbox\bgroup + \ifx\checkedgridmethod\empty\orelse\ifconditional\headisdisplay + #2% + \fi + \snaptogrid[\checkedgridmethod]\hbox{#3}% + \egroup + \fi} + +\unexpanded\gdef\page_layouts_calculate_overshoot + {\ifgridsnapping\ifcase\layoutlines + \getnoflines\textheight + \textovershoot\dimexpr\noflines\globalbodyfontlineheight-\textheight\relax + \fi\fi} + +\unexpanded\def\page_layouts_report_overshoot + {\page_layouts_calculate_overshoot + \ifdim\textovershoot>\zeropoint + \writestatus\m!layouts{gridmode,\space + noflines: \the\noflines,\space + textheight: \the\textheight,\space + textovershoot: \the\textovershoot\space + (maybe set number of lines instead)% + }% + \fi + \glet\page_layouts_report_overshoot\page_layouts_calculate_overshoot} + +\appendtoks + \page_layouts_report_overshoot +\to \everybeforepagebody + +%D Visualization: + +\definepalet + [grid] + [ one=red, + two=green, + three=blue, + four=gray] + +\unexpanded\def\setgridtracebox#1[#2]% % maybe reverse the order + {\setbox\nextbox#1% + {\hbox + {\hbox to \zeropoint + {\setlayoutcomponentattribute{\v!grid:\v!test}% + \color[grid:#2]{\ruledhbox \layoutcomponentboxattribute {\fakebox\nextbox}}% + \hss}% + \flushnextbox}}} + +\setnewconstant\gridboxlinenomode\plusone % 0:nothing 1:all 2:lines 3:frame 4:l/r +\setnewconstant\gridboxlinemode \plusone + +\unexpanded\def\gridboxvbox + {\ifcase\gridboxlinemode + \vpack + \or + \ruledvpack + \or + \vpack + \or + \ruledvpack + \else + \ruledvpack + \fi} + +\def\gridboxwidth{\ifcase\gridboxlinemode0\or.5\or.5\or0\else.5\fi\linewidth} + +\unexpanded\def\setgridbox#1#2#3% maybe ifgridsnapping at outer level + {\setbox#1\gridboxvbox to #3 % given size + {\forgetall + \resetvisualizers + \resetteststrut + \offinterlineskip + \hsize#2% + \ifcase\gridboxlinenomode\or\or\or + \gridboxlinenomode\doifoddpageelse\plusone\plustwo % 3: outer + \or + \gridboxlinenomode\doifoddpageelse\plustwo\plusone % 4: inner + \fi + \topskipcorrection + \gridboxvbox % calculated size + {\getrawnoflines{#3}% \getnoflines{#3}% + \scratchdimen\dimexpr#2+\lineheight\relax + \dorecurse\noflines + {\strut + \hskip-.5\lineheight\relax + \ifcase\gridboxlinenomode\or + \rlap + {\hskip\dimexpr.2\bodyfontsize+\scratchdimen\relax + \infofont\hbox to \emwidth{\hss\recurselevel}}% + \or + \llap + {\infofont\hbox to \emwidth{\hss\recurselevel}% + \hskip.2\bodyfontsize}% + \fi + \vrule + \s!height \gridboxwidth + \s!depth \gridboxwidth + \s!width \scratchdimen + \par}} + \vfill}} + +%D This has become obsolete: + +\def\fuzzysnappedbox#1#2% \box \unvbox + {#1#2} + +\def\moveboxontogrid#1#2#3% will become obsolete, but it needs checking + {} + +%D Helper: + +\unexpanded\def\spac_helpers_assign_skip#1#2% ook nog \v!halfline+fuzzysnap + {\doifelse{#2}\v!line + {#1\ifgridsnapping + \bodyfontlineheight + \else + \openlineheight + \fi} + {\ifgridsnapping + \assigndimension{#2}{#1}{.25\bodyfontlineheight}{.5\bodyfontlineheight}\bodyfontlineheight + \else + \assigndimension{#2}{#1}\smallskipamount\medskipamount\bigskipamount + \fi}% + \relax} + +% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop +% \start \dosetstretch{.5em} effe flink doorfietsen \stop + +% experimental code, not yet interfaced: + +% category: +% +% 0 == discard discard +% 1 == only if larger largest +% 2 == force even if smaller force +% 3 == only take penalty component penalty +% 4 == add to existing skip add +% 5 == disable (ignore following) disable +% 6 == kill whitespace nowhite +% 7 == discard previous back +% 10 == no topskip +% +% penalty: larger wins +% order: larger wins +% category:2,order:5,penalty:10000,skip:value|kw +% +% \defineblankmethod [\v!joinedup] {\ifvmode\nointerlineskip\fi} + +% todo, in grid mode: builders.vspacing.fixed = false +% +% \ifgridsnapping will go + +\installcorenamespace{vspacingamount} + +\unexpanded\def\definevspacingamount + {\dotripleempty\spac_vspacing_define_amount} + +\def\spac_vspacing_define_amount[#1][#2][#3]% can be combined + {\ifthirdargument + \setvalue{\??vspacingamount#1}{\ifgridsnapping#3\else#2\fi}% + \orelse\ifsecondargument + \setvalue{\??vspacingamount#1}{\ifgridsnapping\lineheight\else#2\fi}% + \else + \setvalue{\??vspacingamount#1}{\lineheight}% + \fi + \clf_vspacingsetamount{#1}} + +\def\spac_vspacing_no_topskip % use grouped + {\attribute\skipcategoryattribute\plusten} + +% \installcorenamespace{vspacingamountnormal} +% \installcorenamespace{vspacingamountgrid} + +% \def\spac_vspacing_define_amount[#1][#2][#3]% can be combined +% {\ifcsname n>#1\endcsname\else +% \expandafter\newtoks\csname n>#1\endcsname +% \expandafter\newtoks\csname g>#1\endcsname +% \fi +% \csname n>#1\endcsname{#2}% +% \csname g>#1\endcsname{#3}% +% \clf_vspacingsetamount{#1}} + +\unexpanded\def\definevspacing + {\dodoubleempty\spac_vspacing_define} + +\def\spac_vspacing_define[#1][#2]% + {\clf_vspacingdefine{#1}{#2}} + +%D The injector code (generated at the \LUA\ end): + +\newtoks\everybeforeblankhandling +\newtoks\everyafterblankhandling + +\newconditional\c_space_vspacing_done +\newconditional\c_space_vspacing_fixed +\newconditional\c_space_ignore_parskip + +\appendtoks + \s_spac_vspacing_temp\zeropoint + \attribute\skipcategoryattribute\plusone + \attribute\skippenaltyattribute \attributeunsetvalue + \attribute\skiporderattribute \attributeunsetvalue + \ifgridsnapping + \settrue\c_space_vspacing_fixed + \else + \setfalse\c_space_vspacing_fixed + \fi +\to \everybeforeblankhandling + +\appendtoks + \s_spac_vspacing_temp\plusone\s_spac_vspacing_temp + \ifconditional\c_space_vspacing_fixed \else + \s!plus \skipgluefactor\s_spac_vspacing_temp + \s!minus\skipgluefactor\s_spac_vspacing_temp + \fi + \relax +\to \everyafterblankhandling + +\unexpanded\def\setblankpacked + {\settrue\c_space_ignore_parskip} + +\unexpanded\def\setblankcategory#1% + {\settrue\c_space_vspacing_done + \attribute\skipcategoryattribute#1\relax} + +\unexpanded\def\setblankorder#1% + {\attribute\skiporderattribute#1\relax} + +\unexpanded\def\fixedblankskip + {\settrue\c_space_vspacing_fixed} + +\unexpanded\def\flexibleblankskip + {\setfalse\c_space_vspacing_fixed} + +% \unexpanded\def\addblankskip#1#2#3% +% {\settrue\c_space_vspacing_done +% \advance\s_spac_vspacing_temp#1\dimexpr\ifgridsnapping#3\else#2\fi\relax\relax} + +\unexpanded\def\setblankpenalty#1% + {\flushblankhandling + \settrue\c_space_vspacing_done + \attribute\skipcategoryattribute \plusthree + \attribute\skippenaltyattribute #1\relax + \flushblankhandling} + +\unexpanded\def\startblankhandling % move this to \vspacing + {\par + \ifvmode + \expandafter\dostartblankhandling + \else + \expandafter\nostartblankhandling + \fi} + +\unexpanded\def\nostartblankhandling#1\stopblankhandling + {} + +\def\dostartblankhandling + {\begingroup + \setfalse\c_space_vspacing_done + \setfalse\c_space_ignore_parskip + \the\everybeforeblankhandling} + +\unexpanded\def\stopblankhandling + {\the\everyafterblankhandling + \ifconditional\c_space_vspacing_done + \vskip\s_spac_vspacing_temp + \fi + \ifconditional\c_space_ignore_parskip + \endgroup\ignoreparskip + \else + \endgroup + \fi} + +\unexpanded\def\flushblankhandling + {\the\everyafterblankhandling + \ifconditional\c_space_vspacing_done + \vskip\s_spac_vspacing_temp + \fi + \setfalse\c_space_vspacing_done + \the\everybeforeblankhandling} + +\unexpanded\def\addpredefinedblankskip#1#2% + {\settrue\c_space_vspacing_done + \advance\s_spac_vspacing_temp#1\dimexpr\csname\??vspacingamount#2\endcsname\relax} + +% \unexpanded\def\addpredefinedblankskip#1#2% +% {\settrue\c_space_vspacing_done +% \advance\s_spac_vspacing_temp#1\dimexpr\the\csname\ifgridsnapping g\else n\fi>#2\endcsname\relax} + +\unexpanded\def\addaskedblankskip#1#2% + {\settrue\c_space_vspacing_done + \advance\s_spac_vspacing_temp#1\dimexpr#2\relax} + +% The main spacer: + +\unexpanded\def\vspacing + {\doifelsenextoptionalcs\spac_vspacing_yes\spac_vspacing_nop} + +\def\spac_vspacing_yes + {\ifinpagebody % somewhat weird + \expandafter\spac_vspacing_yes_indeed + \orelse\ifconditional\c_spac_packed_blank + \expandafter\spac_vspacing_yes_indeed + \else + \expandafter\spac_vspacing_yes_ignore + \fi} + +\def\spac_vspacing_nop + {\ifinpagebody % somewhat weird + \expandafter\spac_vspacing_nop_indeed + \orelse\ifconditional\c_spac_packed_blank + \expandafter\spac_vspacing_nop_indeed + \else + \expandafter\spac_vspacing_nop_ignore + \fi} + +\def\spac_vspacing_yes_indeed[#1]% + {\ifmmode\else\par\clf_vspacing{#1}\fi} + +\def\spac_vspacing_yes_ignore[#1]% + {\ifmmode\else\par\fi} + +\def\spac_vspacing_nop_indeed + {\ifmmode\else\par\clf_vspacing{\currentvspacing}\fi} + +\def\spac_vspacing_nop_ignore + {\ifmmode\else\par\fi} + +\installcorenamespace{vspacing} + +\unexpanded\def\directvspacing#1% + {\par + \ifchkdim#1\or + \spac_vspacing_dim_preset{\the\dimexpr#1}% + \orelse\ifcsname\??vspacing#1\endcsname + \lastnamedcs + \else + \spac_vspacing_yes_preset{#1}% + \fi} + +\def\spac_vspacing_dim_preset#1% + {\ifcsname\??vspacing#1\endcsname + \lastnamedcs + \else + \spac_vspacing_yes_preset{#1}% + \fi} + +\def\spac_vspacing_yes_preset#1% + {\setxvalue{\??vspacing#1}{\clf_vspacing{#1}}% + %\writestatus{}{}% + %\writestatus{#1}{\expandafter\meaning\csname\??vspacing#1\endcsname}% + %\writestatus{}{}% + \csname\??vspacing#1\endcsname} + +\def\spac_vspacing_yes_indeed[#1]% + {\ifmmode\else + \directvspacing{#1}% + \fi} + +\def\spac_vspacing_nop_indeed + {\ifmmode\else + \directvspacing\currentvspacing + \fi} + +\def\directdefaultvspacing + {\ifinpagebody % somewhat weird + \directvspacing\currentvspacing + \orelse\ifconditional\c_spac_packed_blank + \directvspacing\currentvspacing + \fi} + +\def\directcheckedvspacing + {\ifinpagebody % somewhat weird + \expandafter\directvspacing + \orelse\ifconditional\c_spac_packed_blank + \expandafter\directvspacing + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\useblankparameter#1% faster local variant + {\edef\m_spac_blank_asked{#1\c!blank}% + \ifx\m_spac_blank_asked\empty\else + \directvspacing\m_spac_blank_asked + \fi} + +%D Handy (and faster): + +\unexpanded\def\directvpenalty#1% + {\begingroup + \attribute\skipcategoryattribute \plusthree + \attribute\skippenaltyattribute #1\relax + \attribute\skiporderattribute \attributeunsetvalue + \vskip\zeropoint + \endgroup} + +\unexpanded\def\directvskip#1% + {\begingroup + \attribute\skipcategoryattribute \plusone + \attribute\skippenaltyattribute \attributeunsetvalue + \attribute\skiporderattribute \attributeunsetvalue + \vskip#1\relax + \endgroup} + +%D These depend on bigskipamount cum suis so we'd better sync them: + +\unexpanded\def\setupvspacing + {\doifelsenextoptionalcs\setupvspacing_yes\setupvspacing_nop} + +\let\currentvspacing\s!default % hm, default, standard ... + +\def\setupvspacing_yes[#1]% + {\edef\currentvspacing{#1}% + \spac_whitespace_setup_nop % yes or no, was forgotten + } + +\def\setupvspacing_nop + {\ifx\empty\currentvspacing % mistakenly had an \else + \let\currentvspacing\s!default + \fi + \spac_whitespace_setup_nop} + +\unexpanded\def\restorestandardblank % or default ? + {\let\currentvspacing\v!standard} + +\let\synchronizevspacing\setupvspacing_nop + +%D The \type {category:4} is default. + +\definevspacingamount[\v!none] [\zeropoint] [\zeropoint] +\definevspacingamount[\v!big] [\bigskipamount] [\bodyfontlineheight] +\definevspacingamount[\v!medium] [\medskipamount] [.5\bodyfontlineheight] +\definevspacingamount[\v!small] [\smallskipamount] [.25\bodyfontlineheight] +\definevspacingamount[\v!line] [\openlineheight] [\bodyfontlineheight] +\definevspacingamount[\v!halfline] [.5\openlineheight] [.5\bodyfontlineheight] +\definevspacingamount[\v!quarterline] [.25\openlineheight] [.25\bodyfontlineheight] +\definevspacingamount[\v!formula] [\medskipamount] [.5\bodyfontlineheight] +\definevspacingamount[\v!white] [\parskip] [\bodyfontwhitespace] +\definevspacingamount[\v!height] [\strutht] [\bodyfontstrutheight] +\definevspacingamount[\v!depth] [\strutdp] [\bodyfontstrutdepth] + +\definevspacingamount[\v!standard] [.75\openlineheight] [.75\openlineheight] % mkii compatible + +\def\bodyfontwhitespace + {\dimexpr + \ifdim\parskip=\zeropoint + \zeropoint + \orelse\ifgridsnapping + \bodyfontlineheight + \else + \parskip + \fi + \relax} + +%D used in itemize \unknown\ always test this: + +\newdimen\d_spac_overlay + +\def\spac_overlay_lines + {\directcheckedvspacing{\v!back,\v!overlay}% \blank[\v!back,\v!overlay]% + \nointerlineskip} + +% \startitemize[n] +% \item \input zapf +% \item \startitemize[a] +% \item \input knuth +% \stopitemize +% \stopitemize +% +% \strut \hfill first line \blank[overlay] second line \hfill \strut +% +% \ruledvbox { +% \strut \hfill line 1 \blank[overlay] +% line 2 \hfill \strut \blank[overlay] +% \strut \hfill line 3 \hfill \strut +% } +% +% \dorecurse{50} +% {\startitemize[n] \startitem \startitemize[a] \item #1 \stopitemize \stopitem \stopitemize} + +\definevspacing[\v!preference][penalty:-500] % goodbreak +\definevspacing[\v!samepage] [penalty:10000] % nobreak + +\definevspacing[\v!always] [category:0] % hm, internally it's discard +\definevspacing[\v!max] [category:1] +\definevspacing[\v!force] [category:2] +\definevspacing[\v!disable] [category:5] +\definevspacing[\v!nowhite] [category:6] +\definevspacing[\v!back] [category:7] +\definevspacing[\v!packed] [category:8] % noparskip (kind of special) +\definevspacing[\v!overlay] [category:9] +\definevspacing[\v!enable] [category:10] + +%definevspacing[\v!noparskip] [category:8] +%definevspacing[\v!notopskip] [category:11] + +\definevspacing[\v!weak] [order:0] +\definevspacing[\v!strong] [order:100] + +\definevspacing[\s!default] [\v!white] % was big for a while + +\newcount\c_spac_vspacing_special_base \c_spac_vspacing_special_base = 32250 % 4000 +\newcount\c_spac_vspacing_special_step \c_spac_vspacing_special_step = 10 % 250 +\newcount\c_spac_vspacing_special_done + +% 2019-05-31 : upgraded a bit to more distinctive samepage-[level]-[0|1|2] names + +\unexpanded\def\spac_vspacing_define_same_step#1#2% alternatively we could have samepage-n-m + {\begingroup + \scratchcounterone\numexpr\plusthree*#1+#2\relax + \scratchcountertwo\numexpr\c_spac_vspacing_special_base+\c_spac_vspacing_special_step*\scratchcounterone\relax + %\writestatus{defined}{\v!samepage-\number#1-\number#2\space=>\space penalty:\the\scratchcountertwo}% + \normalexpanded{\definevspacing[\v!samepage-\number#1-\number#2][penalty:\the\scratchcountertwo]}% + \endgroup} + +\unexpanded\def\spac_vspacing_define_same_page#1% + {\dostepwiserecurse\c_spac_vspacing_special_done{#1}\plusone + {\spac_vspacing_define_same_step\recurselevel\zerocount % before + \spac_vspacing_define_same_step\recurselevel\plusone % after + \spac_vspacing_define_same_step\recurselevel\plustwo}% % whatever + \global\c_spac_vspacing_special_done#1\relax} + +\spac_vspacing_define_same_page{12} % 12 levels should be more than enough as a start + +\def\spac_vspacing_same_page#1#2% level offset (starts at 0) + {\ifnum#1>\c_spac_vspacing_special_done + \spac_vspacing_define_same_page{#1}% + \fi + %\writestatus{used}{\v!samepage-\number#1-\number#2}% + \vspacing[\v!samepage-\number#1-\number#2]} + +\definevspacing[\v!default] [\v!big] % todo: needs to adapt to \setupblank +\definevspacing[\v!before] [\v!default] % but we need to avoid circular references +\definevspacing[\v!inbetween][\v!default] % then +\definevspacing[\v!after] [\v!before] + +\setupvspacing + [\v!big] % alternatively [\v!standard] + +%D Maybe at some point we will differ between \type {\vspacing} and \type {\blank} +%D (we needed the first one while playing with the new code). + +% We keep this one as reference +% +% \unexpanded\def\inhibitblank +% {\vspacing[\v!disable]} +% +% but use the following more efficient variant instead: + +\unexpanded\def\inhibitblank + {\ifvmode + \begingroup + \attribute\skipcategoryattribute\plusfive + \vskip\zeropoint + \endgroup + \fi} + +\let\doinhibitblank\inhibitblank % keep this command, used in styles + +\let\defineblank \definevspacing +\let\setupblank \setupvspacing +\let\blank \vspacing +\let\synchronizeblank \synchronizevspacing +\let\defineblankmethod\definevspacingamount + +%D The following command is for Wolfgang. It has to be used with care as it does +%D {\em not} work in tandem with the other spacing commands. + +\installcorenamespace{vspace} + +\unexpanded\def\definevspace + {\dotripleempty\spac_vspace_define} + +\def\spac_vspace_define[#1][#2][#3]% + {\ifthirdargument + \setvalue{\??vspace#1:#2}{#3}% + \else + \setvalue{\??vspace:#1}{#2}% + \fi} + +\letvalue{\??vspace:\s!unknown}\zeropoint + +\unexpanded\def\vspace + {\dodoubleempty\spac_vspace_inject} + +\def\spac_vspace_unknown + {\csname\??vspace:\s!unknown\endcsname} + +\def\spac_vspace_inject[#1][#2]% use \lastnamedcs + {\par + \ifvmode + \removelastskip + \vskip + \ifsecondargument + \ifcsname\??vspace#1:#2\endcsname + \lastnamedcs + \orelse\ifcsname\??vspace:#2\endcsname + \lastnamedcs + \else + \spac_vspace_unknown + \fi + \orelse\iffirstargument + \ifcsname\??vspace:#1\endcsname + \lastnamedcs + \else + \spac_vspace_unknown + \fi + \else + \ifcsname\??vspace:\s!default\endcsname + \lastnamedcs + \else + \spac_vspace_unknown + \fi + \fi + \relax + \fi} + +%D Some preliminary code: a simple and fast hanger, for usage in macros. + +\installcorenamespace {hanging} + +\installdirectcommandhandler \??hanging {hanging} + +\setuphanging + [\c!distance=.5\emwidth, + \c!location=\v!left, + \c!n=\zerocount] + +\unexpanded\def\starthanging + {\dontleavehmode\bgroup + \dosingleempty\spac_hanging_start} + +\unexpanded\def\stophanging + {\endgraf + \egroup} + +\let\m_spac_hanging_location\empty + +\def\spac_hanging_start[#1]% + {\doifelseassignment{#1} + {\let\m_spac_hanging_location\empty + \setupcurrenthanging[#1]}% + {\edef\m_spac_hanging_location{#1}}% + \ifx\m_spac_hanging_location\empty + \edef\m_spac_hanging_location{\directhangingparameter\c!location}% + \fi + \dowithnextboxcs\spac_hanging_finish\hbox} + +\def\spac_hanging_finish + {\scratchdistance\directhangingparameter\c!distance\relax + \ifdim\ht\nextbox>\strutht + \setbox\nextbox\tbox{\box\nextbox}% + \fi + \scratchcounter\directhangingparameter\c!n\relax + \ifnum\scratchcounter>\zerocount + \hangafter-\scratchcounter + \else + \getboxheight\scratchdimen\of\box\nextbox + \getnoflines\scratchdimen + \hangafter-\noflines + \fi + \ht\nextbox\strutht + \dp\nextbox\strutdp + \scratchwidth\dimexpr\wd\nextbox+\scratchdistance\relax + \ifx\m_spac_hanging_location\v!right + \hangindent\ifconditional\displaylefttoright-\fi\scratchwidth + \rlap{\hskip\dimexpr\hsize-\leftskip-\wd\nextbox\relax\box\nextbox}% \leftskip is new + \else + \hangindent\ifconditional\displaylefttoright\else-\fi\scratchwidth + \llap{\box\nextbox\hskip\scratchdistance}% + \fi + \ignorespaces} + + +%D \macros +%D {startfixed} +%D +%D \starttyping +%D \startitemize +%D \startitem \externalfigure[cow][height=1cm] \stopitem +%D \startitem \externalfigure[cow][height=1cm] \stopitem +%D +%D \startitem \startfixed \externalfigure[cow][height=1cm]\stopfixed \stopitem +%D \startitem \startfixed[high]\externalfigure[cow][height=1cm]\stopfixed \stopitem +%D \startitem \startfixed[low] \externalfigure[cow][height=1cm]\stopfixed \stopitem +%D \startitem \startfixed[lohi]\externalfigure[cow][height=1cm]\stopfixed \stopitem +%D +%D \startitem test \par \startfixed \externalfigure[koe][height=1cm]\stopfixed \stopitem +%D \startitem test \par \startfixed[high]\externalfigure[koe][height=1cm]\stopfixed \stopitem +%D \startitem test \par \startfixed[low] \externalfigure[koe][height=1cm]\stopfixed \stopitem +%D \startitem test \par \startfixed[lohi]\externalfigure[koe][height=1cm]\stopfixed \stopitem +%D \stopitemize +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\installcorenamespace{fixedalternatives} + +\unexpanded\def\startfixed + {\bgroup + \dosingleempty\typo_fixed_start} + +\def\typo_fixed_start + {\ifhmode + \expandafter\typo_fixed_start_h + \else + \expandafter\typo_fixed_start_v + \fi} + +\def\typo_fixed_start_h[#1]% + {\let\stopfixed\typo_fixed_stop_h + \dowithnextbox{\typo_fixed_finish{#1}}% + \vbox\bgroup + %ignorespaces + \setlocalhsize} + +\unexpanded\def\typo_fixed_stop_h + {%removeunwantedspaces + \egroup + \egroup} + +\def\typo_fixed_start_v[#1]% + {\let\stopfixed\typo_fixed_stop_v + \startbaselinecorrection} + +\unexpanded\def\typo_fixed_stop_v + {\stopbaselinecorrection + \egroup} + +\letvalue{\??fixedalternatives \v!high}\bbox +\letvalue{\??fixedalternatives \v!low}\tbox +\letvalue{\??fixedalternatives \v!middle}\vcenter +\letvalue{\??fixedalternatives \v!lohi}\vcenter +\letvalue{\??fixedalternatives\s!unknown}\tbox +\letvalue{\??fixedalternatives\s!default}\tbox + +\unexpanded\def\typo_fixed_finish#1% + {\expandnamespacevalue\??fixedalternatives{#1}\s!default{\box\nextbox}} + +% %D Forgotten already: +% +% \def\shapefill{\vskip\zeropoint\s!plus\lineheight\s!minus\lineheight\relax} + +%D Nasty: + +% \writestatus{1}{\the\prevdepth} \blank[force,5*big] { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page +% \writestatus{2}{\the\prevdepth} \blank[force,5*big] { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page +% \writestatus{3}{\the\prevdepth} \blank[force,5*big] { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page +% \writestatus{4}{\the\prevdepth} \input tufte \page +% \writestatus{5}{\the\prevdepth} \input tufte \page +% \writestatus{6}{\the\prevdepth} \blank[force,5*big] { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page + +% \writestatus{1}{\the\prevdepth} \null\vskip4cm { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page +% \writestatus{2}{\the\prevdepth} \null\vskip4cm { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page +% \writestatus{3}{\the\prevdepth} \null\vskip4cm { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page +% \writestatus{4}{\the\prevdepth} \input tufte \page +% \writestatus{5}{\the\prevdepth} \input tufte \page +% \writestatus{6}{\the\prevdepth} \null\vskip4cm { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page + +\appendtoks + \ifvmode\prevdepth\zeropoint\fi % consistent, else first page -1000pt .. needed for fixed,3*big first/successive pages consistency +\to \everystarttext + +\prevdepth\zeropoint + +%D Helper: + +\unexpanded\def\checkedblank[#1]% + {\edef\p_blank{#1}% + \ifx\p_blank\empty + % ignore + \orelse\ifx\p_blank\v!none + % ignore + \else + \blank[\p_blank]% + \fi} + +% \setupwhitespace[line] +% \prerollblank[2*line] \the\prerolledblank +% \prerollblank[-2*line] \the\prerolledblank + +\newskip\prerolledblank + +\unexpanded\def\prerollblank[#1]% + {\begingroup + \edef\p_blank{#1}% + \ifx\p_blank\empty + \global\prerolledblank\zeropoint + \orelse\ifx\p_blank\v!none + \global\prerolledblank\zeropoint + \else + % don't mess with \arskip here! + \scratchskip\plusten\lineheight + \setbox\scratchbox\vbox + {\vskip\scratchskip + \kern\zeropoint + \blank[\p_blank]}% + % \dimexpr doesn't work well with skips + \advance\scratchskip-\ht\scratchbox + \global\prerolledblank-\scratchskip + \fi + \endgroup} + +\newcount\c_spac_vspacing_ignore_parskip + +% \setupwhitespace[line] +% \setuphead[subject][after={\blank[packed]},style=\bfb] +% \subject{foo} +% test \par +% test \par +% \blank[packed] % \ignoreparskip +% test \par +% test \par +% \ignoreparskip +% test \par +% test \par +% \setuphead[subject][after={\blank[nowhite]},style=\bfb] +% \subject{foo} +% test \par +% test \par + +\unexpanded\def\ignoreparskip{\c_spac_vspacing_ignore_parskip\plusone} + +\protect \endinput diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf index d65f4089b..c0b856eb0 100644 Binary files a/tex/context/base/mkiv/status-files.pdf and b/tex/context/base/mkiv/status-files.pdf differ diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf index 2db709d41..5d07a4305 100644 Binary files a/tex/context/base/mkiv/status-lua.pdf and b/tex/context/base/mkiv/status-lua.pdf differ diff --git a/tex/context/base/mkiv/strc-itm.mklx b/tex/context/base/mkiv/strc-itm.mklx new file mode 100644 index 000000000..959801c8b --- /dev/null +++ b/tex/context/base/mkiv/strc-itm.mklx @@ -0,0 +1,1854 @@ +%D \module +%D [ file=strc-itm, +%D version=2008.10.20, +%D title=\CONTEXT\ Structure Macros, +%D subtitle=Itemgroups, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Structure Macros / Itemgroups} + +\registerctxluafile{strc-itm}{} + +%D As we analyze/register widths and such we could as well push and pop the numbers +%D at the \LUA\ end (which saves a few calls). +%D +%D Cleaning up this module happened around the time when Kate Bush came up with the +%D nicest numbered list of words: 50 Words For Snow. It's therefore no surprise that +%D I had that cd running several times when updating this code. One of the +%D highlights of 2011. +%D +%D This module needs to be rewritten but that is tricky with respect to +%D compatibilitity. Basically each major variant (regular, text, columns, +%D horizontal, etc) needs to be on its own. + +% todo: check breaks +% todo: check grouping +% todo: fixedconversion + +% \startitemize[n,packed] +% \item test \item test \item test +% \stopitemize +% +% \startitemize[n,packed,reverse] +% \item test \item test \item test +% \stopitemize +% +% \startitemize[n,packed,reverse] \item test \item test \stopitemize +% \startitemize[continue] +% \item test \startitemize[n,packed] \item test \item test \stopitemize +% \item test +% \item test +% \stopitemize +% \startitemize[continue] \item test \stopitemize +% +% \startitemize[n,packed] \item test \item test \stopitemize +% \startitemize[continue] \item test \stopitemize +% \startitemize[continue] \item test \stopitemize +% +% \setupwhitespace[big] +% \starttext +% test \startitemize[joinedup] \item test \item test \stopitemize test \par +% test \startitemize[joinedup,nowhite] \item test \item test \stopitemize test \par +% test \startitemize[joinedup,nowhite,before] \item test \item test \stopitemize test \par +% test \startitemize[joinedup,nowhite,after] \item test \item test \stopitemize test \par +% \stoptext +% +% test / example +% +% \startnarrower[left] \startcolumns[n=3] \startitemize +% \item \input ward \item \input ward \item \input ward +% \stopitemize \stopcolumns\stopnarrower \blank +% +% \startnarrower[left] \startitemize[columns,three] +% \item \input ward \item \input ward \item \input ward +% \stopitemize \stopnarrower \blank +% +% \setupitemize[leftmargin=1.5em] \startitemize[columns,three] +% \item \input ward \item \input ward \item \input ward +% \stopitemize \blank +% +% beware, we don't group (yet) as we want to keep the left/right skip +% +% \startitemize +% \startitem \stopitem +% some intermediate text that will properly indent +% \startitem \stopitem +% \stopitem +% +% so we need to keep that property +% +% \startitemize +% \starthead {xx} test \stophead +% \startitem test \stopitem +% \startitem test \stopitem +% \stopitemize +% +% Sometimes the user demands get pretty weird: +% +% \startitemize +% \item test +% \item test +% \headsym{xx} test \par test +% \stopitemize +% +% aligned items +% +% \startitemize[n,fit,broad][itemalign=flushright] +% \dorecurse{100}{\item The first item.} +% \stopitemize +% +% \setupitemgroup[itemize][each][fit] +% \setupitemgroup[itemize][each][distance=.5em,factor=1,itemalign=flushright] +% +% \startitemize[n] +% \dorecurse{100}{\item The first item.} +% \stopitemize +% +% \defineitemgroup[gbitemize] +% \setupitemgroup[gbitemize][each][headstyle=bold] +% +% \startgbitemize +% \txt{italian} some italians like this kind of cross||breed between +% an itemize and a description +% \txt{sicilians} i wonder how many sicilian mathematicians do a thesis +% on the math involved in predicting the next big bang of the vulcano +% \stopgbitemize +% +% \startitemize[n,repeat] +% \noitem \startitemize[a] \item Item 1.a. \item Item 1.b. \stopitemize +% \noitem \startitemize[a] \item Item 2.a. \item Item 2.b. \stopitemize +% \stopitemize +% +% \startitemize[n,repeat][width=0pt] +% \noitem \startitemize[a][width=2em] \item Item 1.a. \item Item 1.b. \stopitemize +% \noitem \startitemize[a][width=2em] \item Item 2.a. \item Item 2.b. \stopitemize +% \stopitemize +% +% \startbuffer +% \item +% \startitemize[n] +% \item item 1.1 +% \item item 1.2 +% \startitemize[n] \item item 1.2.1 \item item 1.2.2 \stopitemize +% \item item 1.3 +% \stopitemize +% \item +% \startitemize[n] \item item 2.1 \item item 2.2 \stopitemize +% \item item 3 +% \startitemize[n] \item item 3.1 \item item 3.2 \stopitemize +% \item +% \startitemize[n] \item item 4.1 \item item 4.2 \stopitemize +% \stopbuffer +% +% \startitemize[n,repeat,6*broad,packed] \getbuffer \stopitemize \blank[3*big] +% \startitemize[n,repeat,packed] \getbuffer \stopitemize \blank[3*big] +% \setupitemize[each][atmargin][width=3em] +% \startitemize[n,repeat,packed] \getbuffer \stopitemize +% +% todo: assume startitem ... stopitem and do an autostopitem .. cleaner for +% elements +% +% \startitemize[text][space=medium] +% \item one \item two \item three +% \stopitemize +% +% For Giuseppe "Oblomov" Bilotta, inspired on a suggestion by Taco +% Hoekwater. +% +% \def\MyItemCommand#1{{\bf#1}\quad} +% \setupitemgroup[itemize][command=\MyItemCommand] +% +% \startitemize +% \item {test} is this okay? +% \item {test} is this okay? +% \item {test} is this okay? +% \stopitemize + +\unprotect + +\newconditional\c_strc_itemgroups_sub +\newconditional\c_strc_itemgroups_head +\newconditional\c_strc_itemgroups_intro +\newconditional\c_strc_itemgroups_randomize +\newconditional\c_strc_itemgroups_horizontal +\newconditional\c_strc_itemgroups_collecting +\newconditional\c_strc_itemgroups_auto_intro +\newconditional\c_strc_itemgroups_pack +\newconditional\c_strc_itemgroups_paragraph +\newconditional\c_strc_itemgroups_text +\newconditional\c_strc_itemgroups_text_saved +\newconditional\c_strc_itemgroups_first +\newconditional\c_strc_itemgroups_before +\newconditional\c_strc_itemgroups_after +\newconditional\c_strc_itemgroups_nowhite +\newconditional\c_strc_itemgroups_joined +\newconditional\c_strc_itemgroups_reverse +\newconditional\c_strc_itemgroups_continue +\newconditional\c_strc_itemgroups_fitting +\newconditional\c_strc_itemgroups_indented_first +\newconditional\c_strc_itemgroups_inline +\newconditional\c_strc_itemgroups_columns +\newconditional\c_strc_itemgroups_concat +\newconditional\c_strc_itemgroups_txt +\newconditional\c_strc_itemgroups_extra +\newconditional\c_strc_itemgroups_repeat + +% 0 = before/after +% 1 = between unless before +% 2 = between + +\newconstant \c_strc_itemgroups_spacing_mode \c_strc_itemgroups_spacing_mode\plustwo +\newconditional\c_strc_itemgroups_optimize \settrue\c_strc_itemgroups_optimize +\newconditional\c_strc_itemgroups_auto_concat \settrue\c_strc_itemgroups_auto_concat + +\newsignal \d_strc_itemgroups_signal + +\newbox \b_strc_itemgroups + +\newdimen \d_strc_itemgroups_list_width +\newdimen \d_strc_itemgroups_asked_width + +\newdimen \d_strc_itemgroups_max_width % multipass +\newcount \c_strc_itemgroups_max_items % multipass + +\newcount \c_strc_itemgroups_n_of_items +\newcount \c_strc_itemgroups_nesting +\newcount \c_strc_itemgroups_column_depth + +\def \v_strc_itemgroups_counter {itemgroup:\currentparentitemgroup} +\let \m_strc_itemgroups_repeat_start \empty +\def \v_strc_itemgroups_unknown_symbol {?} +\let \m_strc_itemgroups_indenting \empty +\let \m_strc_itemgroups_destination \empty + +\let \currentitemlevel \!!zerocount % public +\def \currentnofitems {\the\c_strc_itemgroups_max_items} +\def \currentitemnumber {\strc_counters_raw_sub\v_strc_itemgroups_counter\currentitemlevel} % public + +\newtoks \itemgroupcommands % maybe public + +\def \currentitemgroupsymbol {n} % here we cannot use a _ in the name +\let \currentitemgroupconversionset \empty % here we cannot use a _ in the name +\let \currentitemgroupsegments \empty + +\def\strc_itemgroups_register_status + {\clf_registeritemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\c_strc_itemgroups_n_of_items\dimexpr\itemgroupparameter\c!maxwidth\relax} + +\def\strc_itemgroups_check_n_of_items % we could do this at the lua end and save a call (i.e. will be dimen and counter) + {\clf_analyzeitemgroup{\currentparentitemgroup}\c_strc_itemgroups_nesting\relax + \edef\currentnofitems{\the\c_strc_itemgroups_max_items}} + +% todo: \dodosetreference -> \strc_counters_register_component (to be checked) + +\def\strc_itemgroups_insert_reference % we will make a decent number helper + {\iftrialtypesetting \orelse \ifx\currentitemreference \empty \else + \strc_itemgroups_insert_reference_indeed + \fi} + +\def\strc_itemgroups_insert_extra_reference + {\iftrialtypesetting \orelse \ifx\currentitemreference \empty \else + \normalexpanded{\textreference[\currentitemreference]{\strc_itemgroups_extra_symbol}}% + \fi} + +\def\strc_itemgroups_insert_reference_indeed % maybe we need a 'frozen counter' numberdata blob / quick hack .. .mive this to strc-ref + {% needs testing, gave problems: + \setnextinternalreference + % no need to collect nodes in \b_strc_destination_nodes here ... maybe at some point + \strc_references_start_destination_nodes + % this is somewhat over the top ... we should use the counter's reference + \clf_setdestinationattribute + {% + metadata {% + kind {item}% was item, why? + \ifx\currentreferencecoding\s!xml + xmlroot {\xmldocument}% only useful when text + \fi + catcodes \catcodetable + }% + references {% + internal \locationcount % no: this spoils references + % block {\currentsectionblock}% + view {\interactionparameter\c!focus}% + prefix {\referenceprefix}% + reference {\currentitemreference}% + }% + prefixdata {% + prefix {\namedcounterparameter\v_strc_itemgroups_counter\c!prefix}% + separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixseparatorset}% + conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversion}% + conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconversionset}% + set {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixset}% + segments {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixsegments}% + % segments {\askedprefixsegments}% + connector {\namedcounterparameter\v_strc_itemgroups_counter\c!prefixconnector}% + }% + numberdata {% + numbers {\v_strc_itemgroups_counter}% + separatorset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberseparatorset}% + % conversion {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversion}% + % conversionset {\namedcounterparameter\v_strc_itemgroups_counter\c!numberconversionset}% + % fixedconversion {\currentitemgroupconversionset}% + conversionset {fixed::\currentitemgroupconversionset}% temp hack + % + % for the moment no stopper, we need to make references configurable first + % stopper {\namedcounterparameter\v_strc_itemgroups_counter\c!numberstopper}% + segments {\namedcounterparameter\v_strc_itemgroups_counter\c!numbersegments}% + }% + }% + \relax + \strc_references_stop_destination_nodes + \xdef\currentdestinationattribute{\number\lastdestinationattribute}% + % will become an option: + \ifnum\lastdestinationattribute>\zerocount + \dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup + \strc_references_flush_destination_nodes + \egroup + \fi} + +%D Defining and setup: + +\installcorenamespace{itemgroup} +\installcorenamespace{itemgroupoption} +\installcorenamespace{itemgroupsetting} +\installcorenamespace{itemgroupkeyword} +\installcorenamespace{itemgroupalign} +\installcorenamespace{itemgrouplocal} +\installcorenamespace{itemgroupglobal} +\installcorenamespace{itemgroupdistance} +\installcorenamespace{itemgroupstack} +\installcorenamespace{itemgroupfirst} +\installcorenamespace{itemgroupstart} + +\installcommandhandler \??itemgroup {itemgroup} \??itemgroup + +\let\setupitemgroups\setupitemgroup + +\appendtoks + \setuevalue{\e!start\currentitemgroup}{\startitemgroup[\currentitemgroup]}% + \setuevalue{\e!stop \currentitemgroup}{\stopitemgroup}% + \setuevalue{\e!setup\currentitemgroup\e!endsetup}{\setupitemgroup[\currentitemgroup]}% obsolete + \let\currentparentitemgroup\currentitemgroup + \definecounter[\v_strc_itemgroups_counter]% + % beware ... we cannot use _ as the conversion set is not expanded + % \defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]% +\to \everydefineitemgroup + +%D Global states + +\def\strc_itemgroups_store_continue_state#options#settings% + {\setxvalue{\??itemgroupoption \currentitemgroup}{\strc_itemgroups_process_options{#options}}% + \setgvalue{\??itemgroupsetting\currentitemgroup}{\setupcurrentitemgroup[#settings]}} + +\def\strc_itemgroups_fetch_continue_state + {\csname\??itemgroupoption \currentitemgroup\endcsname + \csname\??itemgroupsetting\currentitemgroup\endcsname} + +\def\strc_itemgroups_reset_continue_state + {\expandafter\glet\csname\??itemgroupoption \currentitemgroup\endcsname\relax + \expandafter\glet\csname\??itemgroupsetting\currentitemgroup\endcsname\relax} + +% These will become keywords. We will also add a feature to keep the while set +% together. + +\definevspacing[\v!item @0] [penalty:0] % allow +\definevspacing[\v!item @10000] [penalty:10000] % no +\definevspacing[\v!item @-5] [penalty:-5] +\definevspacing[\v!item @5] [penalty:5] +\definevspacing[\v!item @500] [penalty:500] % discourage .. too low, 5000 is better + +\def\strc_itemgroups_insert_break_when_needed#break% + {\ifconditional\c_strc_itemgroups_optimize + \ifconditional\c_strc_itemgroups_text \else + #break\relax + \fi + \fi} + +\def\strc_itemgroups_insert_breakallow {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakallow_indeed} +\def\strc_itemgroups_insert_breakno {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_breakno_indeed } +\def\strc_itemgroups_insert_break {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_break_indeed } +\def\strc_itemgroups_insert_nobreak {\strc_itemgroups_insert_break_when_needed\strc_itemgroups_insert_nobreak_indeed } + +\def\strc_itemgroups_insert_breakallow_indeed{\vspacing[\v!item @0]} +\def\strc_itemgroups_insert_breakno_indeed {\vspacing[\v!item @10000]} +\def\strc_itemgroups_insert_break_indeed {\flushnotes + \vspacing[\v!item @-5]} +\def\strc_itemgroups_insert_nobreak_indeed {\flushnotes + \ifinsidecolumns % todo + \vspacing[\v!item @5]% + \else + \vspacing[\v!item @500]% + \fi} + +\unexpanded\def\strc_itemgroups_process_options#options% + {\processcommacommand[#options]\strc_itemgroups_process_option} % expansion of options is handy for xml + +% \installcommalistprocessorcommand \strc_itemgroups_process_option_list \strc_itemgroups_process_option +% +% \unexpanded\def\strc_itemgroups_process_options#options% +% {\normalexpanded{\strc_itemgroups_process_option_list[#options]}} % expansion of options is handy for xml + +\def\strc_itemgroups_process_option#option% + {\edef\itemgroupconstantvalue{#option}% + \ifx\itemgroupconstantvalue\empty\else + \splitatasterisk\itemgroupconstantvalue\itemgroupfirst\itemgroupsecond + \ifx\itemgroupsecond\empty + \let\itemgroupsecond\itemgroupfirst + \let\itemgroupfirst\!!plusone + \fi + \ifcsname\??itemgroupkeyword\itemgroupsecond\endcsname + \lastnamedcs + \else + \strc_itemgroups_set_symbol\itemgroupconstantvalue + \fi + \fi} + +\def\strc_itemgroups_process_set_option_pack + {\ifcase\c_strc_itemgroups_nesting \else + \settrue\c_strc_itemgroups_pack + \fi} + +\def\strc_itemgroups_process_set_option_unpack + {\ifcase\c_strc_itemgroups_nesting\else + \setfalse\c_strc_itemgroups_pack + \fi} + +\setvalue{\??itemgroupkeyword\!!zerocount }{} % ignore 0 +\setvalue{\??itemgroupkeyword\v!packed }{\strc_itemgroups_process_set_option_pack} +\setvalue{\??itemgroupkeyword\v!unpacked }{\strc_itemgroups_process_set_option_unpack} +\setvalue{\??itemgroupkeyword\v!intro }{\settrue\c_strc_itemgroups_intro} % here? not set to false +\setvalue{\??itemgroupkeyword\v!autointro }{\settrue\c_strc_itemgroups_auto_intro} +\setvalue{\??itemgroupkeyword\v!broad }{\ifx\itemgroupfirst\empty + \let\itemgroupfirst\!!plusone + \fi + \letitemgroupparameter\c!factor\itemgroupfirst} +\setvalue{\??itemgroupkeyword\v!text }{\settrue\c_strc_itemgroups_text + \settrue\c_strc_itemgroups_inline + \settrue\c_strc_itemgroups_joined + \strc_itemgroups_process_set_option_pack} +\setvalue{\??itemgroupkeyword\v!before }{\settrue\c_strc_itemgroups_before} +\setvalue{\??itemgroupkeyword\v!after }{\settrue\c_strc_itemgroups_after} +\setvalue{\??itemgroupkeyword\v!nowhite }{\settrue\c_strc_itemgroups_nowhite} +\setvalue{\??itemgroupkeyword\v!margin }{\setitemgroupparameter\c!width{-2em}} % signal +\setvalue{\??itemgroupkeyword\v!inmargin }{\setitemgroupparameter\c!width{-2em}} % signal +\setvalue{\??itemgroupkeyword\v!atmargin }{\ifnum\c_strc_itemgroups_nesting>\plusone + \setitemgroupparameter\c!width{0em}% + \fi} % signal +\setvalue{\??itemgroupkeyword\v!intext }{\settrue\c_strc_itemgroups_inline} +\setvalue{\??itemgroupkeyword\v!loose }{\setfalse\c_strc_itemgroups_optimize} +\setvalue{\??itemgroupkeyword\v!fit }{\settrue\c_strc_itemgroups_fitting} +\setvalue{\??itemgroupkeyword\v!nofit }{\setfalse\c_strc_itemgroups_fitting} +\setvalue{\??itemgroupkeyword\v!paragraph }{\settrue\c_strc_itemgroups_paragraph + \strc_itemgroups_process_set_option_pack} +\setvalue{\??itemgroupkeyword\v!joinedup }{\settrue\c_strc_itemgroups_joined + \strc_itemgroups_process_set_option_pack} +\setvalue{\??itemgroupkeyword\v!notjoinedup}{\setfalse\c_strc_itemgroups_joined} +\setvalue{\??itemgroupkeyword\v!serried }{\edef\itemgroupfirst{-\ifx\itemgroupfirst\empty1\else\itemgroupfirst\fi}% + \letitemgroupparameter\c!factor\itemgroupfirst} +\setvalue{\??itemgroupkeyword\v!stopper }{\letitemgroupparameter\c!placestopper\v!yes} % keep {} +\setvalue{\??itemgroupkeyword\v!nostopper }{\letitemgroupparameter\c!placestopper\v!no} % keep {} +\setvalue{\??itemgroupkeyword\v!repeat }{\settrue\c_strc_itemgroups_repeat} +\setvalue{\??itemgroupkeyword\v!norepeat }{\setfalse\c_strc_itemgroups_repeat} +\setvalue{\??itemgroupkeyword\v!reverse }{\settrue\c_strc_itemgroups_reverse} +\setvalue{\??itemgroupkeyword\v!columns }{\settrue\c_strc_itemgroups_columns} +\setvalue{\??itemgroupkeyword\v!one }{\letitemgroupparameter\c!n\plusone} +\setvalue{\??itemgroupkeyword\v!two }{\letitemgroupparameter\c!n\plustwo} +\setvalue{\??itemgroupkeyword\v!three }{\letitemgroupparameter\c!n\plusthree} +\setvalue{\??itemgroupkeyword\v!four }{\letitemgroupparameter\c!n\plusfour} +\setvalue{\??itemgroupkeyword\v!five }{\letitemgroupparameter\c!n\plusfive} +\setvalue{\??itemgroupkeyword\v!six }{\letitemgroupparameter\c!n\plussix} +\setvalue{\??itemgroupkeyword\v!seven }{\letitemgroupparameter\c!n\plusseven} +\setvalue{\??itemgroupkeyword\v!eight }{\letitemgroupparameter\c!n\pluseight} +\setvalue{\??itemgroupkeyword\v!nine }{\letitemgroupparameter\c!n\plusnine} +%setvalue{\??itemgroupkeyword\v!standard }{\setupcurrentitemgroup +% [\c!width =1.5\emwidth,% +% \c!distance =.5\emwidth,% +% \c!factor =0,% +% \c!inner =,% +% \c!beforehead=,% +% \c!afterhead =\blank,% +% \c!before =\blank,% +% \c!inbetween =\blank,% +% \c!after =\blank]} +\setvalue{\??itemgroupkeyword\v!standard }{\setitemgroupparameter\c!width {1.5\emwidth}% + \setitemgroupparameter\c!distance {.5\emwidth}% + \letitemgroupparameter\c!factor \!!zerocount + \letitemgroupparameter\c!inner \empty + \letitemgroupparameter\c!beforehead\empty + \letitemgroupparameter\c!afterhead \blank + \letitemgroupparameter\c!before \blank + \letitemgroupparameter\c!inbetween \blank + \letitemgroupparameter\c!after \blank} + + +\def\strc_itemgroups_initialize_local + {\setfalse\c_strc_itemgroups_inline + \setfalse\c_strc_itemgroups_concat + \setfalse\c_strc_itemgroups_txt + % + \setfalse\c_strc_itemgroups_reverse + \setfalse\c_strc_itemgroups_intro + \setfalse\c_strc_itemgroups_auto_intro + \setfalse\c_strc_itemgroups_before + \setfalse\c_strc_itemgroups_after + \setfalse\c_strc_itemgroups_nowhite + \setfalse\c_strc_itemgroups_randomize + \setfalse\c_strc_itemgroups_horizontal + \setfalse\c_strc_itemgroups_collecting + \setfalse\c_strc_itemgroups_intro + \setfalse\c_strc_itemgroups_continue + % this will be a constant + \setfalse\c_strc_itemgroups_head + \setfalse\c_strc_itemgroups_sub + \setfalse\c_strc_itemgroups_symbol + \setfalse\c_strc_itemgroups_columns + % to be checked + \let\m_strc_itemgroups_destination\empty + \let\strc_itemgroups_used_symbol \empty % ** start value + \let\strc_itemgroups_margin_symbol\empty + \let\strc_itemgroups_extra_symbol \empty + % + \global\letitemgroupparameter\c!maxwidth\!!zeropoint + } + +\setvalue{\??itemgroupfirst\v!intro }{\settrue\c_strc_itemgroups_intro} +\setvalue{\??itemgroupfirst\v!continue }{\settrue\c_strc_itemgroups_continue} +\setvalue{\??itemgroupfirst\v!random }{\settrue\c_strc_itemgroups_randomize + \settrue\c_strc_itemgroups_collecting} +\setvalue{\??itemgroupkeyword\v!horizontal}{\settrue\c_strc_itemgroups_horizontal + \settrue\c_strc_itemgroups_collecting + \settrue\c_strc_itemgroups_inline + \settrue\c_strc_itemgroups_joined + \strc_itemgroups_process_set_option_pack} + +\def\strc_itemgroups_preset_stage_one#options% + {\processcommacommand[#options]\strc_itemgroups_preset_stage_one_indeed} + +% \installcommalistprocessorcommand \strc_itemgroups_preset_stage_one_list \strc_itemgroups_preset_stage_one_indeed +% +% \def\strc_itemgroups_preset_stage_one#options% +% {\normalexpanded{\strc_itemgroups_preset_stage_one_list[#options]}} + +\def\strc_itemgroups_preset_stage_one_indeed#option% + {\ifcsname\??itemgroupfirst#option\endcsname + \lastnamedcs + \fi} + +\ifdefined\dotagsetitemgroup \else \let\dotagsetitemgroup\relax \fi +\ifdefined\dotagsetitem \else \let\dotagsetitem \gobbleoneargument \fi + +\def\strc_itemgroups_tag_start_group + {\dostarttaggedchained\t!itemgroup\currentparentitemgroup\??itemgroup + \dotagsetitemgroup} + +\def\strc_itemgroups_tag_stop_group + {\dostoptagged} + +\def\strc_itemgroups_before_command + {\ifconditional\c_strc_itemgroups_nowhite + \ifconditional\c_strc_itemgroups_before + \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!before\fi + \else + \nowhitespace + \fi + \orelse\ifconditional\c_strc_itemgroups_joined + % \empty + \else + \itemgroupparameter\c!before + \fi} + +\def\strc_itemgroups_after_command + {\ifconditional\c_strc_itemgroups_nowhite + \ifconditional\c_strc_itemgroups_after + \ifcase\c_strc_itemgroups_nesting\or\itemgroupparameter\c!after\fi + \else + \nowhitespace + \fi + \orelse\ifconditional\c_strc_itemgroups_joined + % \empty + \else + \itemgroupparameter\c!after + \fi} + +\def\strc_itemgroups_between_command + {\ifconditional\c_strc_itemgroups_nowhite + \nowhitespace + \orelse\ifconditional\c_strc_itemgroups_joined + % \empty + \else + \itemgroupparameter\c!inbetween + \fi} + +\def\strc_itemgroups_before_head_command + {\ifconditional\c_strc_itemgroups_nowhite + \nowhitespace + \orelse\ifconditional\c_strc_itemgroups_joined + % \empty + \else + \itemgroupparameter\c!beforehead + \fi} + +\def\strc_itemgroups_after_head_command + {\ifconditional\c_strc_itemgroups_nowhite + \nowhitespace + \orelse\ifconditional\c_strc_itemgroups_joined + % \empty + \else + \itemgroupparameter\c!afterhead + \fi} + +% compatible setup command: + +\let\strc_itemgroups_normal_setup\setupitemgroup + +\unexpanded\def\setupitemgroup + {\doquadrupleempty\strc_itemgroups_setup} + +\def\strc_itemgroups_setup[#category][#levels][#options][#settings]% category level|each options|settings settings|options + {\edef\strc_itemgroups_setup_what{#levels}% + \iffourthargument + \ifx\strc_itemgroups_setup_what\v!each + \strc_itemgroups_setup_each{#category}{#options}% + \strc_itemgroups_setup_each{#category}{#settings}% + \else + \strc_itemgroups_setup_list{#levels}{#category}{#options}% + \strc_itemgroups_setup_list{#levels}{#category}{#settings}% + \fi + \orelse\ifthirdargument + \ifx\strc_itemgroups_setup_what\v!each + \strc_itemgroups_setup_each{#category}{#options}% + \else + \strc_itemgroups_setup_list{#levels}{#category}{#options}% + \fi + \orelse\ifsecondargument + \strc_itemgroups_setup_each{#category}{#levels}% + \else + \strc_itemgroups_normal_setup[#category]% == settings + \fi} + +% can be made a bit faster + +% \def\strc_itemgroups_setup_each#category#whatever% +% {\doifelseassignment{#whatever} +% {\strc_itemgroups_normal_setup[#category][#whatever]} +% {\strc_itemgroups_normal_setup[#category][\c!option={#whatever}]}} + +\def\strc_itemgroups_setup_each#category#whatever% + {\ifcondition\validassignment{#whatever}% + \strc_itemgroups_normal_setup[#category][#whatever]% + \else + \strc_itemgroups_normal_setup[#category][\c!option={#whatever}]% + \fi} + +\def\strc_itemgroups_setup_list_level_a#category#whatever#level% + {\strc_itemgroups_normal_setup[#category:#level][#whatever]} + +\def\strc_itemgroups_setup_list_level_b#category#whatever#level% + {\strc_itemgroups_normal_setup[#category:#level][\c!option={#whatever}]} + +% \def\strc_itemgroups_setup_list#subcategories#category#whatever% +% {\doifelseassignment{#whatever} +% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}} +% {\processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}}} + +\def\strc_itemgroups_setup_list#subcategories#category#whatever% + {\ifcondition\validassignment{#whatever}% + \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_a{#category}{#whatever}}% + \else + \processcommalist[#subcategories]{\strc_itemgroups_setup_list_level_b{#category}{#whatever}}% + \fi} + +\def\strc_itemgroups_increment_item_counter + {\ifconditional\c_strc_itemgroups_sub \else + \ifconditional\c_strc_itemgroups_symbol \else % \ifx\strc_itemgroups_extra_symbol\empty + \strc_counters_increment_sub\v_strc_itemgroups_counter\currentitemlevel + \fi + \fi} + +\unexpanded\def\strc_itemgroups_insert_item_counter + {\ifconditional\c_strc_itemgroups_repeat + \ifcase\c_strc_itemgroups_nesting + % skip + \or + \strc_itemgroups_insert_item_counter_indeed % this could become an option + \else + \strc_itemgroups_insert_item_counter_indeed + \fi + \else + \strc_itemgroups_insert_item_counter_indeed + \fi} + +\def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it + {\begingroup % can be optimized ... best move some to strc-num + \setupcounter + [\v_strc_itemgroups_counter]% + [\c!prefix=\itemgroupparameter\c!prefix, + \c!prefixstopper=\itemgroupparameter\c!prefixstopper, + \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset, + \c!prefixconversion=\itemgroupparameter\c!prefixconversion, + \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset, + \c!prefixset=\itemgroupparameter\c!prefixset, + \c!prefixsegments=\itemgroupparameter\c!prefixsegments, + \c!prefixconnector=\itemgroupparameter\c!prefixconnector, + \c!criterium=\itemgroupparameter\c!criterium, + \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi, + \c!numberstopper=\expdoif{\itemgroupparameter\c!placestopper}\v!yes{\itemgroupparameter\c!stopper}, + \c!numberconversionset=\v_strc_itemgroups_counter, + \c!numbersegments=\currentitemgroupsegments]% + % there will be a fixedconversion key + %\normalexpanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}% + \normalexpanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}% + % + \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]% + \strc_itemgroups_insert_reference + \endgroup} + +% needs testing (maybe it need to happen later) +% +% \appendtoks +% \setupcounter +% [\v_strc_itemgroups_counter]% +% [\c!prefix=\itemgroupparameter\c!prefix, +% \c!prefixstopper=\itemgroupparameter\c!prefixstopper, +% \c!prefixseparatorset=\itemgroupparameter\c!prefixseparatorset, +% \c!prefixconversion=\itemgroupparameter\c!prefixconversion, +% \c!prefixconversionset=\itemgroupparameter\c!prefixseparatorset, +% \c!prefixset=\itemgroupparameter\c!prefixset, +% \c!prefixsegments=\itemgroupparameter\c!prefixsegments, +% \c!prefixconnector=\itemgroupparameter\c!prefixconnector, +% \c!criterium=\itemgroupparameter\c!criterium, +% \c!numberorder=\ifconditional\c_strc_itemgroups_reverse\v!reverse\else\v!normal\fi, +% \c!numberstopper=\expdoif{\itemgroupparameter\c!placestopper}\v!yes{\itemgroupparameter\c!stopper}, +% \c!numberconversionset=\v_strc_itemgroups_counter, +% \c!numbersegments=\currentitemgroupsegments]% +% \to\itemgroupcommands +% +% \def\strc_itemgroups_insert_item_counter_indeed % quite slow ... every time this setup .. but it +% {\begingroup % can be optimized ... best move some to strc-num +% % there will be a fixedconversion key +% %\normalexpanded{\defineconversionset[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}% +% \normalexpanded{\strc_sets_define_conversion_set[\v_strc_itemgroups_counter][\currentitemgroupconversionset][\currentitemgroupsymbol]}% +% % +% \convertedcounter[\v_strc_itemgroups_counter]% [\number\currentitemlevel]% +% \strc_itemgroups_insert_reference +% \endgroup} + +\def\strc_itemgroups_set_symbol#symbol% + {\edef\strc_itemgroups_tmp_symbol{#symbol}% + \ifx\strc_itemgroups_tmp_symbol\empty \else + \doifelsesymboldefined\strc_itemgroups_tmp_symbol + \strc_itemgroups_set_symbol_symbol + {\doifelseconversiondefined\strc_itemgroups_tmp_symbol + \strc_itemgroups_set_symbol_conversion + \donothing}% + \fi} + +\def\strc_itemgroups_set_symbol_symbol + {\let\currentitemgroupsymbol\strc_itemgroups_tmp_symbol + \strc_itemgroups_store_global_symbol\currentitemgroupsymbol + \strc_itemgroups_store_local_symbol\v_strc_itemgroups_unknown_symbol + \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_symbol_item + \let\strc_itemgroups_asked_symbol\empty} + +\def\strc_itemgroups_set_symbol_conversion + {\let\currentitemgroupsymbol\strc_itemgroups_tmp_symbol + \strc_itemgroups_store_global_symbol\currentitemgroupsymbol + \strc_itemgroups_store_local_symbol\strc_itemgroups_insert_item_counter + \let\strc_itemgroups_used_symbol\strc_itemgroups_set_symbol_conversion_item + \let\strc_itemgroups_asked_symbol\empty} + +\def\strc_itemgroups_set_symbol_symbol_item + {\symbol[\currentitemgroupsymbol]} + +\def\strc_itemgroups_set_symbol_conversion_item + {\ifconditional\c_strc_itemgroups_text + % maybe block stopper here, but one can as well clone an itemgroup then + \itemgroupparameter\c!lefttext + \strc_itemgroups_fetch_local_symbol + \itemgroupparameter\c!righttext + \else + \itemgroupparameter\c!left + \strc_itemgroups_fetch_local_symbol + \itemgroupparameter\c!right + \fi} + +\def\strc_itemgroups_calculate_list_width#level% + {\let\savedcurrentitemgroup\currentitemgroup + \edef\currentitemgroup{\currentparentitemgroup:\number#level}% + \ifdim\d_strc_itemgroups_max_width>\zeropoint + \d_strc_itemgroups_list_width\d_strc_itemgroups_max_width + \orelse\ifnum\itemgroupparameter\c!factor>\zerocount + \d_strc_itemgroups_list_width\itemgroupparameter\c!step\relax + \ifdim\d_strc_itemgroups_list_width=\zeropoint \d_strc_itemgroups_list_width=.5em\fi + \multiply\d_strc_itemgroups_list_width \itemgroupparameter\c!factor + \advance\d_strc_itemgroups_list_width\itemgroupparameter\c!width\relax + \else + \d_strc_itemgroups_list_width\itemgroupparameter\c!width\relax + \fi + \advance\d_strc_itemgroups_list_width\itemgroupparameter\c!distance\relax + \let\currentitemgroup\savedcurrentitemgroup} + +\unexpanded\def\startitemgroup + {\dotripleempty\strc_itemgroups_start} + +\def\strc_itemgroups_start[#category][#options][#settings]% + {\begingroup % (1) + \def\currentitemgroup{#category}% no nested mixing of itemgroups + \let\currentparentitemgroup\currentitemgroup + \global\advance\c_strc_itemgroups_nesting\plusone + \def\currentitemlevel{\number\c_strc_itemgroups_nesting}% + \normalexpanded{\chaintocurrentitemgroup{\currentparentitemgroup:\currentitemlevel}}% + \edef\currentitemgroup{\currentparentitemgroup:\currentitemlevel}% + % + \ifthirdargument + \strc_itemgroups_start_indeed[#options][#settings]% + \orelse\ifsecondargument + \ifcondition\validassignment{#options}% + \strc_itemgroups_start_indeed[][#options]% + \else + \strc_itemgroups_start_indeed[#options][]% + \fi + \else + \strc_itemgroups_start_indeed[][]% + \fi} + +\def\strc_itemgroups_start_indeed[#options][#settings]% + {\edef\itemgroupoptions{\itemgroupparameter\c!option}% + \edef\itemgroupextraoptions{#options}% + \ifx\itemgroupoptions\empty + \let\itemgroupoptions\itemgroupextraoptions + \orelse\ifx\itemgroupextraoptions\empty + % ok + \else + \edef\itemgroupoptions{\itemgroupoptions,\itemgroupextraoptions}% + \fi + \begingroup % (2) + \the\itemgroupcommands + \let\c_strc_itemgroups_text_saved\c_strc_itemgroups_text + \strc_itemgroups_initialize_local + \strc_itemgroups_preset_stage_one\itemgroupoptions +% +% \ifhmode +% \ifconditional\c_strc_itemgroups_auto_concat +% \ifdim\lastskip=\d_strc_itemgroups_signal +% \settrue\c_strc_itemgroups_concat +% \fi +% \fi +% \ifconditional\c_strc_itemgroups_text_saved \else +% \ifconditional\c_strc_itemgroups_text \else +% \par +% \fi +% \fi +% \fi +% + \iftrialtypesetting + \strc_counters_save\v_strc_itemgroups_counter + \fi + \c_strc_itemgroups_n_of_items\zerocount + \strc_itemgroups_check_n_of_items + \ifx\itemgroupoptions\empty + \strc_itemgroups_setup_symbol_default + \strc_itemgroups_reset_continue_state + \setupcurrentitemgroup[#settings]% + \else + \strc_itemgroups_process_options\itemgroupoptions + \setupcurrentitemgroup[#settings]% + \ifconditional\c_strc_itemgroups_continue + \strc_itemgroups_setup_symbol_continue + \strc_itemgroups_fetch_continue_state + \else + \strc_itemgroups_setup_symbol_asked + \strc_itemgroups_store_continue_state\itemgroupoptions{#settings}% + \fi + \fi + % + \ifhmode + \ifconditional\c_strc_itemgroups_auto_concat + \ifdim\lastskip=\d_strc_itemgroups_signal + \settrue\c_strc_itemgroups_concat + \fi + \fi + \ifconditional\c_strc_itemgroups_text_saved \else + \ifconditional\c_strc_itemgroups_text \else + \par + \fi + \fi + \fi + % + \ifnum\c_strc_itemgroups_nesting=\plusone % NIEUW + \doadaptleftskip {\itemgroupparameter\c!margin}% + \doadaptleftskip {\itemgroupparameter\c!leftmargin}% + \doadaptrightskip{\itemgroupparameter\c!rightmargin}% + \fi + % + \doadaptleftskip {\itemgroupparameter\c!leftmargindistance}% + \doadaptrightskip{\itemgroupparameter\c!rightmargindistance}% + % + \usealignparameter\itemgroupparameter + \edef\m_strc_itemgroups_indenting{\itemgroupparameter\c!indenting}% + \ifnum\c_strc_itemgroups_nesting>\zerocount + \settrue\c_strc_itemgroups_first + \ifconditional\c_strc_itemgroups_continue \else + \strc_counters_restart_sub\v_strc_itemgroups_counter\currentitemlevel{\numexpr\itemgroupparameter\c!start-\plusone\relax}% + \fi + \fi + \ifx\strc_itemgroups_used_symbol\empty + \strc_itemgroups_set_symbol\strc_itemgroups_asked_symbol % ** default value + \ifx\strc_itemgroups_used_symbol\empty + \let\currentitemgroupsymbol\currentitemlevel % ** fall back + \fi + \fi + \ifconditional\c_strc_itemgroups_auto_intro\ifnum\prevgraf<\plusthree + \settrue\c_strc_itemgroups_intro + \fi\fi + \ifconditional\c_strc_itemgroups_paragraph + \ifnum\c_strc_itemgroups_nesting>\plusone + \letitemgroupparameter\c!inbetween\empty + \fi + \fi + \ifconditional\c_strc_itemgroups_pack + \letitemgroupparameter\c!inbetween\empty + \fi + \ifconditional\c_strc_itemgroups_columns + \ifinsidecolumns\else\ifcase\c_strc_itemgroups_column_depth + \global\c_strc_itemgroups_column_depth\c_strc_itemgroups_nesting % global ? + \strc_itemgroups_before_command + \strc_itemgroups_tag_start_group + \strc_itemgroups_start_columns + \fi\fi + \fi + \ifconditional\c_strc_itemgroups_fitting + \ifdim\d_strc_itemgroups_max_width>\zeropoint + \letitemgroupparameter\c!width\d_strc_itemgroups_max_width + \fi + \fi + \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting + \ifdim\d_strc_itemgroups_list_width>\zeropoint\relax + \ifconditional\c_strc_itemgroups_inline\else + \advance\leftskip\d_strc_itemgroups_list_width\relax + \fi + \fi + \ifx\m_strc_itemgroups_repeat_start\empty + \let\currentitemgroupconversionset \currentitemgroupsymbol + \edef\currentitemgroupsegments {\currentitemlevel}% + \else + \edef\currentitemgroupconversionset{\currentitemgroupconversionset,\currentitemgroupsymbol}% + \edef\currentitemgroupsegments {\m_strc_itemgroups_repeat_start:\currentitemlevel}% + \fi + \d_strc_itemgroups_asked_width\itemgroupparameter\c!width\relax + \startcollectitems} + +\let\startcollectitems\relax +\let\stopcollectitems \relax + +\letvalue{\??itemgroupalign\v!flushleft }\relax +\letvalue{\??itemgroupalign\v!right }\relax +\letvalue{\??itemgroupalign\v!flushright}\hfill +\letvalue{\??itemgroupalign\v!left }\hfill +\letvalue{\??itemgroupalign\v!middle }\hfil +\letvalue{\??itemgroupalign\v!center }\hfil + +\def\strc_itemgroups_left_sym_filler + {\csname\??itemgroupalign\itemgroupparameter\c!symalign\endcsname} + +% symbols + states + +\def\strc_itemgroups_store_global_symbol#symbol% + {\letgvalue{\??itemgroupglobal\currentitemlevel}#symbol} + +\def\strc_itemgroups_store_local_symbol#symbol% + {\letgvalue{\??itemgrouplocal\currentitemlevel}#symbol} + +\def\strc_itemgroups_fetch_global_symbol + {\csname\??itemgroupglobal\currentitemlevel\endcsname} + +\def\strc_itemgroups_fetch_local_symbol + {\csname\??itemgrouplocal\currentitemlevel\endcsname} + +\def\strc_itemgroups_setup_symbol_default + {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}% + \strc_itemgroups_store_global_symbol\empty} + +\def\strc_itemgroups_setup_symbol_continue + {\ifcsname\??itemgroupglobal\currentitemlevel\endcsname + \let\strc_itemgroups_asked_symbol\strc_itemgroups_fetch_global_symbol + \else + \let\strc_itemgroups_asked_symbol\currentitemlevel + \fi} + +\def\strc_itemgroups_setup_symbol_asked + {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}} + +\ifdefined\strc_itemgroups_start_columns + + % already defined in page-mix + +\else + + % will be redefined in page-mix + + \ifdefined\startcolumns \else + \unexpanded\def\startcolumns[#settings]{} + \unexpanded\def\stopcolumns {} + \fi + + \def\strc_itemgroups_start_columns + {\startcolumns + [\c!n=\itemgroupparameter\c!n, + \c!height=, + \c!rule=\v!off, + \c!balance=\v!yes, + \c!align=\v!no]} + + \def\strc_itemgroups_stop_columns + {\stopcolumns} + +\fi + +\unexpanded\def\stopitemgroup + {\stopcollectitems + \ifconditional\c_strc_itemgroups_text + \removeunwantedspaces + \space + \ignorespaces + \else + \par + \fi + \strc_itemgroups_register_status + \ifconditional\c_strc_itemgroups_first \else + \dostoptagged + \dostoptagged + % \endgroup % (3) + \fi + \ifnum\c_strc_itemgroups_column_depth=\c_strc_itemgroups_nesting\relax + \strc_itemgroups_stop_columns + \global\c_strc_itemgroups_column_depth\zerocount % global ? + \strc_itemgroups_tag_stop_group + \strc_itemgroups_after_command + \dontrechecknextindentation + \orelse\ifnum\c_strc_itemgroups_nesting=\plusone + \strc_itemgroups_insert_breakallow + \strc_itemgroups_tag_stop_group + \strc_itemgroups_after_command + \useindentnextparameter\itemgroupparameter + \else + % nieuw, not yet nobreak handling + \strc_itemgroups_tag_stop_group + \ifcase\c_strc_itemgroups_spacing_mode + \strc_itemgroups_after_command + \or + \strc_itemgroups_after_command + \fi + \dontrechecknextindentation + \fi + % new test, needed in sidefloats (surfaced in volker's proceedings) + \iftrialtypesetting + \strc_counters_restore\v_strc_itemgroups_counter % could happen in LUA + \fi + \global\advance\c_strc_itemgroups_nesting\minusone + \xdef\currentitemlevel{\number\c_strc_itemgroups_nesting}% + %\ifconditional\c_strc_itemgroups_text + \endgroup % (2) + \endgroup % (1) + %\else + % \endgroup % (2) + % \endgroup % (1) + % \par % hm, already done, and dangerous as \c_strc_itemgroups_text is already forgotten + %\fi + \dorechecknextindentation} + +% The items. + +\unexpanded\def\startitemgroupitem + {\dosingleempty\strc_itemgroups_start_item} + +\def\strc_itemgroups_start_item_first + {\setfalse\c_strc_itemgroups_first + % \begingroup % (3) + \ifcase\c_strc_itemgroups_nesting + % 0 + \or + \strc_itemgroups_start_item_first_one % 1 + \else + \strc_itemgroups_start_item_first_two % 2+ + \fi} + +\def\strc_itemgroups_start_item_first_one + {\ifcase\c_strc_itemgroups_column_depth + \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi + \strc_itemgroups_before_command + \strc_itemgroups_tag_start_group + \ifconditional\c_strc_itemgroups_intro\strc_itemgroups_insert_breakno\fi + \fi} + +\def\strc_itemgroups_start_item_first_two + {\ifconditional\c_strc_itemgroups_paragraph\else + \edef\previtemlevel{\the\numexpr\c_strc_itemgroups_nesting-\plusone}% + \ifcase\c_strc_itemgroups_spacing_mode + \strc_itemgroups_before_command + \or + \doifelsenothing\strc_itemgroups_before_command % should possibly expand to empty + {\nameditemgroupparameter{\currentparentitemgroup:\previtemlevel}\c!inbetween}% + \strc_itemgroups_before_command + \else + \nameditemgroupparameter{\currentparentitemgroup:\previtemlevel}\c!inbetween + \fi + \strc_itemgroups_tag_start_group + \fi} + +\def\strc_itemgroups_start_item_next + {\dostoptagged % ok? what do we stop here? + \dostoptagged % ok? what do we stop here? + \ifconditional\c_strc_itemgroups_text + \ifhmode + % WS: make the distance between items customizable, think about better default values -> see itemize-1.tex + \strc_itemgroups_set_text_item_distance% HH: moved out and made configurable (sort of) + \removeunwantedspaces + \hskip\m_strc_itemgroups_text_distance\relax + \fi + \else + \strc_itemgroups_between_command + \fi} + +% c_strc_itemgroups_concat: +% +% the problem is that we use leftskip so concat cannot reliable take the height into +% account; it's .. rather tricky when white space in there anyway (due to \par) .. so +% we rely on a special blank method +% +% \startitemize[n] +% \item bla +% \item \startitemize[a] +% \item bla $\displaystyle\int^{x^{y^4}}$ \item bla +% \stopitemize +% \stopitemize + +\unexpanded\def\strc_itemgroups_start_item[#reference]% we can reuse more + {\def\currentitemreference{#reference}% + \ifconditional\c_strc_itemgroups_text + % begin of item + \else + \par + \fi + \ifconditional\c_strc_itemgroups_concat + \strc_itemgroups_insert_breakno + \fi + \strc_itemgroups_increment_item_counter + \ifconditional\c_strc_itemgroups_first + \strc_itemgroups_start_item_first + \else + \strc_itemgroups_start_item_next + \fi + \ifconditional\c_strc_itemgroups_concat + \spac_overlay_lines % see spac-ver.mkvi ... a typical potential problem + \setfalse\c_strc_itemgroups_concat + \fi + \dostarttagged\t!item\empty + % \dotagsetitem\empty + \dostarttagged\t!itemtag\empty + \strc_itemgroups_insert_item + \dostoptagged + \ifconditional\c_strc_itemgroups_pack + \setupwhitespace[\v!none]% + \fi + \itemgroupparameter\c!inner % will become obsolete (better use setups) + \strc_itemgroups_margin_symbol + \let\strc_itemgroups_margin_symbol\relax + \dostarttagged\t!itemcontent\empty + \begstrut % \strut + \nobreak % else problems with intext items + \seteffectivehsize % NEW ! + \hskip\d_strc_itemgroups_signal % concat + \itemgroupparameter\c!command} + +\unexpanded\def\stopitemgroupitem + {\ifhmode + \endstrut % new per 2017-12-15 + \fi + \ifconditional\c_strc_itemgroups_text + % nothing + \else + \endgraf + \fi} +\unexpanded\def\startitemgrouphead + {\dosingleempty\strc_itemgroups_start_head} + +\unexpanded\def\strc_itemgroups_start_head[#reference]% + {\ifconditional\c_strc_itemgroups_first \else + \strc_itemgroups_insert_breakallow + \fi + \ifconditional\c_strc_itemgroups_pack \else + \strc_itemgroups_before_head_command + \fi + \ifconditional\c_strc_itemgroups_first + \ifconditional\c_strc_itemgroups_intro \else + \ifcase\c_strc_itemgroups_nesting + \strc_itemgroups_insert_breakallow + \fi + \fi + \fi + \strc_itemgroups_start_item[#reference]% + \pickupgroupedcommand + \strc_itemgroups_start_head_indeed + \strc_itemgroups_stop_head_indeed + \strc_itemgroups_head_body_indeed} + +\unexpanded\def\stopitemgrouphead + {\dostoptagged + \stopitemgroupitem} + +\unexpanded\def\strc_itemgroups_start_head_indeed + {\settrue\c_strc_itemgroups_head + \dotagsetitem\s!head% % weird place + \dostarttagged\t!itemhead\empty + \useitemgroupstyleandcolor\c!headstyle\c!headcolor\ignorespaces} + +\unexpanded\def\strc_itemgroups_stop_head_indeed + {\removeunwantedspaces + \dostoptagged + \ifconditional\c_strc_itemgroups_text + \space + \ignorespaces + \else + \par + \fi + \strc_itemgroups_insert_breakno + \ifconditional\c_strc_itemgroups_pack\else\strc_itemgroups_after_head_command\fi + \strc_itemgroups_insert_breakno} + +\unexpanded\def\strc_itemgroups_head_body_indeed + {\dostarttagged\t!itembody\empty + \noindentation} + +% Simple commands. + +\unexpanded\def\strc_itemgroups_start_do_item + {\startitemgroupitem} + +\unexpanded\def\strc_itemgroups_start_no_item + {\let\currentitemreference\empty + \strc_itemgroups_increment_item_counter + %\advance\c_strc_itemgroups_n_of_items\plusone + \setbox\b_strc_itemgroups\emptyhbox + \strc_itemgroups_check_for_repeated + \ignorespaces} + +\unexpanded\def\strc_itemgroups_start_button[#destination]% + {\edef\m_strc_itemgroups_destination{#destination}% + \startitemgroupitem} + +\unexpanded\def\strc_itemgroups_start_symbol#text% + {\def\strc_itemgroups_extra_symbol{#text}% + \settrue\c_strc_itemgroups_symbol + \startitemgroupitem + \dotagsetitem\s!symbol} + +\unexpanded\def\strc_itemgroups_start_dummy + {\strc_itemgroups_start_symbol + %\strut\strut} % two ? + \begstrut} + +\unexpanded\def\strc_itemgroups_start_subitem + {\settrue\c_strc_itemgroups_sub + \startitemgroupitem + \dotagsetitem\s!sub} + +\unexpanded\def\strc_itemgroups_start_edge#text% + {\strc_itemgroups_start_symbol + {\strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting + \dostarttagged\t!ignore\empty % for the moment, maybe an attribute + \hbox to \d_strc_itemgroups_list_width + {#text\hskip\itemgroupparameter\c!distance}% + \dostoptagged}} + +\unexpanded\def\strc_itemgroups_start_margin#text% + {\def\strc_itemgroups_margin_symbol % brrr + {\dostarttagged\t!ignore\empty % for the moment, maybe an attribute + \llap + {\begingroup + \useitemgroupstyleandcolor\c!marstyle\c!marcolor + #text% keep em/ex local + \endgroup + \hskip\dimexpr\leftskip+\leftmargindistance\relax}% + \dostoptagged}% + \startitemgroupitem + \dotagsetitem\s!margin} + +\unexpanded\def\strc_itemgroups_start_text#text% + {\def\strc_itemgroups_extra_symbol{#text}% + \settrue\c_strc_itemgroups_symbol + \settrue\c_strc_itemgroups_txt + \startitemgroupitem} + +% \unexpanded\def\strc_itemgroups_start_head +% {\settrue\c_strc_itemgroups_head +% \startitemgrouphead} + +\unexpanded\def\strc_itemgroups_start_items + {\dosingleempty\strc_itemgroups_start_items_indeed} + +\unexpanded\def\strc_itemgroups_start_items_indeed[#whatever]% something got lost + {\strc_itemgroups_start_edge + {\dorecurse{0\itemgroupparameter\c!items}{\strc_itemgroups_used_symbol\hss}% + \unskip}} + +% \unexpanded\def\startspecialitemgroupitem[#name]% +% {\csname\??itemgroupstart\ifcsname\??itemgroupstart#name\endcsname#name\else\v!item\fi\endcsname} + +\unexpanded\def\startspecialitemgroupitem[#name]% + {\ifcsname\??itemgroupstart#name\endcsname + \expandafter\lastnamedcs + \else + \expandafter\strc_itemgroups_start_do_item + \fi} + +\unexpanded\def\stopspecialitemgroupitem + {\stopitemgroupitem} + +\letvalue{\??itemgroupstart\v!item}\strc_itemgroups_start_do_item +\letvalue{\??itemgroupstart\v!sub }\strc_itemgroups_start_subitem +\letvalue{\??itemgroupstart\v!sym }\strc_itemgroups_start_symbol +\letvalue{\??itemgroupstart\v!ran }\strc_itemgroups_start_edge +\letvalue{\??itemgroupstart\v!its }\strc_itemgroups_start_items +\letvalue{\??itemgroupstart\v!mar }\strc_itemgroups_start_margin + +\def\optimizelistitemsbreak + {\ifcase\c_strc_itemgroups_column_depth + \ifconditional\c_strc_itemgroups_optimize + \ifcase\c_strc_itemgroups_max_items + \orelse\ifnum\c_strc_itemgroups_max_items=\plusthree + \ifnum\c_strc_itemgroups_n_of_items>\plusone + \strc_itemgroups_insert_nobreak + \fi + \orelse\ifnum\c_strc_itemgroups_max_items>\plusthree + \ifnum\c_strc_itemgroups_n_of_items=\plustwo + \ifconditional\c_strc_itemgroups_intro + \strc_itemgroups_insert_breakno + \else + \strc_itemgroups_insert_nobreak + \fi + \orelse\ifnum\c_strc_itemgroups_max_items=\c_strc_itemgroups_n_of_items\relax + \strc_itemgroups_insert_nobreak + \orelse\ifnum\c_strc_itemgroups_n_of_items>\plustwo + \strc_itemgroups_insert_break + \else + \ifconditional\c_strc_itemgroups_intro\else\strc_itemgroups_insert_break\fi + \fi + \fi + \fi + \fi} + +\def\strc_itemgroups_handle_text_item + {\scratchdimen\wd\b_strc_itemgroups + \advance \scratchdimen \itemgroupparameter\c!distance\relax + \ifdim\scratchdimen>\d_strc_itemgroups_list_width + \advance\scratchdimen -\d_strc_itemgroups_list_width + \else + \scratchdimen\zeropoint + \fi + \llap{\hbox to \d_strc_itemgroups_list_width{\ifconditional\c_strc_itemgroups_sub\llap{+\enspace}\fi\box\b_strc_itemgroups\hss}}% was: \hfill + \hskip\scratchdimen} + +\def\strc_itemgroups_handle_lapped_item_positive + {\llap + {\dontcomplain + \hbox to \d_strc_itemgroups_list_width + {\ifconditional\c_strc_itemgroups_sub + \dostarttagged\t!ignore\empty + \llap{+\enspace}% + \dostoptagged + \fi + \strc_itemgroups_left_sym_filler + \box\b_strc_itemgroups % can already have a forced widt, only factor handled here + \hfil + \hskip\itemgroupparameter\c!distance}}} + +\def\strc_itemgroups_handle_lapped_item_negative + {\llap + {\ifconditional\c_strc_itemgroups_sub + \dostarttagged\t!ignore\empty + \llap{+\enspace}% + \dostoptagged + \fi + \box\b_strc_itemgroups + \hskip\leftmargindistance}} + +\def\strc_itemgroups_handle_groups_text_item + {\hbox + {\ifconditional\c_strc_itemgroups_sub + \dostarttagged\t!ignore\empty + +\enspace + \dostoptagged + \fi + \box\b_strc_itemgroups + \hskip\interwordspace}% + \nobreak} + +\def\strc_itemgroups_handle_groups_inline_item + {\hbox to \d_strc_itemgroups_list_width + {\ifconditional\c_strc_itemgroups_sub + \dostarttagged\t!ignore\empty + \llap{+\enspace}% + \dostoptagged + \fi + \box\b_strc_itemgroups + \hss}} % was: \hfill + +\unexpanded\def\strc_itemgroups_start_head_sym#text% + {\def\strc_itemgroups_extra_symbol{#text}% + \settrue\c_strc_itemgroups_symbol + \settrue\c_strc_itemgroups_head + \strc_itemgroups_start_head} + +\def\strc_itemgroups_make_symbol_box + {\setbox\b_strc_itemgroups\autodirhbox + {\ifconditional\c_strc_itemgroups_head + \ifconditional\c_strc_itemgroups_symbol + \strc_itemgroups_insert_extra_reference + \useitemgroupstyleandcolor\c!symstyle\c!symcolor + \strc_itemgroups_extra_symbol + \else + \useitemgroupstyleandcolor\c!headstyle\c!headcolor + \strc_itemgroups_used_symbol + \fi + \else + \ifconditional\c_strc_itemgroups_symbol + \strc_itemgroups_insert_extra_reference + \useitemgroupstyleandcolor\c!symstyle\c!symcolor + \strc_itemgroups_extra_symbol + \else + \useitemgroupstyleandcolor\c!style\c!color + \strc_itemgroups_used_symbol + \fi + \fi}% + \let\strc_itemgroups_extra_symbol\empty + \setfalse\c_strc_itemgroups_symbol} + +\def\strc_itemgroups_make_fitting_box + {\ifdim\wd\b_strc_itemgroups>\itemgroupparameter\c!maxwidth\relax + \normalexpanded{\global\setitemgroupparameter{\c!maxwidth}{\the\wd\b_strc_itemgroups}}% + \fi + \ifdim\d_strc_itemgroups_max_width>\zeropoint + \setbox\b_strc_itemgroups\simplealignedbox + {\dimexpr\d_strc_itemgroups_max_width+\itemgroupparameter\c!distance\relax} + {\itemgroupparameter\c!itemalign} + {\box\b_strc_itemgroups\hskip\itemgroupparameter\c!distance}% + \fi} + +\def\strc_itemgroups_make_aligned_box + {\doifsomething{\itemgroupparameter\c!itemalign} + {\setbox\b_strc_itemgroups\simplealignedbox + {\dimexpr\d_strc_itemgroups_asked_width+\itemgroupparameter\c!distance\relax} + {\itemgroupparameter\c!itemalign} + {\box\b_strc_itemgroups\hskip\itemgroupparameter\c!distance}}} + +\def\strc_itemgroups_make_destination_box + {\iftrialtypesetting \else \ifx\m_strc_itemgroups_destination\empty \else + \setbox\b_strc_itemgroups\hbox{\directgotobox{\box\b_strc_itemgroups}[\m_strc_itemgroups_destination]}% + \fi\fi} + +\def\strc_itemgroups_check_indenting + {\setfalse\c_strc_itemgroups_indented_first + \ifx\m_strc_itemgroups_indenting\empty \else + \normalexpanded{\setupindenting[\v!reset,\v!yes,\m_strc_itemgroups_indenting]}% + \ifconditional\c_spac_indentation_indent_first % better is to have a mode + \doifnot{\itemgroupparameter\c!alignsymbol}\v!yes + {\settrue\c_strc_itemgroups_indented_first}% + \fi + \fi} + +\def\strc_itemgroups_check_for_repeated + {\ifconditional\c_strc_itemgroups_repeat + \ifx\m_strc_itemgroups_repeat_start\empty + \edef\m_strc_itemgroups_repeat_start{\currentitemlevel}% + \fi + \else + \let\m_strc_itemgroups_repeat_start\empty + \fi} + +\def\strc_itemgroups_insert_item + {\ifconditional\c_strc_itemgroups_text % again? + % begin of item + \else + \par % done twice? + \fi + \advance\c_strc_itemgroups_n_of_items\plusone + \optimizelistitemsbreak + \strc_itemgroups_check_indenting + \dontleavehmode + \ifconditional\c_strc_itemgroups_indented_first + \hskip-\parindent + \fi + \strc_itemgroups_make_symbol_box + \strc_itemgroups_make_destination_box + \ifconditional\c_strc_itemgroups_fitting + \strc_itemgroups_make_fitting_box + \else\ifdim\d_strc_itemgroups_asked_width>\zeropoint + \strc_itemgroups_make_aligned_box + \fi\fi + \let\m_strc_itemgroups_destination\empty + \ht\b_strc_itemgroups\strutheight % just in case a symbols is not yet available in + \dp\b_strc_itemgroups\strutdepth % the current run (more a mkii mp side artifact) + \strc_itemgroups_check_for_repeated + \ifdim\d_strc_itemgroups_asked_width<\zeropoint\relax + \strc_itemgroups_handle_lapped_item_negative + \else + \ifdim\d_strc_itemgroups_asked_width=\zeropoint\relax + \strc_itemgroups_calculate_list_width\plusone + \else + \strc_itemgroups_calculate_list_width\c_strc_itemgroups_nesting + \fi + \ifconditional\c_strc_itemgroups_text + \strc_itemgroups_handle_groups_text_item + \orelse\ifconditional\c_strc_itemgroups_inline + \strc_itemgroups_handle_groups_inline_item + \orelse\ifconditional\c_strc_itemgroups_txt + \strc_itemgroups_handle_text_item + \else + \strc_itemgroups_handle_lapped_item_positive + \fi + \fi + \setfalse\c_strc_itemgroups_head + \setfalse\c_strc_itemgroups_sub + \ifconditional\c_strc_itemgroups_indented_first + \hskip\parindent + \fi + \ignorespaces} + +\def\strc_itemgroups_start_item_nop + {\let\currentitemreference\empty + \strc_itemgroups_increment_item_counter + \advance\c_strc_itemgroups_n_of_items\plusone + \setbox\b_strc_itemgroups\hbox + {\useitemgroupstyleandcolor\c!style\c!color + \strc_itemgroups_used_symbol}% + \strc_itemgroups_check_for_repeated + \ignorespaces} + +\setvalue{\??itemgroupdistance\v!none}% + {\let\m_strc_itemgroups_text_distance\zeropoint} + +\setvalue{\??itemgroupdistance\v!space}% + {\def\m_strc_itemgroups_text_distance{\interwordspace\!!plus\interwordstretch\!!minus\interwordshrink}} + +\setvalue\??itemgroupdistance % catches empty value + {\let\m_strc_itemgroups_text_distance\zeropoint} + +\unexpanded\def\strc_itemgroups_set_text_item_distance + {\edef\m_strc_itemgroups_text_distance{\itemgroupparameter\c!textdistance}% + \ifx\m_strc_itemgroups_text_distance\empty + % + \orelse\ifcsname\??itemgroupdistance\m_strc_itemgroups_text_distance\endcsname + \lastnamedcs + \else + \strc_itemgroups_set_text_item_distance_indeed + \fi} + +\def\strc_itemgroups_set_text_item_distance_indeed + {\assignvalue + \m_strc_itemgroups_text_distance + \m_strc_itemgroups_text_distance + {.5\interwordspace\!!plus.5\emwidth}% + {\interwordspace \!!plus \emwidth}% + {\emwidth \!!plus \interwordstretch\!!minus\interwordshrink}} + +% \unexpanded\def\strc_itemgroups_default_command +% {\EveryPar{\ignorespaces}% needed ? +% \ignorespaces} + +\unexpanded\def\strc_itemgroups_default_command + {\ignorespaces} + +%D Special case: + +\unexpanded\def\strc_itemgroups_head#text\par + {\startitemgrouphead{#text}} + +%D The local commands: + +\appendtoks + \let\item \strc_itemgroups_start_do_item + \let\noitem \strc_itemgroups_start_no_item + \let\itm \strc_itemgroups_start_do_item + \let\but \strc_itemgroups_start_button + \let\nop \strc_itemgroups_start_dummy + \let\txt \strc_itemgroups_start_text + \let\head \strc_itemgroups_head + \let\headsym \strc_itemgroups_start_head_sym + \let\startitem \startitemgroupitem + \let\stopitem \stopitemgroupitem + \let\starthead \startitemgrouphead + \let\stophead \stopitemgroupitemhead + \let\startspecialitem\startspecialitemgroupitem + \let\stopspecialitem \stopspecialitemgroupitem +\to \itemgroupcommands + +\ifx\currentinterface \v!english \else + + \appendtoks + \expandafter\let\csname\v!item \endcsname\strc_itemgroups_start_do_item + \expandafter\let\csname\v!sub \endcsname\strc_itemgroups_start_subitem + \expandafter\let\csname\v!sym \endcsname\strc_itemgroups_start_symbol + \expandafter\let\csname\v!ran \endcsname\strc_itemgroups_start_edge + \expandafter\let\csname\v!head \endcsname\strc_itemgroups_head + \expandafter\let\csname\v!its \endcsname\strc_itemgroups_start_items + \expandafter\let\csname\v!mar \endcsname\strc_itemgroups_start_margin + \expandafter\let\csname\v!txt \endcsname\strc_itemgroups_start_text + \expandafter\let\csname\e!start\v!item\endcsname\startitemgroupitem + \expandafter\let\csname\e!stop \v!item\endcsname\stopitemgroupitem + \expandafter\let\csname\e!start\v!head\endcsname\startitemgrouphead + \expandafter\let\csname\e!stop \v!head\endcsname\stopitemgrouphead + \to \itemgroupcommands + +\fi + +\relaxvalueifundefined \v!item +\relaxvalueifundefined \v!sub +\relaxvalueifundefined \v!sym +\relaxvalueifundefined \v!ran +\relaxvalueifundefined \v!head +\relaxvalueifundefined \v!its +\relaxvalueifundefined \v!mar +\relaxvalueifundefined \v!txt +\relaxvalueifundefined {\e!start\v!item} +\relaxvalueifundefined {\e!stop \v!item} +\relaxvalueifundefined {\e!start\v!head} +\relaxvalueifundefined {\e!stop \v!head} + +%D A nice example of a plugin: +%D +%D \startbuffer +%D \startitemize[a,random,packed] +%D \startitem first \stopitem \startitem second \stopitem +%D \startitem third \stopitem \startitem fourth \stopitem +%D \stopitemize +%D +%D \startitemize[a,random,packed] +%D \startitem first \stopitem \startitem second \stopitem +%D \startitem third \stopitem \startitem fourth \stopitem +%D \stopitemize +%D +%D \startitemize[a,packed] +%D \startitem first \stopitem \startitem second \stopitem +%D \startitem third \stopitem \startitem fourth \stopitem +%D \stopitemize +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +% better collectitems als conditional and a real plugin mechanism (some day) + +\newcount\c_strc_itemgroups_collected_stored +\newcount\c_strc_itemgroups_collected_done +\newcount\c_strc_itemgroups_collected_current + +% \expandafter\def\expandafter\strc_itemgroups_collected_store\expandafter#\expandafter1\csname\e!stop\v!item\endcsname % use grabuntil +% {\advance\c_strc_itemgroups_collected_stored\plusone +% \setvalue{\??itemgroupstack\number\c_strc_itemgroups_collected_stored}{\startitemgroupitem#1\stopitemgroupitem}} + +\let\strc_itemgroups_collected_store\relax + +\normalexpanded{\def\strc_itemgroups_collected_store#1\csname\e!stop\v!item\endcsname}% + {\advance\c_strc_itemgroups_collected_stored\plusone + \setvalue{\??itemgroupstack\number\c_strc_itemgroups_collected_stored}{\startitemgroupitem#1\stopitemgroupitem}} + +\def\strc_itemgroups_collected_flush_randomize + {\collecteditemgroupitem} + +\def\strc_itemgroups_collected_flush_horizontal + {\begingroup + \scratchcounter\itemgroupparameter\c!n\relax + \ifnum\c_strc_itemgroups_collected_done>\plusone + \ifcase\modulonumber\scratchcounter\c_strc_itemgroups_collected_done\relax + % compensate for rounding errors + \hfill % \hskip\zeropoint plus \scaledpoint minus \scaledpoint + \allowbreak + \fi + \fi + \noindent % no \dontleavehmode + \hbox to \dimexpr\availablehsize/\scratchcounter\relax{\collecteditemgroupitem\hss}% + \endgroup} + +% \def\strc_itemgroups_collected_flush_indeed +% {\collecteditemgroupitem +% \iftrialtypesetting +% \undefinevalue{\??itemgroupstack\number\c_strc_itemgroups_collected_current}% +% \fi} + +\def\strc_itemgroups_collected_flush_indeed + {\collecteditemgroupitem + \undefinevalue{\??itemgroupstack\number\c_strc_itemgroups_collected_current}} + +\def\strc_itemgroups_collected_flush + {\ifconditional\c_strc_itemgroups_randomize + \getrandomcount\c_strc_itemgroups_collected_current\plusone\c_strc_itemgroups_collected_stored + \else + \advance\c_strc_itemgroups_collected_current\plusone + \fi + \ifcsname\??itemgroupstack\number\c_strc_itemgroups_collected_current\endcsname + \edef\collecteditemgroupitem{\lastnamedcs}% + \ifconditional\c_strc_itemgroups_horizontal + \strc_itemgroups_collected_flush_horizontal + \else + \strc_itemgroups_collected_flush_indeed + \fi + \advance\c_strc_itemgroups_collected_done\plusone + \fi + \ifnum\c_strc_itemgroups_collected_done<\c_strc_itemgroups_collected_stored + \expandafter\strc_itemgroups_collected_flush + \fi} + +\unexpanded\def\stopcollectitems + {\ifconditional\c_strc_itemgroups_collecting + \c_strc_itemgroups_collected_done \zerocount + \c_strc_itemgroups_collected_current\zerocount + \ifnum\c_strc_itemgroups_collected_stored>\zerocount + \ifconditional\c_strc_itemgroups_horizontal + \strc_itemgroups_before_command + \setfalse\c_strc_itemgroups_first + \strc_itemgroups_collected_flush + %\strc_itemgroups_after_command % triggered elsewhere + \else + \strc_itemgroups_collected_flush + \fi + \fi + \fi} + +\unexpanded\def\startcollectitems + {\ifconditional\c_strc_itemgroups_collecting + \c_strc_itemgroups_collected_stored\zerocount + \letvalue{\e!start\v!item}\strc_itemgroups_collected_store + \fi} + +%D Left-overs: + +\unexpanded\def\item + {\strc_itemgroups_item_alone} + +\def\strc_itemgroups_item_alone[#category]#text\par + {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}% + \startitem#text\stopitem + \stopitemgroup} + +\unexpanded\def\head + {\strc_itemgroups_head_alone} + +\def\strc_itemgroups_head_alone[#category]#head\par#body\par + {\doifelsesomething{#category}{\startitemgroup[#category]}{\startitemgroup[\v!itemize]}% + \starthead{#head}#body\stophead + \stopitemgroup} + +\setuvalue{\e!start\v!item}% + {\startitemgroup[\v!itemize]% + \startitemgroupitem + \setuvalue{\e!stop\v!item}{\stopitemgroupitem\stopitemgroup}} + +% \def\sym#text% +% {\noindent +% \begingroup +% \setbox\scratchbox\hbox{\settrialtypesetting#text}% +% \setbox\scratchbox\hbox\ifdim\wd\scratchbox<1em to 1.5\else spread 1\fi em{#text\hfil}% +% \normalexpanded{\box\scratchbox\endgroup\hangindent\the\wd\scratchbox}% +% \ignorespaces} + +%D End of plugin. + +%D Something for tables: + +\unexpanded\def\itemtag + {\dosingleempty\strc_itemgroups_item_tag} + +\unexpanded\def\strc_itemgroups_item_tag[#reference]% we can reuse more + {\def\currentitemreference{#reference}% + \iftrialtypesetting + \strc_counters_save\v_strc_itemgroups_counter + \strc_itemgroups_increment_item_counter + \strc_itemgroups_insert_item_tag_indeed + \strc_counters_restore\v_strc_itemgroups_counter + \else + \strc_itemgroups_increment_item_counter + \strc_itemgroups_insert_item_tag_indeed + \fi} + +\def\strc_itemgroups_insert_item_tag_indeed + {\letitemgroupparameter\c!distance\zeropoint + %letitemgroupparameter\c!width\zeropoint + \strc_itemgroups_make_symbol_box + \strc_itemgroups_make_destination_box + \let\m_strc_itemgroups_destination\empty + \ht\b_strc_itemgroups\strutheight + \dp\b_strc_itemgroups\strutdepth + \box\b_strc_itemgroups + \ignorespaces} + +%D Done again. + +\setupitemgroup + [\c!margin=\zeropoint, + \c!leftmargin=\zeropoint, + \c!rightmargin=\zeropoint, + \c!leftmargindistance=\zeropoint, + \c!rightmargindistance=\zeropoint, + \c!indentnext=\v!yes, + \c!width=1.5\emwidth, + \c!factor=0, + %\c!distance=.5em, % is now: + \c!step=.5\emwidth, % deals with broad + \c!distance=\zeropoint, + %\c!align=\v!normal, % definitely not \v!normal ! + %\c!symalign=, + %\c!color=, + %\c!indenting=, % untouched if empty + %\c!style=, + \c!marstyle=\v!type, + %\c!symstyle=, + %\c!headstyle=, + %\c!marcolor=, + %\c!symcolor=, + %\c!headcolor=, + %\c!beforehead=, + \c!symcolor=\itemgroupparameter\c!color, % new per 2012.01.17 + \c!symstyle=\itemgroupparameter\c!style, % new per 2012.01.17 + \c!afterhead=\blank, + \c!before=\blank, + \c!inbetween=\blank, + \c!after=\blank, + %\c!stopper=., + \c!placestopper=\v!yes, + \c!stopper=., + %\c!inner=, + \c!n=2, + \c!items=4, + \c!levels=10, + \c!lefttext=(, + \c!righttext=), + \c!start=1, + \c!criterium=\v!all, % permits 0 and negative numbers + %\c!option=, + \c!textdistance=\v!space, % none big medium small + \c!command=\strc_itemgroups_default_command, + \c!indenting=\v!next, + %\c!alignsymbol=v!no, + \c!symbol=\currentitemlevel, + \c!prefix=\v!no, + %\c!prefixstopper=., + %\c!prefixseparatorset=, + %\c!prefixconversion=, + %\c!prefixconversionset=, + %\c!prefixset=, + %\c!prefixsegments=1:100, + \c!prefixconnector=., + \c!numberseparatorset=, + \c!numberconversionset=, + \c!numberstopper=., + \c!numbersegments=1] + +\defineitemgroup + [\v!itemize] + +\protect \endinput diff --git a/tex/context/base/mkiv/strc-itm.mkvi b/tex/context/base/mkiv/strc-itm.mkvi index eea42f2de..892e33104 100644 --- a/tex/context/base/mkiv/strc-itm.mkvi +++ b/tex/context/base/mkiv/strc-itm.mkvi @@ -15,14 +15,14 @@ \registerctxluafile{strc-itm}{} -%D As we analyze/register widths and such we could as well push and pop the -%D numbers at the \LUA\ end (which saves a few calls). - -%D Cleaning up this module happened around the time when Kate Bush came up -%D with the nicest numbered list of words: 50 Words For Snow. It's therefore -%D no surprise that I had that cd running several times when updating this -%D code. One of the highlights of 2011. - +%D As we analyze/register widths and such we could as well push and pop the numbers +%D at the \LUA\ end (which saves a few calls). +%D +%D Cleaning up this module happened around the time when Kate Bush came up with the +%D nicest numbered list of words: 50 Words For Snow. It's therefore no surprise that +%D I had that cd running several times when updating this code. One of the +%D highlights of 2011. +%D %D This module needs to be rewritten but that is tricky with respect to %D compatibilitity. Basically each major variant (regular, text, columns, %D horizontal, etc) needs to be on its own. diff --git a/tex/context/base/mkiv/supp-box.mkiv b/tex/context/base/mkiv/supp-box.mkiv index 59e710520..2fce3311a 100644 --- a/tex/context/base/mkiv/supp-box.mkiv +++ b/tex/context/base/mkiv/supp-box.mkiv @@ -57,8 +57,8 @@ %D \macros %D {dontcomplain} %D -%D The next macro suppresses over- and underfull messages which -%D often makes sense when we deal with boxes. +%D The next macro suppresses over- and underfull messages which often makes sense +%D when we deal with boxes. \unexpanded\def\dontcomplain {\hbadness\plustenthousand @@ -66,18 +66,15 @@ \hfuzz \maxdimen \vfuzz \maxdimen} -%D This module implements some box manipulation macros. Some -%D are quite simple, some are more advanced and when understood -%D well, all can be of use. +%D This module implements some box manipulation macros. Some are quite simple, some +%D are more advanced and when understood well, all can be of use. %D %D \macros %D {strutdp,strutht,strutwd} %D -%D The next shortcuts save memory and keying. The width is -%D normally zero points (if not, you're in trouble). These -%D shortcuts can be used like a dimension, opposite to the -%D core macros \type {\strutdepth} and alike, which are -%D values. +%D The next shortcuts save memory and keying. The width is normally zero points (if +%D not, you're in trouble). These shortcuts can be used like a dimension, opposite +%D to the core macros \type {\strutdepth} and alike, which are values. \def\strutdp {\dp\strutbox} \def\strutht {\ht\strutbox} @@ -88,8 +85,8 @@ %D \macros %D {voidbox,nextbox} %D -%D Let's start with an easy one. The next macro hides the -%D ugly \type {@} in \type {\voidb@x}. +%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type +%D {\voidb@x}. \ifdefined\voidbox \else \newbox\voidbox \fi \ifdefined\nextbox \else \newbox\nextbox \fi @@ -97,19 +94,17 @@ %D \macros %D {nextdepth} %D -%D Let's start with a rather simple declaration. Sometimes we -%D need to save the \TEX\ \DIMENSION\ \type{\prevdepth} and -%D append it later on. The name \type{\nextdepth} suits -%D this purpose well. +%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\ +%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth} +%D suits this purpose well. \newdimen\nextdepth %D \macros %D {smashbox, smashedbox} %D -%D Smashing is introduced in \PLAIN\ \TEX, and stands for -%D reducing the dimensions of a box to zero. The most resolute -%D one is presented first. +%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of +%D a box to zero. The most resolute one is presented first. \unexpanded\def\smashbox#1% {\wd#1\zeropoint @@ -125,8 +120,8 @@ %D \macros %D {hsmashbox,vsmashbox} %D -%D Smashing can be used for overlaying boxes. Depending on -%D the mode, horizontal or vertical, one can use: +%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or +%D vertical, one can use: \unexpanded\def\hsmashbox#1% {\wd#1\zeropoint} @@ -135,8 +130,7 @@ {\ht#1\zeropoint \dp#1\zeropoint} -%D The next implementation is less sensitive for spurious -%D spaces. +%D The next implementation is less sensitive for spurious spaces. \newcount\c_boxes_register @@ -174,10 +168,9 @@ %D {hsmash,vsmash, %D hsmashed,vsmashed} %D -%D While the previous macros expected a \BOX, the next act on a -%D content. They are some subtle differences betreen the smash -%D and smashed alternatives. The later ones reduce all -%D dimensions to zero. +%D While the previous macros expected a \BOX, the next act on a content. They are +%D some subtle differences betreen the smash and smashed alternatives. The later +%D ones reduce all dimensions to zero. \unexpanded\def\hsmash {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox} \unexpanded\def\vsmash {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox} @@ -227,10 +220,9 @@ %D \macros %D {smash} %D -%D This smash alternative takes an optional arg [whdtb] as -%D well as is potentially catcode safer. It is needed by the -%D math module (although the \type {\leavevmode} is not added -%D here). +%D This smash alternative takes an optional arg [whdtb] as well as is potentially +%D catcode safer. It is needed by the math module (although the \type {\leavevmode} +%D is not added here). \unexpanded\def\smash {\begingroup @@ -304,12 +296,12 @@ %D \macros %D {phantom, hphantom, vphantom, mathstrut} %D -%D The next implementation of \type {\phantom} cum suis does -%D not grab an argument in the non||math case, which is better. +%D The next implementation of \type {\phantom} cum suis does not grab an argument in +%D the non||math case, which is better. %D -%D Due to a complicated call to \type {\mathpallete} and -%D thereby \type {\mathchoice}, the next macro looks ugly. -%D We also take care of non||braced arguments. +%D Due to a complicated call to \type {\mathpallete} and thereby \type +%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced +%D arguments. \unexpanded\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed } \unexpanded\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v} @@ -382,8 +374,7 @@ %D \macros %D {getboxheight} %D -%D Although often needed, \TEX\ does not support arithmics -%D like: +%D Although often needed, \TEX\ does not support arithmics like: %D %D \starttyping %D \dimen0 = \ht0 + \dp0 @@ -409,33 +400,29 @@ %D {#1\ht#3\advance#1\dp#3\relax} %D \stoptyping %D -%D The next alternative is slightly more clever, since -%D it accepts \type {{12}} as well as \type {12} as box -%D number. +%D The next alternative is slightly more clever, since it accepts \type {{12}} as +%D well as \type {12} as box number. \unexpanded\def\getboxheight#1\of#2\box#3% {\def\next{#1\dimexpr\ht\c_boxes_register+\dp\c_boxes_register\relax}% \afterassignment\next\c_boxes_register=#3} -%D For a long time the following three macros were part of -%D the grid snapping core module, but it makes more sense to -%D have them here so that users can see them. +%D For a long time the following three macros were part of the grid snapping core +%D module, but it makes more sense to have them here so that users can see them. %D %D \macros %D {getnoflines, getroundednoflines, getrawnoflines} %D -%D Het commando \type{\getnoflines} converteert een hoogte -%D (dimensie) in een aantal regels en kent dit toe aan -%D \type{\noflines}. +%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal +%D regels en kent dit toe aan \type {\noflines}. %D %D \starttyping %D \getnoflines{dimensie} %D \stoptyping %D -%D Er wordt gedeeld door \type{\openlineheight} en een hoogte -%D van~0pt komt overeen met 0~regels. The raw alternative -%D does not round. - +%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen +%D met 0~regels. The raw alternative does not round. +%D %D For a long time we had: %D %D \starttyping @@ -538,9 +525,9 @@ %D \macros %D {determinenoflines} %D -%D The next macro determines the number of lines and -%D returns it it \type {\noflines}. The macro works -%D reasonable well as long as the content can be unboxed. +%D The next macro determines the number of lines and returns it it \type +%D {\noflines}. The macro works reasonable well as long as the content can be +%D unboxed. %D %D \starttyping %D \determinenoflines{test\\test} @@ -569,9 +556,8 @@ %D \macros %D {doiftextelse, doiftext} %D -%D When \type {\doifelse} cum suis hopelessly fail, for -%D instance because we pass data, we can fall back on the next -%D macro: +%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass +%D data, we can fall back on the next macro: %D %D \starttyping %D \doiftextelse {data} {then branch} {else branch} @@ -605,23 +591,19 @@ %D \macros %D {dowithnextbox,nextbox} %D -%D Sometimes we want a macro to grab a box and do something -%D on the content. One could pass an argument to a box, but -%D this can violate the specific \CATCODES\ of its content and -%D leads to unexpected results. The next macro treats the -%D following braced text as the content of a box and -%D manipulates it afterwards in a predefined way. +%D Sometimes we want a macro to grab a box and do something on the content. One +%D could pass an argument to a box, but this can violate the specific \CATCODES\ of +%D its content and leads to unexpected results. The next macro treats the following +%D braced text as the content of a box and manipulates it afterwards in a predefined +%D way. %D -%D The first argument specifies what to do with the content. -%D This content is available in \type{\nextbox}. The second -%D argument is one of \type{\hbox}, \type{\vbox} or -%D \type{\vtop}. The third argument must be grouped with -%D \type{\bgroup} and \type{\egroup}, \type{{...}} or can be -%D a \type{\box} specification. +%D The first argument specifies what to do with the content. This content is +%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type +%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup} +%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification. %D -%D In \CONTEXT\ this macro is used for picking up a box and -%D treating it according to earlier specifications. We use for -%D instance something like: +%D In \CONTEXT\ this macro is used for picking up a box and treating it according to +%D earlier specifications. We use for instance something like: %D %D \starttyping %D \def\getfloat% @@ -636,9 +618,8 @@ %D {...#1...} %D \stoptyping %D -%D In this implementation the \type{\aftergroup} construction -%D is needed because \type{\afterassignment} is executed inside -%D the box. +%D In this implementation the \type {\aftergroup} construction is needed because +%D \type {\afterassignment} is executed inside the box. \unexpanded\def\dowithnextbox#1% {\def\syst_boxes_with_next_box{#1}% @@ -684,14 +665,14 @@ %D \setbox\nextbox#2} %D \stoptyping %D -%D This alternative also accepts \type{\box0} and alike, but -%D we don't really need this functionality now. +%D This alternative also accepts \type {\box0} and alike, but we don't really need +%D this functionality now. %D \macros %D {nextboxht,nextboxwd,nextboxdp,flushnextbox} %D -%D The next couple of shortcuts saves us memory as well as -%D \type {{}}'s in passing parameters. +%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing +%D parameters. \def\nextboxht {\ht\nextbox} \def\nextboxwd {\wd\nextbox} @@ -703,9 +684,8 @@ %D \macros %D {dowithnextboxcontent} %D -%D But, occasionally we do need to pass some local settings -%D without wanting to use additional grouping. Therefore we -%D provide: +%D But, occasionally we do need to pass some local settings without wanting to use +%D additional grouping. Therefore we provide: %D %D \starttyping %D \dowithnextboxcontent{inside}{after}{box content} @@ -731,8 +711,8 @@ %D \macros %D {llap, rlap, tlap, blap, clap} %D -%D Some well known friends, but we implement them our own -%D way. We want the macros to work in both math and text mode. +%D Some well known friends, but we implement them our own way. We want the macros to +%D work in both math and text mode. \def\dodorlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup} \def\dodollap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup} @@ -764,16 +744,14 @@ %D shapebox, %D ifreshapingbox} %D -%D The next utility macro originates from some linenumbering -%D mechanism. Due to \TEX's advanced way of typesetting -%D paragraphs, it's not easy to do things on a line||by||line -%D basis. This macro is able to reprocess a given box and can -%D act upon its vertical boxed components, such as lines. The -%D unwinding sequence in this macro is inspired by a \NTG\ -%D workshop of David Salomon in June 1992. +%D The next utility macro originates from some linenumbering mechanism. Due to +%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a +%D line||by||line basis. This macro is able to reprocess a given box and can act +%D upon its vertical boxed components, such as lines. The unwinding sequence in this +%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992. %D -%D First we have to grab the piece of text we want to act -%D upon. This is done by means of the duo macros: +%D First we have to grab the piece of text we want to act upon. This is done by +%D means of the duo macros: %D %D \starttyping %D \beginofshapebox @@ -781,16 +759,14 @@ %D \endofshapebox %D \stoptyping %D -%D When all texts is collected, we can call \type{\reshapebox} -%D and do something with it's vertical components. We can make -%D as much passes as needed. When we're done, the box can be -%D unloaded with \type{\flushshapebox}. The only condition in -%D this scheme is that \type{\reshapebox} must somehow unload -%D the \BOX\ \type{\shapebox}. +%D When all texts is collected, we can call \type {\reshapebox} and do something +%D with it's vertical components. We can make as much passes as needed. When we're +%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in +%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type +%D {\shapebox}. %D -%D An important aspect is that the content is unrolled -%D bottom||up. The next example illustrates this maybe -%D unexpected characteristic. +%D An important aspect is that the content is unrolled bottom||up. The next example +%D illustrates this maybe unexpected characteristic. %D %D \startbuffer %D \beginofshapebox @@ -810,8 +786,7 @@ %D %D \getbuffer %D -%D As we can see, when some kind of numbering is done, we have -%D to add a second pass. +%D As we can see, when some kind of numbering is done, we have to add a second pass. %D %D \startbuffer %D \newcounter\LineNumber @@ -835,9 +810,9 @@ %D %D \getbuffer %D -%D This example shows that the content of the box is still -%D available after flushing. Another feature is that only the -%D last reshaping counts. Multiple reshaping can be done by: +%D This example shows that the content of the box is still available after flushing. +%D Another feature is that only the last reshaping counts. Multiple reshaping can be +%D done by: %D %D \startbuffer %D \beginofshapebox @@ -856,26 +831,23 @@ %D %D \getbuffer %D -%D The macros are surprisingly easy to follow and in fact -%D introduce no new concepts. Nearly all books on \TEX\ show -%D similar solutions for unwinding \BOXES. +%D The macros are surprisingly easy to follow and in fact introduce no new concepts. +%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES. %D -%D Some macros, like footnote ones, can be sensitive for -%D reshaping, which can result in an endless loop. We -%D therefore offer: +%D Some macros, like footnote ones, can be sensitive for reshaping, which can result +%D in an endless loop. We therefore offer: %D %D \starttyping %D \ifreshapingbox %D \stoptyping %D -%D Some \CONTEXT\ commands are protected this way. Anyhow, -%D reshaping is aborted after 100 dead cycles. +%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted +%D after 100 dead cycles. %D -%D By the way, changing the height and depth of \BOX\ -%D \type{\shapebox} results in bad spacing. This means that -%D for instance linenumbers etc. should be given zero height -%D and depth before being lapped into the margin. The -%D previous examples ignore this side effect, but beware! +%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in +%D bad spacing. This means that for instance linenumbers etc. should be given zero +%D height and depth before being lapped into the margin. The previous examples +%D ignore this side effect, but beware! \newif \ifsomeshapeleft \newif \ifreshapingbox @@ -1034,9 +1006,8 @@ % \kern-\dp\newshapebox\relax \fi} -%D For absolute control, one can use \type{\doreshapebox} -%D directly. This macro takes four arguments, that take care -%D of: +%D For absolute control, one can use \type {\doreshapebox} directly. This macro +%D takes four arguments, that take care of: %D %D \startitemize[n,packed] %D \item \type{\shapebox} @@ -1048,10 +1019,9 @@ %D \macros %D {shapedhbox} %D -%D When constructing a new box, using the content of \type -%D {\shapebox}, one can best use \type {\shapedhbox} instead -%D of \type {\hbox}, since it manages the height and depth of -%D the line. +%D When constructing a new box, using the content of \type {\shapebox}, one can best +%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and +%D depth of the line. \unexpanded\def\shapedhbox % lines with non strutted dimensions have {\expanded{\dowithnextbox % interlineskip so if we want the original @@ -1066,8 +1036,8 @@ %D hyphenatedfile, %D dohyphenateword} %D -%D We no longer use the pure \TEX\ variant. In due time we will -%D report some more advanced statistics. +%D We no longer use the pure \TEX\ variant. In due time we will report some more +%D advanced statistics. %D %D \starttyping %D \showhyphens{dohyphenatedword} @@ -1104,11 +1074,10 @@ %D \macros %D {processtokens} %D -%D We fully agree with (most) typographers that inter||letter -%D spacing is only permitted in fancy titles, we provide a -%D macro that can be used to do so. Because this is -%D (definitely and fortunately) no feature of \TEX, we have to -%D step through the token list ourselves. +%D We fully agree with (most) typographers that inter||letter spacing is only +%D permitted in fancy titles, we provide a macro that can be used to do so. Because +%D this is (definitely and fortunately) no feature of \TEX, we have to step through +%D the token list ourselves. %D %D \starttyping %D \processtokens {before} {between} {after} {space} {tokens} @@ -1126,8 +1095,8 @@ %D %D \getbuffer %D -%D The list of tokens may contain spaces, while \type{\\}, -%D \type{{}} and \type{\ } are handled as space too. +%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\ +%D } are handled as space too. \unexpanded\def\processtokens#1#2#3#4#5% {\begingroup @@ -1171,20 +1140,18 @@ %D \macros %D {doboundtext} %D -%D Sometimes there is not enough room to show the complete -%D (line of) text. In such a situation we can strip of some -%D characters by using \type{\doboundtext}. When the text is -%D wider than the given width, it's split and the third -%D argument is appended. When the text to be checked is packed -%D in a command, we'll have to use \type{\expandafter}. +%D Sometimes there is not enough room to show the complete (line of) text. In such a +%D situation we can strip of some characters by using \type {\doboundtext}. When the +%D text is wider than the given width, it's split and the third argument is +%D appended. When the text to be checked is packed in a command, we'll have to use +%D \type {\expandafter}. %D %D \starttyping %D \doboundtext{a very, probably to long, text}{3cm}{...} %D \stoptyping %D -%D When calculating the room needed, we take the width of the -%D third argument into account, which leads to a bit more -%D complex macro than needed at first sight. +%D When calculating the room needed, we take the width of the third argument into +%D account, which leads to a bit more complex macro than needed at first sight. \def\dodoboundtext#1% {\setbox\scratchboxone\hbox{#1}% @@ -1205,18 +1172,17 @@ %D \macros %D {limitatetext} %D -%D A bit more beautiful alternative for the previous command is -%D the next one. This command is more robust because we let -%D \TEX\ do most of the job. The previous command works better -%D on text that cannot be hyphenated. +%D A bit more beautiful alternative for the previous command is the next one. This +%D command is more robust because we let \TEX\ do most of the job. The previous +%D command works better on text that cannot be hyphenated. %D %D \starttyping %D \limitatetext {text} {width} {sentinel} %D \limitatetext {text} {-width} {prelude} %D \stoptyping %D -%D When no width is given, the whole text comes available. The -%D sentinel is optional. This is about the third version. +%D When no width is given, the whole text comes available. The sentinel is optional. +%D This is about the third version. \ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax \fi \ifdefined\veryraggedright \else \def\veryraggedright{\raggedright} \fi @@ -1477,10 +1443,9 @@ %D \macros %D {sbox} %D -%D This is a rather strange command. It grabs some box content -%D and and limits the size to the height and depth of a -%D \type{\strut}. The resulting bottom||alligned box can be used -%D aside other ones, without disturbing the normal baseline +%D This is a rather strange command. It grabs some box content and and limits the +%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned +%D box can be used aside other ones, without disturbing the normal baseline %D distance. %D %D \startbuffer @@ -1496,10 +1461,9 @@ %D \getbuffer %D \stopexample %D -%D Before displaying the result we added some skip, otherwise -%D the first two lines would have ended up in the text. This -%D macro can be useful when building complicated menus, headers -%D and footers and|/|or margin material. +%D Before displaying the result we added some skip, otherwise the first two lines +%D would have ended up in the text. This macro can be useful when building +%D complicated menus, headers and footers and|/|or margin material. \unexpanded\def\sbox {\vbox\bgroup @@ -1533,8 +1497,7 @@ %D \macros %D {struttedbox} %D -%D This boxing macro limits the height and depth to those of -%D a strut. +%D This boxing macro limits the height and depth to those of a strut. \unexpanded\def\struttedbox {\hpack\bgroup @@ -1549,9 +1512,8 @@ %D \macros %D {topskippedbox} %D -%D This macro compensates the difference between the topskip -%D and strutheight. Watch how we preserve the depth when it -%D equals strutdepth. +%D This macro compensates the difference between the topskip and strutheight. Watch +%D how we preserve the depth when it equals strutdepth. \unexpanded\def\topskippedbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox} @@ -1565,13 +1527,12 @@ %D \macros %D {centeredbox, centerednextbox} %D -%D Here is another strange one. This one offers a sort of overlay -%D with positive or negative offsets. This command can be used -%D in well defined areas where no offset options are available. -%D We first used it when building a button inside the margin -%D footer, where the button should have a horizontal offset and -%D should be centered with respect to the surrounding box. The -%D last of the three examples we show below says: +%D Here is another strange one. This one offers a sort of overlay with positive or +%D negative offsets. This command can be used in well defined areas where no offset +%D options are available. We first used it when building a button inside the margin +%D footer, where the button should have a horizontal offset and should be centered +%D with respect to the surrounding box. The last of the three examples we show below +%D says: %D %D \starttyping %D \vsize=3cm @@ -1581,8 +1542,8 @@ %D {\vrule width \hsize height \vsize}}} %D \stoptyping %D -%D Here the \type{\ruledvbox} just shows the surrounding box -%D and \type{\vrule} is used to show the centered box. +%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is +%D used to show the centered box. %D %D \def\AnExample#1#2% %D {\vsize=3cm @@ -1599,14 +1560,12 @@ %D \stopcombination %D \stoplinecorrection %D -%D This command takes two optional arguments: \type{width} and -%D \type{height}. Observing readers can see that we use \TEX's -%D own scanner for grabbing these arguments: \type{#1#} reads -%D everyting till the next brace and passes it to both rules. -%D The setting of the box dimensions at the end is needed for -%D special cases. The dimensions of the surrounding box are kept -%D intact. This commands handles positive and negative -%D dimensions (which is why we need two boxes with rules). +%D This command takes two optional arguments: \type {width} and \type {height}. +%D Observing readers can see that we use \TEX's own scanner for grabbing these +%D arguments: \type {#1#} reads everyting till the next brace and passes it to both +%D rules. The setting of the box dimensions at the end is needed for special cases. +%D The dimensions of the surrounding box are kept intact. This commands handles +%D positive and negative dimensions (which is why we need two boxes with rules). \unexpanded\def\centeredbox#1#% height +/-dimen width +/-dimen {\bgroup @@ -1666,8 +1625,8 @@ %D \centerbox {content} %D \stoptyping %D -%D When omitted, the current \type {\hsize} and \type -%D {\vsize} are used. Local dimensions are supported. +%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local +%D dimensions are supported. \unexpanded\def\centerbox#1#% optional height +/-dimen width +/-dimen {\bgroup @@ -1684,27 +1643,21 @@ %D \macros %D {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines} %D -%D These macros are copied from the \TEX book, page~397, and -%D extended by a macro that sets the \type{\hsize}. +%D These macros are copied from the \TEX book, page~397, and extended by a macro +%D that sets the \type {\hsize}. %D %D \starttyping %D \setrigidcolumnhsize {total width} {distance} {n} %D \rigidcolumnbalance {box} %D \stoptyping %D -%D Both these macros are for instance used in typesetting -%D footnotes. -%D -%D Men kan het proces van breken enigzins beinvloeden met de -%D volgende twee switches: +%D Both these macros are for instance used in typesetting footnotes. The following +%D flags influence the process. \newif\ifalignrigidcolumns \newif\ifstretchrigidcolumns \newif\iftightrigidcolumns % if true: just a vbox, no depth/noflines/gridsnap corrrections -%D De eerste switch bepaald het uitlijnen, de tweede rekt de -%D individuele kolommen op naar \type{\vsize}. - \unexpanded\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr {\xdef\savedrigidhsize{\the\hsize}% \hsize#1\relax @@ -1791,9 +1744,8 @@ %D \macros %D {startvboxtohbox,stopvboxtohbox,convertvboxtohbox} %D -%D Here is another of Knuth's dirty tricks, as presented on -%D pages 398 and 399 of the \TEX book. These macros can be used -%D like: +%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the +%D \TEX book. These macros can be used like: %D %D \starttyping %D \vbox @@ -1809,14 +1761,14 @@ %D \egroup %D \stoptyping %D -%D These macros are used in reformatting footnotes, so they do -%D what they're meant for. +%D These macros are used in reformatting footnotes, so they do what they're meant +%D for. \newdimen\vboxtohboxslack \newdimen\hboxestohboxslack -% Create line and fake height of paragraph by messign with heights: -% a nice hack by DEK himself. +%D Create line and fake height of paragraph by messign with heights: a nice hack by +%D DEK himself. %\unexpanded\def\setvboxtohbox % {\bgroup @@ -1933,8 +1885,8 @@ %D \macros %D {unhhbox} %D -%D The next macro is used in typesetting inline headings. -%D Let's first look at the macro and then show an example. +%D The next macro is used in typesetting inline headings. Let's first look at the +%D macro and then show an example. \newbox \unhhedbox \newbox \hhbox @@ -1977,10 +1929,9 @@ \afterassignment\dohboxofvbox \scratchcounter=} -%D This macro can be used to break a paragraph apart and treat -%D each line seperately, for instance, making it clickable. The -%D main complication is that we want to be able to continue the -%D paragraph, something that's needed in the in line section +%D This macro can be used to break a paragraph apart and treat each line seperately, +%D for instance, making it clickable. The main complication is that we want to be +%D able to continue the paragraph, something that's needed in the in line section %D headers. %D %D \startbuffer @@ -1999,23 +1950,22 @@ %D %D \typebuffer %D -%D Not that nice a definition, but effective. Note the stretch -%D we've build in the line that connects the two paragraphs. +%D Not that nice a definition, but effective. Note the stretch we've build in the +%D line that connects the two paragraphs. %D \macros %D {doifcontent} %D -%D When processing depends on the availability of content, one -%D can give the next macro a try. +%D When processing depends on the availability of content, one can give the next +%D macro a try. %D %D \starttyping %D \doifcontent{pre content}{post content}{no content}\somebox %D \stoptyping %D -%D Where \type{\somebox} is either a \type{\hbox} or -%D \type{\vbox}. If the dimension of this box suggest some -%D content, the resulting box is unboxed and surrounded by the -%D first two arguments, else the third arguments is executed. +%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the +%D dimension of this box suggest some content, the resulting box is unboxed and +%D surrounded by the first two arguments, else the third arguments is executed. \unexpanded\def\doifcontent#1#2#3% {\dowithnextbox @@ -2049,17 +1999,17 @@ %D %D \getbuffer %D -%D Where the last call of course does not show up in this -%D document, but definitely generates a confusing message. +%D Where the last call of course does not show up in this document, but definitely +%D generates a confusing message. %D \macros %D {processboxes} %D -%D The next macro gobble boxes and is for instance used for -%D overlays. First we show the general handler. +%D The next macro gobble boxes and is for instance used for overlays. First we show +%D the general handler. -% we cannot use \futurelet here as we want to skip spaces between -% boxes (see startoverlay for an example usage) +% We cannot use \futurelet here as we want to skip spaces between boxes (see +% startoverlay for an example usage) % \newbox\processbox % public : this is the one where \nextbox's end up in % @@ -2184,8 +2134,7 @@ %D \hbox{\fakebox0} %D \stoptyping %D -%D returns an empty box with the dimensions of the box -%D specified, here being zero. +%D returns an empty box with the dimensions of the box specified, here being zero. \unexpanded\def\fakebox {\bgroup @@ -2210,10 +2159,9 @@ %D \rbox{text ...} %D \stoptyping %D -%D Are similar to \type {\vbox}, which means that they also -%D accept something like \type{to 3cm}, but align to the left, -%D middle and right. These box types can be used to typeset -%D paragraphs. +%D Are similar to \type {\vbox}, which means that they also accept something like +%D \type {to 3cm}, but align to the left, middle and right. These box types can be +%D used to typeset paragraphs. \def\syst_boxes_lrc_process#1{\bgroup\forgetall\let\\\endgraf#1\let\next} @@ -2225,8 +2173,8 @@ \unexpanded\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter} \unexpanded\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright } -%D The alternatives \type {\tbox} and \type {\bbox} can be used -%D to properly align boxes, like in: +%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align +%D boxes, like in: %D %D \setupexternalfigures[directory={../sample}] %D \startbuffer @@ -2288,16 +2236,15 @@ %D \macros %D {boxofsize} %D -%D Sometimes we need to construct a box with a height or -%D width made up of several dimensions. Instead of cumbersome -%D additions, we can use: +%D Sometimes we need to construct a box with a height or width made up of several +%D dimensions. Instead of cumbersome additions, we can use: %D %D \starttyping %D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset} %D \stoptyping %D -%D This example demonstrates that one can use positive and -%D negative values. Dimension registers are also accepted. +%D This example demonstrates that one can use positive and negative values. +%D Dimension registers are also accepted. \newdimen\sizeofbox @@ -2527,8 +2474,8 @@ %D \macros %D {initializeboxstack,savebox,foundbox} %D -%D At the cost of some memory, but saving box registers, we -%D have implemented a box repository. +%D At the cost of some memory, but saving box registers, we have implemented a box +%D repository. %D %D \starttyping %D \initializeboxstack{one} @@ -2665,9 +2612,8 @@ %D \macros %D {removedepth, obeydepth} %D -%D While \type {\removedepth} removes the preceding depth, -%D \type {\obeydepth} makes sure we have depth. Both macros -%D leave the \type {\prevdepth} untouched. +%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes +%D sure we have depth. Both macros leave the \type {\prevdepth} untouched. \unexpanded\def\removedepth {\ifvmode @@ -2700,8 +2646,8 @@ %D \macros %D {makestrutofbox} %D -%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete -%D so it will go away. +%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so +%D it will go away. \unexpanded\def\makestrutofbox % not used {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register} @@ -2714,9 +2660,8 @@ %D \macros %D {raisebox,lowerbox} %D -%D Some more box stuff, related to positioning (under -%D construction). Nice stuff for a tips and tricks maps -%D article. +%D Some more box stuff, related to positioning (under construction). Nice stuff for +%D a tips and tricks maps article. %D %D \starttyping %D \raisebox{100pt}\hbox{test} diff --git a/tex/context/base/mkiv/supp-box.mkxl b/tex/context/base/mkiv/supp-box.mkxl new file mode 100644 index 000000000..920624329 --- /dev/null +++ b/tex/context/base/mkiv/supp-box.mkxl @@ -0,0 +1,2930 @@ +%D \module +%D [ file=supp-box, +%D version=1995.10.10, +%D title=\CONTEXT\ Support Macros, +%D subtitle=Boxes, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Support Macros / Boxes} + +\unprotect + +\registerctxluafile{supp-box}{optimize} + +% This file is partially cleaned up. + +%D First some defaults: + +\fixupboxesmode\plusone + +% handy to have +% +% \hbox to \hsize +% {\en +% \switchnaarkorps[5pt]% +% \emergencystretch2em +% \dimen0=\baselineskip +% \baselineskip=\dimen0 plus 1pt +% \hsize=.2\hsize +% \vsize=2\hsize +% \ruledvbox to \vsize{\input tufte \par}\hss +% \ruledvbox to \vsize{\input tufte \par\kern-\prevdepth}\hss +% \ruledvbox to \vsize{\input tufte \par\kern0pt}\hss +% \ruledvbox to \vsize{\input tufte \par\vfill}\hss +% \ruledvbox to \vsize{\input tufte \par\kern-\prevdepth\vfill}} +% +% \hbox to \hsize +% {\en +% \switchnaarkorps[5pt]% +% \emergencystretch2em +% \dimen0=\baselineskip +% \baselineskip=\dimen0 plus 1pt +% \hsize=.18\hsize +% \vsize=2.5\hsize +% \setbox0=\vbox{\input tufte\relax}% +% \ruledvbox to \vsize{\unvcopy0}\hss +% \ruledvbox to \vsize{\unvcopy0\kern-\dp0}\hss +% \ruledvbox to \vsize{\unvcopy0\kern0pt}\hss +% \ruledvbox to \vsize{\unvcopy0\vfill}\hss +% \ruledvbox to \vsize{\unvcopy0\kern-\dp0\vfill}} + +%D \macros +%D {dontcomplain} +%D +%D The next macro suppresses over- and underfull messages which often makes sense +%D when we deal with boxes. + +\unexpanded\def\dontcomplain + {\hbadness\plustenthousand + \vbadness\plustenthousand + \hfuzz \maxdimen + \vfuzz \maxdimen} + +%D This module implements some box manipulation macros. Some are quite simple, some +%D are more advanced and when understood well, all can be of use. +%D +%D \macros +%D {strutdp,strutht,strutwd} +%D +%D The next shortcuts save memory and keying. The width is normally zero points (if +%D not, you're in trouble). These shortcuts can be used like a dimension, opposite +%D to the core macros \type {\strutdepth} and alike, which are values. + +\def\strutdp {\dp\strutbox} +\def\strutht {\ht\strutbox} +\def\strutwd {\wd\strutbox} +\def\struthtdp{\htdp\strutbox} +\def\strutgap {\dimexpr\ht\strutbox-\dp\strutbox\relax} + +%D \macros +%D {voidbox,nextbox} +%D +%D Let's start with an easy one. The next macro hides the ugly \type {@} in \type +%D {\voidb@x}. + +\ifdefined\voidbox \else \newbox\voidbox \fi +\ifdefined\nextbox \else \newbox\nextbox \fi + +%D \macros +%D {nextdepth} +%D +%D Let's start with a rather simple declaration. Sometimes we need to save the \TEX\ +%D \DIMENSION\ \type{\prevdepth} and append it later on. The name \type {\nextdepth} +%D suits this purpose well. + +\newdimen\nextdepth + +%D \macros +%D {smashbox, smashedbox} +%D +%D Smashing is introduced in \PLAIN\ \TEX, and stands for reducing the dimensions of +%D a box to zero. The most resolute one is presented first. + +\unexpanded\def\smashbox#1% + {\wd#1\zeropoint + \ht#1\zeropoint + \dp#1\zeropoint} + +\unexpanded\def\smashboxed#1% + {\wd#1\zeropoint + \ht#1\zeropoint + \dp#1\zeropoint + \box#1\relax} + +%D \macros +%D {hsmashbox,vsmashbox} +%D +%D Smashing can be used for overlaying boxes. Depending on the mode, horizontal or +%D vertical, one can use: + +\unexpanded\def\hsmashbox#1% + {\wd#1\zeropoint} + +\unexpanded\def\vsmashbox#1% + {\ht#1\zeropoint + \dp#1\zeropoint} + +%D The next implementation is less sensitive for spurious spaces. + +\newcount\c_boxes_register + +\unexpanded\def\smashbox + {\afterassignment\syst_boxes_smash_boxes_register\c_boxes_register} + +\def\syst_boxes_smash_boxes_register + {\wd\c_boxes_register\zeropoint + \ht\c_boxes_register\zeropoint + \dp\c_boxes_register\zeropoint} + +\unexpanded\def\hsmashbox + {\afterassignment\syst_boxes_hsmashed_boxes_register\c_boxes_register} + +\def\syst_boxes_hsmashed_boxes_register + {\wd\c_boxes_register\zeropoint} + +\unexpanded\def\vsmashbox + {\afterassignment\syst_boxes_vsmashed_boxes_register\c_boxes_register} + +\def\syst_boxes_vsmashed_boxes_register + {\ht\c_boxes_register\zeropoint + \dp\c_boxes_register\zeropoint} + +\unexpanded\def\smashedbox + {\afterassignment\syst_boxes_smashed_boxes_register\c_boxes_register} + +\unexpanded\def\syst_boxes_smashed_boxes_register + {\wd\c_boxes_register\zeropoint + \ht\c_boxes_register\zeropoint + \dp\c_boxes_register\zeropoint + \box\c_boxes_register} + +%D \macros +%D {hsmash,vsmash, +%D hsmashed,vsmashed} +%D +%D While the previous macros expected a \BOX, the next act on a content. They are +%D some subtle differences betreen the smash and smashed alternatives. The later +%D ones reduce all dimensions to zero. + +\unexpanded\def\hsmash {\bgroup\dowithnextboxcs\syst_boxes_hsmashed_nextbox\hbox} +\unexpanded\def\vsmash {\bgroup\dowithnextboxcs\syst_boxes_vsmashed_nextbox\vbox} +\unexpanded\def\hsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \hbox} +\unexpanded\def\vsmashed{\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox \vbox} + +\unexpanded\def\syst_boxes_hsmashed_nextbox + {\wd\nextbox\zeropoint + \box\nextbox + \egroup} + +\unexpanded\def\syst_boxes_vsmashed_nextbox + {\ht\nextbox\zeropoint + \dp\nextbox\zeropoint + \box\nextbox + \egroup} + +\unexpanded\def\syst_boxes_smashed_nextbox + {\ht\nextbox\zeropoint + \dp\nextbox\zeropoint + \wd\nextbox\zeropoint + \box\nextbox + \egroup} + +%D \macros +%D {smashedhbox,smashedvbox} +%D +%D Also handy (all dimensions zeroed): +%D +%D \starttyping +%D \smashedhbox to ... {...} +%D \smashedvbox to ... {...} +%D \stoptyping + +\unexpanded\def\smashedhbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\hbox} +\unexpanded\def\smashedvbox{\vpack\bgroup\dowithnextboxcs\syst_boxes_smashed_nextbox\vbox} + +%D First we define a helper. We use a \LUATEX\ feature in order to avoid +%D mathpalettes. + +\newcount\c_boxes_math_style + +\unexpanded\def\syst_boxes_math_set_nextbox#1% + {\c_boxes_math_style\mathstyle + \setbox\nextbox\hbox{\normalstartimath\mathsurround\zeropoint\triggermathstyle\c_boxes_math_style{#1}\normalstopimath}} + +%D \macros +%D {smash} +%D +%D This smash alternative takes an optional arg [whdtb] as well as is potentially +%D catcode safer. It is needed by the math module (although the \type {\leavevmode} +%D is not added here). + +\unexpanded\def\smash + {\begingroup + \futurelet\nexttoken\syst_boxes_smash} + +\def\syst_boxes_smash + {\ifx\nexttoken[% + \expandafter\syst_boxes_smash_yes + \else + \expandafter\syst_boxes_smash_nop + \fi} + +\def\syst_boxes_smash_nop + {\edef\m_boxes_smash_options{hd}% + \futurelet\nexttoken\syst_boxes_smash_indeed} + +\def\syst_boxes_smash_yes[#1]% + {\edef\m_boxes_smash_options{#1}% + \futurelet\nexttoken\syst_boxes_smash_indeed} + +\def\syst_boxes_smash_indeed + {\ifmmode + \expandafter\syst_boxes_smash_math + \orelse\ifx\nexttoken\bgroup + \expandafter\syst_boxes_smash_hbox + \else + \expandafter\syst_boxes_smash_text + \fi} + +\def\syst_boxes_smash_math#1% + {\syst_boxes_math_set_nextbox{#1}% + \syst_boxes_smash_process} + +\def\syst_boxes_smash_hbox + {\dowithnextboxcs\syst_boxes_smash_process\hbox} + +\def\syst_boxes_smash_text#1% + {\setbox\nextbox\hbox{#1}% + \syst_boxes_smash_process} + +\def\syst_boxes_smash_process + {\expandafter\syst_boxes_smash_process_option\m_boxes_smash_options\relax + \box\nextbox + \endgroup} + +\installcorenamespace {smashoptions} + +\setvalue{\??smashoptions w}{\wd\nextbox\zeropoint} +\setvalue{\??smashoptions h}{\ht\nextbox\zeropoint} +\setvalue{\??smashoptions d}{\dp\nextbox\zeropoint} +\setvalue{\??smashoptions t}{\ht\nextbox\zeropoint} +\setvalue{\??smashoptions b}{\dp\nextbox\zeropoint} + +\def\syst_boxes_smash_process_option#1% + {\ifx#1\relax\else + \begincsname\??smashoptions#1\endcsname + \expandafter\syst_boxes_smash_process_option + \fi} + +\def\syst_boxes_lower_nextbox_dp + {\setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}} + +%D \starttabulate[|l|l|] +%D \NC w \NC \ruledhbox{\smash [w]{This is some great smashing, isn't it?}} \NC \NR +%D \NC h \NC \ruledhbox{\smash [h]{This is some great smashing, isn't it?}} \NC \NR +%D \NC d \NC \ruledhbox{\smash [d]{This is some great smashing, isn't it?}} \NC \NR +%D \NC tb \NC \ruledhbox{\smash [tb]{This is some great smashing, isn't it?}} \NC \NR +%D \NC whd \NC \ruledhbox{\smash[whd]{This is some great smashing, isn't it?}} \NC \NR +%D \stoptabulate + +%D \macros +%D {phantom, hphantom, vphantom, mathstrut} +%D +%D The next implementation of \type {\phantom} cum suis does not grab an argument in +%D the non||math case, which is better. +%D +%D Due to a complicated call to \type {\mathpallete} and thereby \type +%D {\mathchoice}, the next macro looks ugly. We also take care of non||braced +%D arguments. + +\unexpanded\def\phantom {\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed } +\unexpanded\def\vphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_v} +\unexpanded\def\hphantom{\begingroup\futurelet\nexttoken\syst_boxes_phantom_indeed_h} + +\def\syst_boxes_phantom_math #1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make } +\def\syst_boxes_phantom_math_v#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_v} +\def\syst_boxes_phantom_math_h#1{\syst_boxes_math_set_nextbox{#1}\syst_boxes_phantom_make_h} + +\def\syst_boxes_phantom_hbox {\dowithnextboxcs\syst_boxes_phantom_make \hbox} % always hbox +\def\syst_boxes_phantom_hbox_v{\dowithnextboxcs\syst_boxes_phantom_make_v\hbox} % always hbox +\def\syst_boxes_phantom_hbox_h{\dowithnextboxcs\syst_boxes_phantom_make_h\hbox} % always hbox + +\def\syst_boxes_phantom_text #1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make } % always hbox +\def\syst_boxes_phantom_text_v#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_v} % always hbox +\def\syst_boxes_phantom_text_h#1{\setbox\nextbox\hbox{#1}\syst_boxes_phantom_make_h} % always hbox + +\def\syst_boxes_phantom_indeed + {\ifmmode + \expandafter\syst_boxes_phantom_math + \orelse\ifx\nexttoken\bgroup + \expandafter\syst_boxes_phantom_hbox + \else + \expandafter\syst_boxes_phantom_text + \fi} + +\def\syst_boxes_phantom_indeed_v + {\ifmmode + \expandafter\syst_boxes_phantom_math_v + \orelse\ifx\nexttoken\bgroup + \expandafter\syst_boxes_phantom_hbox_v + \else + \expandafter\syst_boxes_phantom_text_v + \fi} + +\def\syst_boxes_phantom_indeed_h + {\ifmmode + \expandafter\syst_boxes_phantom_math_h + \orelse\ifx\nexttoken\bgroup + \expandafter\syst_boxes_phantom_hbox_h + \else + \expandafter\syst_boxes_phantom_text_h + \fi} + +\def\syst_boxes_phantom_make + {\setbox\scratchbox\emptyhbox + \ht\scratchbox\ht\nextbox + \dp\scratchbox\dp\nextbox + \wd\scratchbox\wd\nextbox + \box\scratchbox + \endgroup} + +\def\syst_boxes_phantom_make_v + {\setbox\scratchbox\emptyhbox + \ht\scratchbox\ht\nextbox + \dp\scratchbox\dp\nextbox + \box\scratchbox + \endgroup} + +\def\syst_boxes_phantom_make_h + {\setbox\scratchbox\emptyhbox + \wd\scratchbox\wd\nextbox + \box\scratchbox + \endgroup} + +%D We also define plain's \type {\mathstrut}. + +\unexpanded\def\mathstrut{\vphantom(} % can be made faster by inlining + +%D \macros +%D {getboxheight} +%D +%D Although often needed, \TEX\ does not support arithmics like: +%D +%D \starttyping +%D \dimen0 = \ht0 + \dp0 +%D \stoptyping +%D +%D so we implemented: +%D +%D \starttyping +%D \getboxheight ... \of \box... +%D \stoptyping +%D +%D For instance, +%D +%D \starttyping +%D \getboxheight \dimen0 \of \box0 +%D \getboxheight \someheight \of \box \tempbox +%D \stoptyping +%D +%D The implementation is rather stupid: +%D +%D \starttyping +%D \def\getboxheight#1\of#2\box#3% +%D {#1\ht#3\advance#1\dp#3\relax} +%D \stoptyping +%D +%D The next alternative is slightly more clever, since it accepts \type {{12}} as +%D well as \type {12} as box number. + +\unexpanded\def\getboxheight#1\of#2\box#3% + {\def\next{#1\dimexpr\ht\c_boxes_register+\dp\c_boxes_register\relax}% + \afterassignment\next\c_boxes_register=#3} + +%D For a long time the following three macros were part of the grid snapping core +%D module, but it makes more sense to have them here so that users can see them. +%D +%D \macros +%D {getnoflines, getroundednoflines, getrawnoflines} +%D +%D Het commando \type {\getnoflines} converteert een hoogte (dimensie) in een aantal +%D regels en kent dit toe aan \type {\noflines}. +%D +%D \starttyping +%D \getnoflines{dimensie} +%D \stoptyping +%D +%D Er wordt gedeeld door \type {\openlineheight} en een hoogte van~0pt komt overeen +%D met 0~regels. The raw alternative does not round. +%D +%D For a long time we had: +%D +%D \starttyping +%D \newcount\noflines +%D \newdimen\noflinesheight +%D +%D \def\dogetnoflines#1#2% +%D {\noflinesheight#2\relax +%D \ifzeropt\noflinesheight % \ifdim\noflinesheight=\zeropoint +%D \noflines\zerocount +%D \else +%D \divide\noflinesheight \openlineheight +%D \noflines\noflinesheight +%D #1\ifdim\noflines\openlineheight=#2\relax \else +%D \advance\noflines\ifdim#2>\zeropoint\plusone\else\minusone\fi +%D \fi\fi +%D \fi} +%D +%D \def\getnoflines {\dogetnoflines\iftrue } % compensated +%D \def\getrawnoflines{\dogetnoflines\iffalse} % no compensation +%D \stoptyping +%D +%D A more recent variant is: + +\ifx\roundingeps\undefined \newdimen\roundingeps \roundingeps=10sp \fi + +\newcount\noflines +\newdimen\noflinesheight + +\unexpanded\def\getnoflines#1% + {\noflinesheight#1\relax + \ifzeropt\noflinesheight + \noflines\zerocount + \orelse\ifdim\noflinesheight>\zeropoint + \advance\noflinesheight-\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \advance\noflines\plusone + \else + \advance\noflinesheight\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \advance\noflines\minusone + \fi} + +\unexpanded\def\getroundednoflines#1% + {\noflinesheight#1\relax + \ifzeropt\noflinesheight + \noflines\zerocount + \orelse\ifdim\noflinesheight>\zeropoint + \advance\noflinesheight\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \else + \advance\noflinesheight-\roundingeps + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \fi} + +\unexpanded\def\getrawnoflines#1% + {\noflinesheight#1\relax + \ifzeropt\noflinesheight + \noflines\zerocount + \orelse\ifdim\noflinesheight>\zeropoint + \advance\noflinesheight\roundingeps + \advance\noflinesheight.5\openlineheight + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \else + \advance\noflinesheight-\roundingeps + \advance\noflinesheight-.5\openlineheight + \divide\noflinesheight\openlineheight + \noflines\noflinesheight + \fi} + +%D Let's proof that it works: +%D +%D \startbuffer +%D \scratchdimen\dimexpr(3pt) \getnoflines\scratchdimen 1=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.1\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.5\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.9\lineheight) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3pt) \getnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight-3sp) \getnoflines\scratchdimen 10=\the\noflines \endgraf +%D +%D \scratchdimen\dimexpr(3pt) \getrawnoflines\scratchdimen 0=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.1\lineheight) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.5\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10.9\lineheight) \getrawnoflines\scratchdimen 11=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3pt) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight+3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \scratchdimen\dimexpr(10\lineheight-3sp) \getrawnoflines\scratchdimen 10=\the\noflines \endgraf +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +%D \macros +%D {determinenoflines} +%D +%D The next macro determines the number of lines and returns it it \type +%D {\noflines}. The macro works reasonable well as long as the content can be +%D unboxed. +%D +%D \starttyping +%D \determinenoflines{test\\test} +%D \determinenoflines{\bfd test\\test} +%D \determinenoflines{\definedfont[Sans at 40pt]test\\test} +%D \stoptyping + +\def\dodeterminenoflines % can be mkiv'd + {\beginofshapebox + \unvbox\nextbox + \endofshapebox + % \global\count1\zerocount + % \reshapebox{\global\advance\count1\plusone}% + % \egroup\noflines\count1 }% + \scratchcounter\zerocount + \reshapebox{\global\advance\scratchcounter\plusone}% + \expandafter\egroup\expandafter\noflines\the\scratchcounter\relax} + +\unexpanded\def\determinenoflines + {\bgroup + \forgetall + \let\crlf\endgraf + \let\\\endgraf + \dowithnextboxcs\dodeterminenoflines\vbox} + +%D \macros +%D {doiftextelse, doiftext} +%D +%D When \type {\doifelse} cum suis hopelessly fail, for instance because we pass +%D data, we can fall back on the next macro: +%D +%D \starttyping +%D \doiftextelse {data} {then branch} {else branch} +%D \doiftext {data} {then branch} +%D \stoptyping + +\unexpanded\def\doifelsetext#1% + {\begingroup + \setbox\scratchbox\hpack + {\settrialtypesetting + \ignorespaces#1\removeunwantedspaces}% + \ifzeropt\wd\scratchbox + \endgroup\expandafter\secondoftwoarguments + \else + \endgroup\expandafter\firstoftwoarguments + \fi} + +\let\doiftextelse\doifelsetext + +\unexpanded\def\doiftext#1% + {\begingroup + \setbox\scratchbox\hpack + {\settrialtypesetting + \ignorespaces#1\removeunwantedspaces}% + \ifzeropt\wd\scratchbox + \endgroup\expandafter\gobbleoneargument + \else + \endgroup\expandafter\firstofoneargument + \fi} + +%D \macros +%D {dowithnextbox,nextbox} +%D +%D Sometimes we want a macro to grab a box and do something on the content. One +%D could pass an argument to a box, but this can violate the specific \CATCODES\ of +%D its content and leads to unexpected results. The next macro treats the following +%D braced text as the content of a box and manipulates it afterwards in a predefined +%D way. +%D +%D The first argument specifies what to do with the content. This content is +%D available in \type {\nextbox}. The second argument is one of \type {\hbox}, \type +%D {\vbox} or \type {\vtop}. The third argument must be grouped with \type {\bgroup} +%D and \type {\egroup}, \type {{...}} or can be a \type {\box} specification. +%D +%D In \CONTEXT\ this macro is used for picking up a box and treating it according to +%D earlier specifications. We use for instance something like: +%D +%D \starttyping +%D \def\getfloat% +%D {\def\handlefloat{...\box\nextbox...} +%D \dowithnextboxcs\handlefloat\vbox} +%D \stoptyping +%D +%D instead of: +%D +%D \starttyping +%D \def\getfloat#1% +%D {...#1...} +%D \stoptyping +%D +%D In this implementation the \type {\aftergroup} construction is needed because +%D \type {\afterassignment} is executed inside the box. + +\unexpanded\def\dowithnextbox#1% + {\def\syst_boxes_with_next_box{#1}% + \afterassignment\syst_boxes_with_next_box_indeed + \setbox\nextbox} + +\def\syst_boxes_with_next_box_indeed + {\aftergroup\syst_boxes_with_next_box} + +\unexpanded\def\dowithnextboxcs#1% + {\let\syst_boxes_with_next_box#1% + \afterassignment\syst_boxes_with_next_box_indeed + \setbox\nextbox} + +%D So in fact we get: +%D +%D \starttyping +%D \setbox\nextbox { \aftergroup\syst_boxes_with_next_box ... } +%D \stoptyping +%D +%D or +%D +%D \starttyping +%D \setbox\nextbox { ... } \syst_boxes_with_next_box +%D \stoptyping +%D +%D A slower but more versatile implementation is: +%D +%D \starttyping +%D \unexpanded\def\dowithnextbox#1#2% +%D {\def\syst_boxes_with_next_box{#1}% +%D \ifx#2\hbox +%D \afterassignment\syst_boxes_with_next_box_indeed +%D \else\ifx#2\vbox +%D \afterassignment\syst_boxes_with_next_box_indeed +%D \else\ifx#2\vtop +%D \afterassignment\syst_boxes_with_next_box_indeed +%D \else\ifx#2\normalvcenter +%D \afterassignment\syst_boxes_with_next_box_indeed +%D \else +%D \afterassignment\syst_boxes_with_next_box +%D \fi\fi\fi\fi +%D \setbox\nextbox#2} +%D \stoptyping +%D +%D This alternative also accepts \type {\box0} and alike, but we don't really need +%D this functionality now. + +%D \macros +%D {nextboxht,nextboxwd,nextboxdp,flushnextbox} +%D +%D The next couple of shortcuts saves us memory as well as \type {{}}'s in passing +%D parameters. + +\def\nextboxht {\ht\nextbox} +\def\nextboxwd {\wd\nextbox} +\def\nextboxdp {\dp\nextbox} +\def\nextboxhtdp {\htdp\nextbox} + +\unexpanded\def\flushnextbox{\box\nextbox} + +%D \macros +%D {dowithnextboxcontent} +%D +%D But, occasionally we do need to pass some local settings without wanting to use +%D additional grouping. Therefore we provide: +%D +%D \starttyping +%D \dowithnextboxcontent{inside}{after}{box content} +%D \stoptyping +%D +%D {\em todo: Search source for potential usage!} + +\unexpanded\def\dowithnextboxcontent#1#2% inside, after + {\def\syst_boxes_with_next_box_one{#2}% + \def\syst_boxes_with_next_box_two{#1}% + \afterassignment\syst_boxes_with_next_box_content_indeed + \setbox\nextbox} + +\unexpanded\def\dowithnextboxcontentcs#1#2% inside, after + {\let\syst_boxes_with_next_box_one#2% + \let\syst_boxes_with_next_box_two#1% + \afterassignment\syst_boxes_with_next_box_content_indeed + \setbox\nextbox} + +\def\syst_boxes_with_next_box_content_indeed + {\syst_boxes_with_next_box_two\aftergroup\syst_boxes_with_next_box_one} + +%D \macros +%D {llap, rlap, tlap, blap, clap} +%D +%D Some well known friends, but we implement them our own way. We want the macros to +%D work in both math and text mode. + +\def\dodorlap{\hpack to \zeropoint{\box\nextbox\hss}\endgroup} +\def\dodollap{\hpack to \zeropoint{\hss\box\nextbox}\endgroup} +\def\dodoclap{\hpack to \zeropoint{\hss\box\nextbox\hss}\endgroup} + +\def\dorlap{\begingroup\dowithnextboxcs\dodorlap\hbox} +\def\dollap{\begingroup\dowithnextboxcs\dodollap\hbox} +\def\doclap{\begingroup\dowithnextboxcs\dodoclap\hbox} + +\def\domathclap{\mathpalette\dodomathclap} \def\dodomathclap#1#2{\doclap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}} +\def\domathllap{\mathpalette\dodomathllap} \def\dodomathllap#1#2{\dollap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}} +\def\domathrlap{\mathpalette\dodomathrlap} \def\dodomathrlap#1#2{\dorlap{\normalstartimath\mathsurround\zeropoint#1#2\normalstopimath}} + +\unexpanded\def\rlap{\mathortext\domathrlap\dorlap} +\unexpanded\def\llap{\mathortext\domathllap\dollap} +\unexpanded\def\clap{\mathortext\domathclap\doclap} + +\def\dodotlap{\vpack to \zeropoint{\vss\box\nextbox}\endgroup} +\def\dodoblap{\vpack to \zeropoint{\box\nextbox\vss}\endgroup} + +\unexpanded\def\tlap{\begingroup\dowithnextboxcs\dodotlap\vbox} +\unexpanded\def\blap{\begingroup\dowithnextboxcs\dodoblap\vbox} + +%D \macros +%D {beginofshapebox, +%D reshapebox, doreshapebox, +%D flushshapebox, +%D innerflushshapebox, +%D shapebox, +%D ifreshapingbox} +%D +%D The next utility macro originates from some linenumbering mechanism. Due to +%D \TEX's advanced way of typesetting paragraphs, it's not easy to do things on a +%D line||by||line basis. This macro is able to reprocess a given box and can act +%D upon its vertical boxed components, such as lines. The unwinding sequence in this +%D macro is inspired by a \NTG\ workshop of David Salomon in June 1992. +%D +%D First we have to grab the piece of text we want to act upon. This is done by +%D means of the duo macros: +%D +%D \starttyping +%D \beginofshapebox +%D a piece of text +%D \endofshapebox +%D \stoptyping +%D +%D When all texts is collected, we can call \type {\reshapebox} and do something +%D with it's vertical components. We can make as much passes as needed. When we're +%D done, the box can be unloaded with \type {\flushshapebox}. The only condition in +%D this scheme is that \type {\reshapebox} must somehow unload the \BOX\ \type +%D {\shapebox}. +%D +%D An important aspect is that the content is unrolled bottom||up. The next example +%D illustrates this maybe unexpected characteristic. +%D +%D \startbuffer +%D \beginofshapebox +%D \em \input tufte +%D \endofshapebox +%D +%D \newcounter\LineNumber +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \hbox{\llap{\LineNumber\hskip2em}\box\shapebox}} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D As we can see, when some kind of numbering is done, we have to add a second pass. +%D +%D \startbuffer +%D \newcounter\LineNumber +%D \newcounter\NumberOfLines +%D +%D \reshapebox +%D {\doglobal\increment\NumberOfLines +%D \box\shapebox} +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \hbox +%D {\llap{\LineNumber\ (\NumberOfLines)\hskip2em}% +%D \box\shapebox}% +%D \doglobal\decrement\NumberOfLines} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D This example shows that the content of the box is still available after flushing. +%D Another feature is that only the last reshaping counts. Multiple reshaping can be +%D done by: +%D +%D \startbuffer +%D \beginofshapebox +%D \flushshapebox +%D \endofshapebox +%D +%D \reshapebox +%D {\doglobal\increment\LineNumber +%D \hbox{\llap{$\star$\hskip1em}\box\shapebox}% +%D \doglobal\decrement\NumberOfLines} +%D +%D \flushshapebox +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D The macros are surprisingly easy to follow and in fact introduce no new concepts. +%D Nearly all books on \TEX\ show similar solutions for unwinding \BOXES. +%D +%D Some macros, like footnote ones, can be sensitive for reshaping, which can result +%D in an endless loop. We therefore offer: +%D +%D \starttyping +%D \ifreshapingbox +%D \stoptyping +%D +%D Some \CONTEXT\ commands are protected this way. Anyhow, reshaping is aborted +%D after 100 dead cycles. +%D +%D By the way, changing the height and depth of \BOX\ \type {\shapebox} results in +%D bad spacing. This means that for instance linenumbers etc. should be given zero +%D height and depth before being lapped into the margin. The previous examples +%D ignore this side effect, but beware! + +\newif \ifsomeshapeleft +\newif \ifreshapingbox + +\newbox \shapebox +\newcount \shapepenalty +\newdimen \shapekern +\newskip \shapeskip + +\newbox \newshapebox +\newbox \oldshapebox + +\newcount \shapecounter + +\newevery \everyshapebox \relax + +\def\shapesignal{.12345678pt} % or 12345sp + +\unexpanded\def\reshapebox#1% + {\doreshapebox + {#1}% + {\penalty\shapepenalty}% + {\kern \shapekern }% + {\vskip \shapeskip }} + +\newbox\tmpshapebox + +\newif\ifreshapingfailed % may save redundant runs + +\def\doreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip + {\global\reshapingfailedfalse + \ifzeropt\ht\oldshapebox % \ifdim\ht\oldshapebox=\zeropoint + \setbox\newshapebox\emptyvbox + \else + \setbox\newshapebox\vbox % can be \vpack + {\unvcopy\oldshapebox + \setbox\newshapebox\emptybox + \shapecounter\zerocount + \doloop{\dodoreshapebox{#1}{#2}{#3}{#4}}}% + \setbox\newshapebox\box\tmpshapebox + \fi} + +\ifx\originalshapebox\undefined \let\originalshapebox\oldshapebox \fi + +% We will turn this into a \MKIV\ variant (we can use \type {\vpack} too). + +\unexpanded\def\insertshapesignal + {\hpack to \shapesignal{\strut\hss}% plus \strut + \prevdepth\strutdp} % never \nointerlineskip + +\unexpanded\def\restoreshapebox % compensates for the signal + {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}} + +\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip + {\ifnum\lastnodetype=\gluenodecode + \shapeskip\lastskip + \global\setbox\tmpshapebox\vbox{#4\unvbox\tmpshapebox}% + \unskip + \orelse\ifnum\lastnodetype=\kernnodecode + \shapekern\lastkern + \global\setbox\tmpshapebox\vbox{#3\unvbox\tmpshapebox}% + \unkern + \orelse\ifnum\lastnodetype=\penaltynodecode + \shapepenalty\lastpenalty + \global\setbox\tmpshapebox\vbox{#2\unvbox\tmpshapebox}% + \unpenalty + \orelse\ifnum\lastnodetype<\zeropoint + \exitloop + \else + \setbox\shapebox\lastbox + \ifvoid\shapebox + \orelse\ifdim\wd\shapebox=\shapesignal\relax + \exitloop + \else + \shapecounter\zerocount + \global\setbox\tmpshapebox\vbox{#1\unvbox\tmpshapebox}% + \fi + \fi + \ifnum\shapecounter>100 % can be less + \global\reshapingfailedtrue + \message{!!forced exit from shapebox \the\lastnodetype !!}% + \restoreshapebox + \exitloop + \else + \advance\shapecounter \plusone + \fi} + +\unexpanded\def\beginofshapebox + {\setbox\oldshapebox\vbox + \bgroup + \reshapingboxtrue + \the\everyshapebox + \insertshapesignal} + +\unexpanded\def\endofshapebox + {\endgraf + \egroup} + +\let\beginshapebox\beginofshapebox +\let\endshapebox \endofshapebox + +\unexpanded\def\flushshapebox + {\bgroup + \ifzeropt\ht\newshapebox % \ifdim\ht\newshapebox=\zeropoint + \else + % make \prevdepth legal + % \par before the next \vskip gives far worse results + \ifdim\parskip>\zeropoint\vskip\parskip\else\par\fi + % and take a look + \ifdim\prevdepth=-\thousandpoint + \prevdepth\zeropoint + \fi + \ifdim\prevdepth<\zeropoint\relax + % something like a line or a signal or ... + \donetrue + \orelse\ifinner + % not watertight and not ok + \donefalse + \orelse\ifdim\pagegoal=\maxdimen + \donetrue + \else + % give the previous line a normal depth + \donetrue + {\forgeteverypar\verticalstrut}\nobreak + \kern-\struttotal % geen \vskip + \kern-\parskip + % \vskip-\strutdp + \fi + \scratchdimen\dp\newshapebox + \unvbox\newshapebox + % \prevdepth=0pt and \dp\newshapebox depend on last line + \kern-\scratchdimen % ?? + % now \prevdepth=0pt + \ifdone + \kern\strutdp + \prevdepth\strutdp + \fi + \fi + \egroup} + +%D In real inner situations we can use: +%D +%D \starttyping +%D \flushinnershapebox +%D \stoptyping +%D +%D This one is used in \type{\framed}. + +% The kern fails on for instance: +% +% \omlijnd[offset=0pt,hoogte=8mm,uitlijnen={rechts,laho}]{\bfa test} + +\unexpanded\def\innerflushshapebox + {\ifzeropt\ht\newshapebox \else + \unvcopy\newshapebox\relax % unvcopy ! else spacing problem + % \kern-\dp\newshapebox\relax + \fi} + +%D For absolute control, one can use \type {\doreshapebox} directly. This macro +%D takes four arguments, that take care of: +%D +%D \startitemize[n,packed] +%D \item \type{\shapebox} +%D \item \type{\shapepenalty} +%D \item \type{\shapekern} +%D \item \type{\shapeskip} +%D \stopitemize + +%D \macros +%D {shapedhbox} +%D +%D When constructing a new box, using the content of \type {\shapebox}, one can best +%D use \type {\shapedhbox} instead of \type {\hbox}, since it manages the height and +%D depth of the line. + +\unexpanded\def\shapedhbox % lines with non strutted dimensions have + {\expanded{\dowithnextbox % interlineskip so if we want the original + {\dp\nextbox\the\ht\shapebox % spacing, we need to preserve the original + \dp\nextbox\the\dp\shapebox % height and depth which is definitely + \box\nextbox}} % needed if we apply struts to the 'new' + \hbox} % box or do something that changed ist size + +%D \macros +%D {hyphenatedword, +%D hyphenatedpar, +%D hyphenatedfile, +%D dohyphenateword} +%D +%D We no longer use the pure \TEX\ variant. In due time we will report some more +%D advanced statistics. +%D +%D \starttyping +%D \showhyphens{dohyphenatedword} +%D \stoptyping + +\unexpanded\def\doshowhyphenatednextbox + {\clf_showhyphenatedinlist\nextbox} + +\unexpanded\def\showhyphens % hpack: so no processing (we hyphenate in lua) + {\dowithnextboxcs\doshowhyphenatednextbox\hpack} + +%D The following macros are seldom used but handy for tracing. +%D +%D \starttyping +%D \hyphenatedword{dohyphenatedword} +%D \hyphenatedpar {\dorecurse{10}{dohyphenatedword }} +%D \hyphenatedfile{tufte} +%D \stoptyping + +\unexpanded\def\dohyphenatednextbox + {\clf_hyphenatedlist\nextbox false\relax + \unhbox\nextbox} + +\unexpanded\def\hyphenatedword {\dowithnextboxcs\dohyphenatednextbox\hbox} +\unexpanded\def\hyphenatedpar {\dowithnextboxcs\dohyphenatednextbox\hbox} +\unexpanded\def\hyphenatedfile#1{\dowithnextboxcs\dohyphenatednextbox\hbox{\readfile{#1}\donothing\donothing}} + +\unexpanded\def\dohyphenatednextboxcolor + {\clf_hyphenatedlist\nextbox true\relax + \unhbox\nextbox} + +\unexpanded\def\hyphenatedcoloredword{\dowithnextboxcs\dohyphenatednextboxcolor\hbox} + +%D \macros +%D {processtokens} +%D +%D We fully agree with (most) typographers that inter||letter spacing is only +%D permitted in fancy titles, we provide a macro that can be used to do so. Because +%D this is (definitely and fortunately) no feature of \TEX, we have to step through +%D the token list ourselves. +%D +%D \starttyping +%D \processtokens {before} {between} {after} {space} {tokens} +%D \stoptyping +%D +%D An example of a call is: +%D +%D \startbuffer +%D \processtokens {[} {+} {]} {\space} {hello world} +%D \stopbuffer +%D +%D \typebuffer +%D +%D This results in: +%D +%D \getbuffer +%D +%D The list of tokens may contain spaces, while \type {\\}, \type {{}} and \type {\ +%D } are handled as space too. + +\unexpanded\def\processtokens#1#2#3#4#5% + {\begingroup + \def\lastcharacter{\lastcharacter}% + \def\space{ }% + \let\\=\space + \def\before {#1}% + \def\between{#2}% + \def\after {#3}% + \def\white {#4}% + \let\savedbefore\before + \doprocesstokens#5\lastcharacter + \endgroup} + +\def\doprocesstokens% the space after = is essential + {\afterassignment\dodoprocesstokens\let\nextprocessedtoken= } + +\def\dodoprocesstokens + {\ifx\nextprocessedtoken\lastcharacter + \after + \let\nextprocessedtoken\relax + \orelse\ifx\nextprocessedtoken\bgroup + \def\nextprocessedtoken + {\dowithnextbox + {\before{\copy\nextbox}% \before can use nextbox several times + \let\before\between + \doprocesstokens} + \hbox\bgroup}% + \else + \expandafter\if\space\nextprocessedtoken + \after\white + \let\before\savedbefore + \else + \before\nextprocessedtoken + \let\before\between + \fi + \let\nextprocessedtoken\doprocesstokens + \fi + \nextprocessedtoken} + +%D \macros +%D {doboundtext} +%D +%D Sometimes there is not enough room to show the complete (line of) text. In such a +%D situation we can strip of some characters by using \type {\doboundtext}. When the +%D text is wider than the given width, it's split and the third argument is +%D appended. When the text to be checked is packed in a command, we'll have to use +%D \type {\expandafter}. +%D +%D \starttyping +%D \doboundtext{a very, probably to long, text}{3cm}{...} +%D \stoptyping +%D +%D When calculating the room needed, we take the width of the third argument into +%D account, which leads to a bit more complex macro than needed at first sight. + +\def\dodoboundtext#1% + {\setbox\scratchboxone\hbox{#1}% + \advance\scratchdimen -\wd\scratchboxone + \ifdim\scratchdimen>\zeropoint\relax#1\fi}% + +\def\doboundtext#1#2#3% still used? + {\hbox + {\setbox\scratchbox\hbox{#1}% + \scratchdimen#2\relax + \ifdim\wd\scratchbox>\scratchdimen + \setbox\scratchbox\hbox{#3}% + \advance\scratchdimen -\wd\scratchbox + \handletokens#1\with\dodoboundtext + \fi + \box\scratchbox}} + +%D \macros +%D {limitatetext} +%D +%D A bit more beautiful alternative for the previous command is the next one. This +%D command is more robust because we let \TEX\ do most of the job. The previous +%D command works better on text that cannot be hyphenated. +%D +%D \starttyping +%D \limitatetext {text} {width} {sentinel} +%D \limitatetext {text} {-width} {prelude} +%D \stoptyping +%D +%D When no width is given, the whole text comes available. The sentinel is optional. +%D This is about the third version. + +\ifdefined\fakecompoundhyphen\else \let\fakecompoundhyphen\relax \fi +\ifdefined\veryraggedright \else \def\veryraggedright{\raggedright} \fi + +\unexpanded\def\limitatetext + {\bgroup % evt \setstrut + \forgetall % otherwise indentation and so + \let\limitatetext\firstofthreearguments + \fakecompoundhyphen % dangerous ! ! ! ! ! ! ! ! ! + \dowithnextboxcs\syst_boxes_limitate_text\hbox} + +\def\syst_boxes_limitate_text#1% #2 + {\doifelsenothing{#1}\syst_boxes_limitate_text_nop\syst_boxes_limitate_text_yes{#1}} % {#2} + +\def\syst_boxes_limitate_text_nop#1#2% + {\unhbox\nextbox + \egroup} + +\def\syst_boxes_limitate_text_yes#1#2% + {\nopenalties + \scratchdimen#1\relax + \ifdim\scratchdimen<\zeropoint\relax % we'll take the last line + \donefalse + \scratchdimen-\scratchdimen + \else + \donetrue + \fi + \ifdim\wd\nextbox>\scratchdimen + \setbox\scratchbox\hbox{\ifdone\space#2\else#2\space\fi}% + \advance\scratchdimen -\wd\scratchbox + \setbox\scratchboxone\box\nextbox + \setbox\nextbox\vbox + {\hsize\scratchdimen + \hfuzz\maxdimen + \veryraggedright + \strut + \ifdone \else + \parfillskip\zeropoint + \rightskip\zeropoint + \hskip\zeropoint \s!plus 1\s!fill % \hsize + \fi + \unhcopy\scratchboxone}% + \ifdim\ht\nextbox>\strutht + \setbox\nextbox\vbox % if omitted: missing brace reported + {\splittopskip\openstrutheight + \ifdone + \setbox\nextbox\vsplit\nextbox to \strutht + \else + \doloop + {\setbox\scratchboxone\vsplit\nextbox to \strutht + \ifdim\ht\nextbox>\strutht \else \exitloop \fi}% + \fi + \unvbox\nextbox + \setbox\nextbox\lastbox + \global\setbox1\hpack + {\ifdone + \unhbox\nextbox\unskip\kern\zeropoint\box\scratchbox + \else + \box\scratchbox\unhbox\nextbox + \fi + \unskip}}% + \unhbox1 + \else + \unhbox0% + \fi + \else + \unhbox\nextbox + \fi + \egroup} + +%D We can also limit a text with more control: +%D +%D \startbuffer +%D \limitatetext {\input tufte } {2cm,5mm} {\unknown} +%D \limitatetext {ton en hans} {2cm,5mm} {\unknown} +%D \limitatetext {ton en hans zijn eikels} {2cm,5mm} {\unknown} +%D \limitatetext {ton} {2cm,5mm} {\unknown} +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D We build this feature on top of the previous macro. + +% we could move the text argument to the end + +\let\normallimitatetext\limitatetext + +\def\speciallimitatetext#1#2#3#4% text left right placeholder + {%\dontleavehmode + \bgroup + \let\speciallimitatetext\firstoffourarguments + \setbox\scratchboxone\hbox + {\nohyphens + \normallimitatetext{#1}{+#2}{}#4% + \normallimitatetext{#1}{-#3}{}}% + \setbox\scratchboxtwo\hbox + {#1}% + \ifdim\wd\scratchboxtwo<\wd\scratchboxone #1\else\unhbox\scratchboxone\fi + \egroup} + +\unexpanded\def\limitatetext#1#2#3% \expanded added 2003/01/16 + {\splitatcomma{#2}\leftlimit\rightlimit + \ifx\rightlimit\empty + \normallimitatetext {#1}\leftlimit {#3}% + \else + \speciallimitatetext{#1}\leftlimit\rightlimit{#3}% + \fi} + +%D Undocumented bonus (see wiki): +%D +%D \starttyping +%D \limitatefirstline{\input tufte\relax}{10cm}{\unknown} +%D \stoptyping + +\unexpanded\def\limitatefirstline#1#2#3% + {\hbox\bgroup\strut % \hpack + \setbox\scratchbox\hbox{\begstrut#1\endstrut}% + \ifdim\wd\scratchbox>#2\relax + \setbox\scratchbox\hbox{#3}% + \hsize#2\relax + \advance\hsize-\wd\scratchbox + \setbox\scratchbox\vbox{\forgetall\veryraggedright#1}% + \setbox\scratchbox\vsplit\scratchbox to \lineheight + \vbox + {\unvbox\scratchbox + \global\setbox\plusone\lastbox + \global\setbox\plusone\hbox{\strut\unhbox\plusone}% + \hbox % to #2 % \hpack + {\ifx\clip\undefined + \box\plusone + \orelse\ifdim\wd\plusone>\hsize + \lower\strutdepth\hpack{\clip[\c!width=\hsize,\c!height=\lineheight]{\hpack{\raise\strutdepth\box\plusone}}}% + \else + \box\plusone + \fi + \removeunwantedspaces#3}}% \removeunwantedspaces\hss#3}}% + \else + #1% + \fi + \egroup} + +%D \macros +%D {processisolatedwords,processisolatedchars} +%D +%D \startbuffer +%D \processisolatedchars{some more words} \ruledhbox \par +%D \processisolatedchars{and some $x + y = z$ math} \ruledhbox \par +%D \processisolatedchars{and a \hbox{$x + y = z$}} \ruledhbox \par +%D \processisolatedwords{some more words} \ruledhbox \par +%D \processisolatedwords{and some $x + y = z$ math} \ruledhbox \par +%D \processisolatedwords{and a \hbox{$x + y = z$}} \ruledhbox \par +%D \stopbuffer +%D +%D \typebuffer \blank \getbuffer \blank + +% todo: provide variant with #1 picked up as box + +\unexpanded\def\processisolatedchars#1#2% + {\dontleavehmode + \begingroup + \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}% + \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}% + \clf_applytobox + method {char}% + box \scratchbox + command {\csstring#2}% + nested true% + \relax + \endgroup} + +\unexpanded\def\processisolatedwords#1#2% + {\dontleavehmode + \begingroup + \setbox\scratchbox\hbox{\settrialtypesetting#2{\savecurrentattributes{pic}}}% + \setbox\scratchbox\hbox{\restorecurrentattributes{pic}#1}% + \clf_applytobox + method {word}% + box \scratchbox + command {\csstring#2}% + nested true% + \relax + \endgroup} + +%D A variant: + +\unexpanded\def\applytocharacters#1% + {\dontleavehmode + \dowithnextbox{\clf_applytobox + method {char}% + box \nextbox + command {\csstring#1}% + nested true% + \relax}% + \hbox} + +\unexpanded\def\applytowords#1% + {\dontleavehmode + \dowithnextbox{\clf_applytobox + method {word}% + box \nextbox + command {\csstring#1}% + nested true% + \relax}% + \hbox} + +%D The old call: + +\unexpanded\def\processwords#1% + {\processisolatedwords{#1}\processword} + +\let\processword\relax + +\unexpanded\def\applytosplitstringchar#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {char}% + \relax} + +\unexpanded\def\applytosplitstringword#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {word}% + \relax} + +\unexpanded\def\applytosplitstringline#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {line}% + \relax} + +\unexpanded\def\applytosplitstringcharspaced#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {char}% + spaced true% + \relax} + +\unexpanded\def\applytosplitstringwordspaced#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {word}% + spaced true% + \relax} + +\unexpanded\def\applytosplitstringlinespaced#1#2% + {\dontleavehmode\clf_processsplit + data {#2}% + command {\csstring#1}% + method {line}% + spaced true% + \relax} + +%D \macros +%D {sbox} +%D +%D This is a rather strange command. It grabs some box content and and limits the +%D size to the height and depth of a \type {\strut}. The resulting bottom||alligned +%D box can be used aside other ones, without disturbing the normal baseline +%D distance. +%D +%D \startbuffer +%D \ruledhbox to .5\hsize{\sbox{eerste\par tweede \par derde}} +%D \stopbuffer +%D +%D \typebuffer +%D +%D Shows up as: +%D +%D \startexample +%D \vskip3\baselineskip +%D \getbuffer +%D \stopexample +%D +%D Before displaying the result we added some skip, otherwise the first two lines +%D would have ended up in the text. This macro can be useful when building +%D complicated menus, headers and footers and|/|or margin material. + +\unexpanded\def\sbox + {\vbox\bgroup + \dowithnextboxcs\syst_boxes_sbox_finish\vbox} + +\unexpanded\def\syst_boxes_sbox_finish + {\setbox\nextbox\hpack + {\strut + \dp\nextbox\zeropoint + \lower\strutdp\box\nextbox}% + \dp\nextbox\strutdp + \ht\nextbox\strutht + \box\nextbox + \egroup} + +%D A variant on this: + +\unexpanded\def\inlinedbox + {\bgroup + \dowithnextbox + {\setbox\nextbox\hpack + {\lower + \dimexpr(\htdp\nextbox-\lineheight)/\plustwo+\strutdp\relax + \box\nextbox}% + \ht\nextbox\strutht + \dp\nextbox\strutdp + \box\nextbox + \egroup}% + \hbox} + +%D \macros +%D {struttedbox} +%D +%D This boxing macro limits the height and depth to those of a strut. + +\unexpanded\def\struttedbox + {\hpack\bgroup + \dowithnextboxcs\syst_boxes_struttedbox_finish\hbox} + +\def\syst_boxes_struttedbox_finish + {\dp\nextbox\strutdepth + \ht\nextbox\strutheight + \box\nextbox + \egroup} + +%D \macros +%D {topskippedbox} +%D +%D This macro compensates the difference between the topskip and strutheight. Watch +%D how we preserve the depth when it equals strutdepth. + +\unexpanded\def\topskippedbox + {\hpack\bgroup\dowithnextboxcs\syst_boxes_topskippedbox_finish\hbox} + +\def\syst_boxes_topskippedbox_finish + {\edef\m_boxes_tmp{\ifdim\strutdepth=\dp\nextbox\dp\nextbox\the\dp\nextbox\fi}% + \lower\topskip\hpack{\raise\strutheight\box\nextbox}% + \m_boxes_tmp + \egroup} + +%D \macros +%D {centeredbox, centerednextbox} +%D +%D Here is another strange one. This one offers a sort of overlay with positive or +%D negative offsets. This command can be used in well defined areas where no offset +%D options are available. We first used it when building a button inside the margin +%D footer, where the button should have a horizontal offset and should be centered +%D with respect to the surrounding box. The last of the three examples we show below +%D says: +%D +%D \starttyping +%D \vsize=3cm +%D \hsize=3cm +%D \ruledvbox to \vsize +%D {\centeredbox height .5cm width -1cm +%D {\vrule width \hsize height \vsize}}} +%D \stoptyping +%D +%D Here the \type {\ruledvbox} just shows the surrounding box and \type {\vrule} is +%D used to show the centered box. +%D +%D \def\AnExample#1#2% +%D {\vsize=3cm +%D \hsize=3cm +%D \ruledvbox to \vsize +%D {\centeredbox height #1 width #2 +%D {\color[green]{\vrule width \hsize height \vsize}}}} +%D +%D \startlinecorrection +%D \startcombination[3*1] +%D {\AnExample {-1cm} {.5cm}} {} +%D {\AnExample {.5cm} {-1cm}} {} +%D {\AnExample {-1cm} {-.5cm}} {} +%D \stopcombination +%D \stoplinecorrection +%D +%D This command takes two optional arguments: \type {width} and \type {height}. +%D Observing readers can see that we use \TEX's own scanner for grabbing these +%D arguments: \type {#1#} reads everyting till the next brace and passes it to both +%D rules. The setting of the box dimensions at the end is needed for special cases. +%D The dimensions of the surrounding box are kept intact. This commands handles +%D positive and negative dimensions (which is why we need two boxes with rules). + +\unexpanded\def\centeredbox#1#% height +/-dimen width +/-dimen + {\bgroup + \setbox\scratchboxone\vpack to \vsize + \bgroup + \dontcomplain + \forgetall + \setbox\scratchboxone\hpack{\vrule\s!width \zeropoint#1}% + \setbox\scratchboxtwo\vpack{\hrule\s!height\zeropoint#1}% + \advance\vsize \ht\scratchboxtwo + \advance\hsize \wd\scratchboxone + \vpack to \vsize + \bgroup + \vskip-\ht\scratchboxtwo + \vss + \hpack to \hsize + \bgroup + \dowithnextbox + {\hskip-\wd\scratchboxone + \hss + \box\nextbox + \hss + \egroup + \vss + \egroup + \egroup + \wd\scratchboxone\hsize + \ht\scratchboxone\vsize + \box\scratchboxone + \egroup} + \hbox} + +%D For those who don't want to deal with \type {\hsize} and \type {\vsize}, we have: +%D +%D \starttyping +%D \centerednextbox width 2bp height 2bp +%D {\framed[width=100bp,height=100bp]{}} +%D \stoptyping +%D +%D Do you see what we call this one \type {next}? + +\unexpanded\def\centerednextbox#1#% + {\bgroup + \dowithnextbox + {\hsize\wd\nextbox + \vsize\ht\nextbox + \centeredbox#1{\box\nextbox}% + \egroup} + \hbox} + +%D \macros +%D {centerbox} +%D +%D Centering on the available space is done by: +%D +%D \starttyping +%D \centerbox {content} +%D \stoptyping +%D +%D When omitted, the current \type {\hsize} and \type {\vsize} are used. Local +%D dimensions are supported. + +\unexpanded\def\centerbox#1#% optional height +/-dimen width +/-dimen + {\bgroup + \dowithnextbox + {\setlocalhsize + \setbox\scratchbox\hpack{\vrule\s!width \zeropoint#1}% + \ifzeropt\wd\scratchbox\else\hsize\wd\scratchbox\fi + \setbox\scratchbox\vpack{\hrule\s!height\zeropoint#1}% + \ifzeropt\ht\scratchbox\else\vsize\ht\scratchbox\fi + \vpack to \vsize{\vss\hpack to \hsize{\hss\box\nextbox\hss}\vss}% + \egroup}% + \hbox} + +%D \macros +%D {setrigidcolumnhsize,rigidcolumnbalance,rigidcolumnlines} +%D +%D These macros are copied from the \TEX book, page~397, and extended by a macro +%D that sets the \type {\hsize}. +%D +%D \starttyping +%D \setrigidcolumnhsize {total width} {distance} {n} +%D \rigidcolumnbalance {box} +%D \stoptyping +%D +%D Both these macros are for instance used in typesetting footnotes. The following +%D flags influence the process. + +\newif\ifalignrigidcolumns +\newif\ifstretchrigidcolumns +\newif\iftightrigidcolumns % if true: just a vbox, no depth/noflines/gridsnap corrrections + +\unexpanded\def\setrigidcolumnhsize#1#2#3% todo: \dimexpr + {\xdef\savedrigidhsize{\the\hsize}% + \hsize#1\relax + \global\chardef\rigidcolumns#3\relax + \scratchdimen -#2\relax + \multiply\scratchdimen #3\relax + \advance\scratchdimen #2\relax + \advance\hsize \scratchdimen + \divide\hsize #3\relax} + +% == +% +% \def\setrigidcolumnhsize#1#2#3% +% {\xdef\savedrigidhsize{\the\hsize}% +% \global\chardef\rigidcolumns#3\relax +% \hsize=\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax} + +\newbox\rigidcolumnbox + +\let\rigidcolumnlines\!!zerocount + +\unexpanded\def\rigidcolumnbalance#1% + {\ifnum\rigidcolumns=1 % tzt ook h/d correctie + \ifinner\ifhmode\box\else\unvbox\fi\else\unvbox\fi#1\relax + \else + \vbox % \vpack + {\forgetall + \nopenalties + \dontcomplain + \setbox\rigidcolumnbox\vbox + {\line{}\goodbreak\unvbox#1\removebottomthings}% + \splittopskip\openstrutheight + \setbox\scratchbox\vsplit\rigidcolumnbox to \zeropoint + \ifcase\rigidcolumnlines\relax + % \iffalse + % % maybe some day an option + % \scratchskip\ht\rigidcolumnbox + % \advance\scratchskip\dp\rigidcolumnbox + % \getnoflines\scratchskip + % \ifodd\noflines + % \advance\noflines\plusone + % \fi + % \divide\noflines\rigidcolumns + %\else + \scratchdimen\ht\rigidcolumnbox + \divide\scratchdimen \rigidcolumns + \getnoflines\scratchdimen + %\fi + \else + \noflines\rigidcolumnlines % to be sure + \fi + \scratchdimen\noflines\lineheight + % new: we now loop so that we don't loose content + % since in practice we also use this macro for + % funny lineheights and border cases + \setbox0=\box\rigidcolumnbox + \doloop + {\setbox\rigidcolumnbox=\copy0 + \setbox\scratchbox\hpack to \savedrigidhsize + {\dorecurse\rigidcolumns + {\setbox\scratchbox\vsplit\rigidcolumnbox to \scratchdimen + \dp\scratchbox\openstrutdepth + \setbox\scratchbox\vtop + \ifalignrigidcolumns to + \ifstretchrigidcolumns\vsize\else\scratchdimen\fi + \fi + {\unvbox\scratchbox}% + \wd\scratchbox\hsize + \box\scratchbox + \hfill}% + \hfillneg}% + \ifvoid\rigidcolumnbox\exitloop\else\advance\scratchdimen\lineheight\fi}% + \iftightrigidcolumns + \setbox\scratchbox\hpack{\raise\dp\scratchbox\box\scratchbox}% + \else + \advance\scratchdimen -\openstrutdepth + \setbox\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}% + \dp\scratchbox\openstrutdepth + \ht\scratchbox\scratchdimen + \fi + \box\scratchbox}% + \fi} + +%D \macros +%D {startvboxtohbox,stopvboxtohbox,convertvboxtohbox} +%D +%D Here is another of Knuth's dirty tricks, as presented on pages 398 and 399 of the +%D \TEX book. These macros can be used like: +%D +%D \starttyping +%D \vbox +%D \bgroup +%D \startvboxtohbox ... \stopvboxtohbox +%D \startvboxtohbox ... \stopvboxtohbox +%D \startvboxtohbox ... \stopvboxtohbox +%D \egroup +%D +%D \vbox +%D \bgroup +%D \convertvboxtohbox +%D \egroup +%D \stoptyping +%D +%D These macros are used in reformatting footnotes, so they do what they're meant +%D for. + +\newdimen\vboxtohboxslack +\newdimen\hboxestohboxslack + +%D Create line and fake height of paragraph by messign with heights: a nice hack by +%D DEK himself. See older files for that code. + +% \definesystemattribute[vboxtohboxseparator][public] + +%newbox\d_syst_boxes_vboxtohbox +\newbox\d_syst_boxes_separator + +\unexpanded\def\startvboxtohboxseparator + {\setbox\d_syst_boxes_separator\hbox attr \vboxtohboxseparatorattribute\plusone\bgroup} + +\unexpanded\def\stopvboxtohboxseparator + {\egroup} + +\unexpanded\def\startvboxtohbox + {\begingroup + \setbox\scratchbox\hbox\bgroup} + +\unexpanded\def\stopvboxtohbox + {\ifvoid\d_syst_boxes_separator + \hskip\zeropoint\ifcase\vboxtohboxslack\else\s!minus\vboxtohboxslack\fi % we really need a skip + \else + \box\d_syst_boxes_separator + \fi + \egroup + \clf_hboxtovbox\scratchbox + \box\scratchbox + \endgroup} + +% A possible reconstruction: + +\unexpanded\def\convertvboxtohbox + {\makehboxofhboxes + \setbox\scratchboxone\hpack{\unhbox\scratchboxone\removehboxes}% \hpack + \noindent\unhbox\scratchboxone\par} + +\unexpanded\def\makehboxofhboxes + {\setbox\scratchboxone\emptyhbox + \loop % \doloop { .. \exitloop .. } + \setbox\scratchboxtwo\lastbox + \ifhbox\scratchboxtwo + \setbox\scratchboxone\hpack{\box\scratchboxtwo\unhbox\scratchboxone}% + \repeat} + +\unexpanded\def\removehboxes + {\setbox\scratchboxone\lastbox + \ifhbox\scratchboxone + {\removehboxes}\unhbox\scratchboxone + \fi} + +% And one special for notes: + +\unexpanded\def\starthboxestohbox + {\bgroup + \setbox\scratchbox\vbox\bgroup} + +\unexpanded\def\stophboxestohbox + {\egroup + \clf_vboxlisttohbox\scratchbox\nextbox\dimexpr\hboxestohboxslack\relax + \dontleavehmode + \unhbox\nextbox + \removeunwantedspaces + \par + \egroup} + +%D \macros +%D {unhhbox} +%D +%D The next macro is used in typesetting inline headings. Let's first look at the +%D macro and then show an example. + +\newbox \unhhedbox +\newbox \hhbox +\newdimen \lasthhboxwidth +\newskip \hhboxindent + +\unexpanded\def\unhhbox#1\with#2% + {\bgroup + \nopenalties + \dontcomplain + \forgetall + \setbox\unhhedbox\vbox{\hskip\hhboxindent\strut\unhbox#1}% => \hsize + \doloop + {\setbox\hhbox\vsplit\unhhedbox to \lineheight + \ifvoid\unhhedbox + \setbox\hhbox\hbox{\strut\hboxofvbox\hhbox}% \hpack + \fi + \ht\hhbox\strutht + \dp\hhbox\strutdp + \ifzeropt\hhboxindent\else % \ifdim\hhboxindent=\zeropoint\else + \setbox\hhbox\hpack{\kern-\hhboxindent\box\hhbox}% + \hhboxindent\zeropoint + \fi + \global\lasthhboxwidth\wd\hhbox + #2\relax + \ifvoid\unhhedbox + \exitloop + \else + \hskip\zeropoint \s!plus \zeropoint + \fi}% + \egroup} + +\def\dohboxofvbox + {\setbox0\vpack{\unvbox\scratchcounter\global\setbox1\lastbox}% + \unhbox1 + \egroup} + +\unexpanded\def\hboxofvbox + {\bgroup + \afterassignment\dohboxofvbox + \scratchcounter=} + +%D This macro can be used to break a paragraph apart and treat each line seperately, +%D for instance, making it clickable. The main complication is that we want to be +%D able to continue the paragraph, something that's needed in the in line section +%D headers. +%D +%D \startbuffer +%D \setbox0=\hbox{\input tufte \relax} +%D \setbox2=\hbox{\input knuth \relax} +%D \unhhbox0\with{\ruledhbox{\box\hhbox}} +%D \hskip1em plus 1em minus 1em +%D \hhboxindent=\lasthhboxwidth +%D \advance\hhboxindent by \lastskip +%D \unhhbox2\with{\ruledhbox{\box\hhbox}} +%D \stopbuffer +%D +%D \getbuffer +%D +%D This piece of text was typeset by saying: +%D +%D \typebuffer +%D +%D Not that nice a definition, but effective. Note the stretch we've build in the +%D line that connects the two paragraphs. + +%D \macros +%D {doifcontent} +%D +%D When processing depends on the availability of content, one can give the next +%D macro a try. +%D +%D \starttyping +%D \doifcontent{pre content}{post content}{no content}\somebox +%D \stoptyping +%D +%D Where \type {\somebox} is either a \type {\hbox} or \type {\vbox}. If the +%D dimension of this box suggest some content, the resulting box is unboxed and +%D surrounded by the first two arguments, else the third arguments is executed. + +\unexpanded\def\doifcontent#1#2#3% + {\dowithnextbox + {\ifhbox\nextbox + \ifdim\wd\nextbox>\zeropoint + #1\unhbox\nextbox#2\relax + \else + #3\relax + \fi + \else + \ifdim\ht\nextbox>\zeropoint + #1\unvbox\nextbox#2\relax + \else + #3\relax + \fi + \fi}} + +%D So when we say: +%D +%D \startbuffer +%D \doifcontent{[}{]}{}\hbox{content sensitive typesetting} +%D +%D \doifcontent{}{\page}{}\vbox{content sensitive typesetting} +%D +%D \doifcontent{}{}{\message{Didn't you forget something?}}\hbox{} +%D \stopbuffer +%D +%D \typebuffer +%D +%D We get: +%D +%D \getbuffer +%D +%D Where the last call of course does not show up in this document, but definitely +%D generates a confusing message. + +%D \macros +%D {processboxes} +%D +%D The next macro gobble boxes and is for instance used for overlays. First we show +%D the general handler. + +\newbox\processbox % public : this is the one where \nextbox's end up in + +\unexpanded\def\processboxes#1% + {\bgroup + \def\syst_boxes_process_indeed{#1}% #1 can be redefined halfway + \setbox\processbox\emptybox + \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop} + +\def\syst_boxes_process_yes + {\dowithnextboxcs\syst_boxes_process_content\hbox} + +\def\syst_boxes_process_content + {\removeunwantedspaces + \syst_boxes_process_indeed % takes \nextbox makes \processbox + \doifelsenextbgroup\syst_boxes_process_yes\syst_boxes_process_nop} + +\unexpanded\def\syst_boxes_process_nop + {\removeunwantedspaces + \box\processbox + \egroup} + +%D \macros +%D {startoverlay} +%D +%D We can overlay boxes by saying: +%D +%D \startbuffer +%D \startoverlay +%D {\framed{hans}} +%D {\framed[width=3cm]{ton}} +%D {\framed[height=2cm]{oeps}} +%D \stopoverlay +%D \stopbuffer +%D +%D \typebuffer +%D +%D shows up as: +%D +%D \leavevmode\getbuffer + +\def\boxisempty#1% + {\ifdim\wd#1=\zeropoint + \ifdim\ht#1=\zeropoint + \ifdim\dp#1=\zeropoint + \zerocount + \else + \plusone + \fi + \else + \plusone + \fi + \else + \plusone + \fi} + +\def\syst_boxes_overlay_process + {\ifcase\boxisempty\nextbox\else + \syst_boxes_overlay_process_indeed + \fi} + +\def\syst_boxes_overlay_process_indeed + {%\removeunwantedspaces % already done + \scratchdepth\dp\ifdim\dp\nextbox>\dp\processbox\nextbox\else\processbox\fi + \ifdim\ht\nextbox>\ht\processbox + \setbox\processbox\vpack to \ht\nextbox {\dp\processbox\zeropoint\vss\box\processbox\vss}% + \else + \setbox\nextbox \vpack to \ht\processbox{\dp\nextbox \zeropoint\vss\box\nextbox \vss}% + \fi + \dp\nextbox \scratchdepth + \dp\processbox\scratchdepth + \scratchwidth\wd\ifdim\wd\nextbox>\wd\processbox\nextbox\else\processbox\fi + \setbox\processbox\hpack to \scratchwidth + {\hpack to \scratchwidth{\hss\box\processbox\hss}% + \kern-\scratchwidth + \hpack to \scratchwidth{\hss\box\nextbox \hss}}} + +\unexpanded\def\startoverlay + {\bgroup + \let\stopoverlay\egroup + \processboxes\syst_boxes_overlay_process} + +\let\stopoverlay\relax + +%D \macros +%D {fakebox} +%D +%D The next macro is a rather silly one, but saves space. +%D +%D \starttyping +%D \hbox{\fakebox0} +%D \stoptyping +%D +%D returns an empty box with the dimensions of the box specified, here being zero. + +\unexpanded\def\fakebox + {\bgroup + \afterassignment\syst_boxes_fakebox_finish\scratchcounter} + +\def\syst_boxes_fakebox_finish + {\setbox\scratchbox\ifhbox\scratchcounter\emptyhbox\else\emptyvbox\fi + \wd\scratchbox\wd\scratchcounter + \ht\scratchbox\ht\scratchcounter + \dp\scratchbox\dp\scratchcounter + \box\scratchbox + \egroup} + +%D \macros +%D {lbox,rbox,cbox,tbox,bbox} +%D +%D Here are some convenient alternative box types: +%D +%D \starttyping +%D \lbox{text ...} +%D \cbox{text ...} +%D \rbox{text ...} +%D \stoptyping +%D +%D Are similar to \type {\vbox}, which means that they also accept something like +%D \type {to 3cm}, but align to the left, middle and right. These box types can be +%D used to typeset paragraphs. + +\def\syst_boxes_lrc_process#1{\bgroup\forgetall\let\\\endgraf#1\let\next} + +\unexpanded\def\lbox#1#{\vbox#1\syst_boxes_lrc_process\raggedleft } +\unexpanded\def\cbox#1#{\vbox#1\syst_boxes_lrc_process\raggedcenter} +\unexpanded\def\rbox#1#{\vbox#1\syst_boxes_lrc_process\raggedright } + +\unexpanded\def\ltop#1#{\vtop#1\syst_boxes_lrc_process\raggedleft } +\unexpanded\def\ctop#1#{\vtop#1\syst_boxes_lrc_process\raggedcenter} +\unexpanded\def\rtop#1#{\vtop#1\syst_boxes_lrc_process\raggedright } + +%D The alternatives \type {\tbox} and \type {\bbox} can be used to properly align +%D boxes, like in: +%D +%D \setupexternalfigures[directory={../sample}] +%D \startbuffer +%D \starttable[|||] +%D \HL +%D \VL \tbox{\externalfigure[cow][height=3cm,frame=on]} \VL top aligned \VL\SR +%D \HL +%D \VL \bbox{\externalfigure[cow][height=3cm,frame=on]} \VL bottom aligned \VL\SR +%D \HL +%D \stoptable +%D \stopbuffer +%D +%D \typebuffer +%D +%D The positioning depends on the strut settings: +%D +%D \getbuffer + +\unexpanded\def\tbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_tbox_finish\hbox} +\unexpanded\def\bbox{\hpack\bgroup\dowithnextboxcs\syst_boxes_bbox_finish\hbox} + +\def\syst_boxes_tbox_finish + {\scratchdepth\dimexpr\ht\nextbox+\dp\nextbox-\ht\strutbox\relax + \ht\nextbox\ht\strutbox + \dp\nextbox\scratchdepth + \setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}% + \ht\nextbox\ht\strutbox + \dp\nextbox\scratchdepth + \box\nextbox + \egroup} + +\def\syst_boxes_bbox_finish + {\scratchheight\dimexpr\ht\nextbox+\dp\nextbox-\dp\strutbox\relax + \dp\nextbox\dp\strutbox + \ht\nextbox\scratchheight + \setbox\nextbox\hpack{\lower\dp\nextbox\box\nextbox}% + \dp\nextbox\dp\strutbox + \ht\nextbox\scratchheight + \box\nextbox + \egroup} + +%D \macros +%D {lhbox,mhbox,rhbox} +%D +%D A few more boxes. + +\def\dodolhbox{\hpack to \hsize{\box\nextbox\hss }} +\def\dodomhbox{\hpack to \hsize{\hss\box\nextbox\hss}} +\def\dodorhbox{\hpack to \hsize{\hss\box\nextbox }} + +\unexpanded\def\lhbox{\dowithnextboxcs\dodolhbox\hbox} +\unexpanded\def\mhbox{\dowithnextboxcs\dodomhbox\hbox} +\unexpanded\def\rhbox{\dowithnextboxcs\dodorhbox\hbox} + +\let\lefthbox \lhbox +\let\midhbox \mhbox +\let\righthbox\rhbox + +%D \macros +%D {boxofsize} +%D +%D Sometimes we need to construct a box with a height or width made up of several +%D dimensions. Instead of cumbersome additions, we can use: +%D +%D \starttyping +%D \boxofsize \vbox 10cm 3cm -5cm {the text to be typeset} +%D \stoptyping +%D +%D This example demonstrates that one can use positive and negative values. +%D Dimension registers are also accepted. + +\newdimen\sizeofbox + +\unexpanded\def\boxofsize#1% + {\bgroup + \sizeofbox\zeropoint + \scratchdimen\zeropoint + \def\docommand + {\advance\sizeofbox\scratchdimen + \futurelet\next\dodocommand}% + \def\dodocommand + {\ifx\next\bgroup + \expanded{\egroup#1 to \the\sizeofbox}% + \else + \expandafter\afterassignment\expandafter\docommand\expandafter\scratchdimen + \fi}% + \docommand} + +%D Some new, still undocumented features: + +% limitatetext -> beter {text} als laatste !! +% +% \limitvbox +% \limithbox + +\unexpanded\def\limitatelines#1#2% size sentinel + {\dowithnextbox + {\dimen0=#1\hsize + \ifdim\wd\nextbox>\dimen0 + \setbox\nextbox\hbox + {\advance\dimen0 -.1\hsize + \limitatetext{\unhbox\nextbox}{\dimen0}{\nobreak#2}}% + \fi + \unhbox\nextbox} + \hbox} + +\unexpanded\def\fittoptobaselinegrid % weg hier + {\dowithnextbox + {\bgroup + \par + \dimen0\ht\nextbox + \ht\nextbox\strutht + \dp\nextbox\strutdp + \hpack{\box\nextbox} + \prevdepth\strutdp + \doloop + {\advance\dimen0 -\lineheight + \ifdim\dimen0<\zeropoint + \exitloop + \else + \nobreak + \hpack{\strut} + \fi} + \egroup} + \vbox} + +%D Some more undocumented macros (used in m-chart). + +\newif\iftraceboxplacement % \traceboxplacementtrue + +\newbox\fakedboxcursor + +\setbox\fakedboxcursor\hpack + {\vrule\s!width\zeropoint\s!height\zeropoint\s!depth\zeropoint} + +\unexpanded\def\boxcursor % overloaded in core-vis + {\iftraceboxplacement + \bgroup + \scratchdimen2\onepoint + \setbox\scratchbox\hpack to \zeropoint + {\hss + \vrule + \s!width \scratchdimen + \s!height\scratchdimen + \s!depth \scratchdimen + \hss}% + \smashedbox\scratchbox + \egroup + \else + \copy\fakedboxcursor + \fi} + +\unexpanded\def\placedbox + {\iftraceboxplacement\ruledhbox\else\hbox\fi} + +\newdimen\boxoffset +\newdimen\boxhdisplacement +\newdimen\boxvdisplacement + +\unexpanded\def\rightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbox_finish \placedbox} +\unexpanded\def\leftbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbox_finish \placedbox} +\unexpanded\def\topbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_topbox_finish \placedbox} +\unexpanded\def\bottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_bottombox_finish \placedbox} +\unexpanded\def\lefttopbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_lefttopbox_finish \placedbox} +\unexpanded\def\righttopbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_righttopbox_finish \placedbox} +\unexpanded\def\leftbottombox {\hpack\bgroup\dowithnextboxcs\syst_boxes_leftbottombox_finish \placedbox} +\unexpanded\def\rightbottombox{\hpack\bgroup\dowithnextboxcs\syst_boxes_rightbottombox_finish\placedbox} + +\let\topleftbox \lefttopbox +\let\toprightbox \righttopbox +\let\bottomleftbox \leftbottombox +\let\bottomrightbox\rightbottombox + +\def\syst_boxes_rightbox_finish + {\global\boxhdisplacement\boxoffset + \global\boxvdisplacement.5\ht\nextbox + \global\advance\boxvdisplacement-.5\dp\nextbox + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_leftbox_finish + {\global\boxhdisplacement-\wd\nextbox + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement.5\ht\nextbox + \global\advance\boxvdisplacement-.5\dp\nextbox + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_topbox_finish + {\global\boxhdisplacement-.5\wd\nextbox + \global\boxvdisplacement-\dp\nextbox + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_bottombox_finish + {\global\boxhdisplacement-.5\wd\nextbox + \global\boxvdisplacement\ht\nextbox + \global\advance\boxvdisplacement\boxoffset + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_lefttopbox_finish + {\global\boxhdisplacement-\wd\nextbox + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\dp\nextbox + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_righttopbox_finish + {\global\boxhdisplacement\boxoffset + \global\boxvdisplacement-\dp\nextbox + \global\advance\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_leftbottombox_finish + {\global\boxhdisplacement-\wd\nextbox + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement\ht\nextbox + \global\advance\boxvdisplacement\boxoffset + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_rightbottombox_finish + {\global\boxhdisplacement\boxoffset + \global\boxvdisplacement\ht\nextbox + \global\advance\boxvdisplacement\boxoffset + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\unexpanded\def\middlebox {\hpack\bgroup\dowithnextboxcs\syst_boxes_middlebox_finish \placedbox} +\unexpanded\def\baselinemiddlebox{\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinemiddlebox_finish\placedbox} +\unexpanded\def\baselineleftbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselineleftbox_finish \placedbox} +\unexpanded\def\baselinerightbox {\hpack\bgroup\dowithnextboxcs\syst_boxes_baselinerightbox_finish \placedbox} + +\def\syst_boxes_middlebox_finish + {\global\boxhdisplacement-.5\wd\nextbox + \global\boxvdisplacement.5\ht\nextbox + \global\advance\boxvdisplacement-.5\dp\nextbox + \boxcursor\kern\boxhdisplacement\lower\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_baselinemiddlebox_finish + {\global\boxhdisplacement-.5\wd\nextbox + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_baselineleftbox_finish + {\global\boxhdisplacement-\wd\nextbox + \global\advance\boxhdisplacement-\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +\def\syst_boxes_baselinerightbox_finish + {\global\boxhdisplacement\boxoffset + \global\boxvdisplacement-\boxoffset + \boxcursor\kern\boxhdisplacement\raise-\boxvdisplacement\box\nextbox + \egroup} + +%D \macros +%D {obox} +%D +%D Experimental, not yet frozen: + +\unexpanded\def\lrtbbox#1#2#3#4% l r t b + {\bgroup + \dowithnextboxcontent + {\advance\hsize-#1\advance\hsize-#2\relax + \advance\vsize-#3\advance\vsize-#4\relax} + {\forgetall\vpack to \vsize{\vskip#3\hpack to \hsize{\hskip#1\box\nextbox\hss}\vss}\egroup} + \vbox} + +%D \macros +%D {toplinebox} +%D +%D See core-tbl.tex for an example of its usage: + +\unexpanded\def\toplinebox + {\dowithnextboxcs\syst_boxes_toplinebox_finish\tbox} + +\def\syst_boxes_toplinebox_finish + {\ifdim\dp\nextbox>\strutdepth + \scratchdimen\dp\nextbox + \advance\scratchdimen-\strutdepth + \getnoflines\scratchdimen + \struttedbox{\box\nextbox}% + \dorecurse\noflines\verticalstrut + \else + \box\nextbox + \fi} + +%D \macros +%D {initializeboxstack,savebox,foundbox} +%D +%D At the cost of some memory, but saving box registers, we have implemented a box +%D repository. +%D +%D \starttyping +%D \initializeboxstack{one} +%D +%D \savebox{one}{a}{test a} +%D \savebox{one}{p}{test p} +%D \savebox{one}{q}{test q} +%D +%D \hbox{a:\foundbox{one}{a}} \par +%D \hbox{q:\foundbox{one}{q}} \par +%D \hbox{p:\foundbox{one}{p}} \par +%D \hbox{x:\foundbox{one}{x}} \par +%D \hbox{y:\foundbox{two}{a}} \par +%D \stoptyping + +%D Kind of obsolete: + +\installcorenamespace {stackbox} +\installcorenamespace {stacklst} + +\unexpanded\def\setstackbox#1#2% + {\ifcsname\??stackbox#1:#2\endcsname\else + \expandafter\newbox\csname\??stackbox#1:#2\endcsname + \fi + \global\setbox\csname\??stackbox#1:#2\endcsname\vbox} + +\unexpanded\def\initializeboxstack#1% + {\def\docommand##1{\setstackbox{#1}{##1}{}}% + \ifcsname\??stacklst#1\endcsname + \expandafter\processcommacommand\expandafter[\lastnamedcs]\docommand + \fi + \letgvalueempty{\??stacklst#1}} + +\unexpanded\def\savebox#1#2% stack name + {% beware, \setxvalue defines the cs beforehand so we cannot use the + % test inside the { } + \ifcsname\??stacklst#1\endcsname + %\setxvalue{\??stacklst#1}{\csname\??stacklst#1\endcsname,#2}% + \expandafter\xdef\csname\??stacklst#1\expandafter\endcsname\expandafter{\lastnamedcs,#2}% + \else + \expandafter\xdef\csname\??stacklst#1\endcsname{#2}% + \fi + \setstackbox{#1}{#2}} + +\unexpanded\def\flushbox#1#2% unwrapped + {\ifcsname\??stackbox#1:#2\endcsname + \box\lastnamedcs + \else + \emptybox + \fi} + +\unexpanded\def\restorebox#1#2% unwrapped + {\ifcsname\??stackbox#1:#2\endcsname + \copy\lastnamedcs + \else + \emptybox + \fi} + +\unexpanded\def\foundbox#1#2% wrapped + {\vpack + {\ifcsname\??stackbox#1:#2\endcsname + \copy\lastnamedcs + \fi}} + +\unexpanded\def\doifelsebox#1#2% + {\ifcsname\??stackbox#1:#2\endcsname + \ifvoid\lastnamedcs + \doubleexpandafter\secondoftwoarguments + \else + \doubleexpandafter\firstoftwoarguments + \fi + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifboxelse\doifelsebox + +%D This one is cheaper (the above is no longer used that much): + +\installcorenamespace {boxstack} + +\newcount\c_syst_boxes_stack +\let \b_syst_boxes_stack\relax + +\unexpanded\def\syst_boxes_stack_allocate + {\newbox\b_syst_boxes_stack + \expandafter\let\csname\??boxstack\number\c_syst_boxes_stack\endcsname\b_syst_boxes_stack} + +\unexpanded\def\syst_boxes_push#1#2% + {\global\advance\c_syst_boxes_stack\plusone + \expandafter\let\expandafter\b_syst_boxes_stack\csname\??boxstack\number\c_syst_boxes_stack\endcsname + \ifx\b_syst_boxes_stack\relax % cheaper then csname check as in most cases it's defined + \syst_boxes_stack_allocate + \fi + #1\setbox\b_syst_boxes_stack\box#2\relax} + +\unexpanded\def\syst_boxes_pop#1#2% + {#1\setbox#2\box\csname\??boxstack\number\c_syst_boxes_stack\endcsname + \global\advance\c_syst_boxes_stack\minusone} + +\unexpanded\def\localpushbox {\syst_boxes_push\relax} +\unexpanded\def\localpopbox {\syst_boxes_pop \relax} + +\unexpanded\def\globalpushbox{\syst_boxes_push\global} +\unexpanded\def\globalpopbox {\syst_boxes_pop \global} + +%D And here is a more modern one (not yet in i-*): +%D +%D \starttyping +%D \dorecurse {100} { +%D \setbox\zerocount\hbox{test \recurselevel} +%D \putboxincache{foo}{\recurselevel}\zerocount +%D \copyboxfromcache{foo}{\recurselevel}\zerocount +%D \iftrue +%D \setbox\zerocount\hbox{\directboxfromcache{foo}{\recurselevel}}% +%D \else +%D \getboxfromcache{foo}{\recurselevel}\zerocount +%D \fi +%D } +%D \resetboxesincache{foo} +%D \stoptyping + +\unexpanded\def\putboxincache #1#2#3{\clf_putboxincache {#1}{#2}#3\relax} +\unexpanded\def\getboxfromcache #1#2#3{\clf_getboxfromcache {#1}{#2}#3\relax} +\unexpanded\def\doifelseboxincache #1#2{\clf_doifelseboxincache {#1}{#2}} +\unexpanded\def\copyboxfromcache #1#2#3{\clf_copyboxfromcache {#1}{#2}#3\relax} +\unexpanded\def\directboxfromcache #1#2{\clf_directboxfromcache {#1}{#2}} +\unexpanded\def\directcopyboxfromcache#1#2{\clf_directcopyboxfromcache{#1}{#2}} +\unexpanded\def\resetboxesincache #1{\clf_resetboxesincache {#1}} + +\unexpanded\def\putnextboxincache#1#2% + {\dowithnextbox{\putboxincache{#1}{#2}\nextbox}} + +%D \macros +%D {removedepth, obeydepth} +%D +%D While \type {\removedepth} removes the preceding depth, \type {\obeydepth} makes +%D sure we have depth. Both macros leave the \type {\prevdepth} untouched. + +\unexpanded\def\removedepth + {\ifvmode + \ifdim\prevdepth>\zeropoint + \kern-\prevdepth + \fi + \fi} + +\unexpanded\def\obeydepth + {\par % watch out for changes in math formulas + \ifvmode\ifdim\prevdepth<\zeropoint\orelse\ifdim\prevdepth<\strutdp + \kern\dimexpr\strutdp-\prevdepth\relax + \prevdepth\strutdp + \fi\fi} + +\unexpanded\def\undepthed + {\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\hbox} + +%D \macros +%D {removebottomthings, removelastskip} +%D +%D A funny (but rather stupid) one, plus a redefinition. + +\unexpanded\def\removebottomthings + {\dorecurse\plusfive{\unskip\unkern\unpenalty}} + +\unexpanded\def\removelastskip % \ifvmode the plain tex one \fi + {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi} + +%D \macros +%D {makestrutofbox} +%D +%D This macro sets the dimensions of a box to those of a strut. Sort of obsolete so +%D it will go away. + +\unexpanded\def\makestrutofbox % not used + {\afterassignment\syst_boxes_makestrutofbox\c_boxes_register} + +\def\syst_boxes_makestrutofbox + {\ht\c_boxes_register\strutht + \dp\c_boxes_register\strutdp + \wd\c_boxes_register\zeropoint} + +%D \macros +%D {raisebox,lowerbox} +%D +%D Some more box stuff, related to positioning (under construction). Nice stuff for +%D a tips and tricks maps article. +%D +%D \starttyping +%D \raisebox{100pt}\hbox{test} +%D \hsmash{\raisebox{100pt}\hbox{test}} +%D \stoptyping + +\unexpanded\def\raisebox#1{\bgroup\afterassignment\syst_boxes_raise_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted +\unexpanded\def\lowerbox#1{\bgroup\afterassignment\syst_boxes_lower_indeed\scratchdimen#1} % so both 10pt and {10pt} is accepted + +\def\syst_boxes_raise_indeed{\dowithnextboxcs\syst_boxes_raise_finish} +\def\syst_boxes_lower_indeed{\dowithnextboxcs\syst_boxes_lower_finish} + +\def\syst_boxes_raise_finish + {\setbox\nextbox\hpack{\raise\scratchdimen\box\nextbox}% + \ht\nextbox\strutht + \dp\nextbox\strutdp + \box\nextbox + \egroup} + +\def\syst_boxes_lower_finish + {\setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}% + \ht\nextbox\strutht + \dp\nextbox\strutdp + \box\nextbox + \egroup} + +% vcenter in text, we kunnen vcenter overloaden + +\unexpanded\def\halfwaybox + {\hpack\bgroup + \dowithnextboxcs\syst_boxes_halfwaybox_finish\hbox} + +\def\syst_boxes_halfwaybox_finish + {\dp\nextbox\zeropoint + \lower.5\ht\nextbox\box\nextbox + \egroup} + +\unexpanded\def\depthonlybox + {\tpack\bgroup + \dowithnextboxcs\syst_boxes_depthonlybox_finish\vbox} + +\def\syst_boxes_depthonlybox_finish + {\hsize\wd\nextbox + \kern\zeropoint\box\nextbox + \egroup} + +%D New: + +\def\setdimentoatleast#1#2{\ifdim#1>\zeropoint\else#1=#2\fi} +\def\setdimentoatmost #1#2{\ifdim#1>#2\relax \else#1=#2\fi} + +%D And even rawer: + +\let\naturalvcenter\normalvtop % will go away + +%D \macros +%D {vcenter} +%D +%D Also new: tex mode \type {\vcenter}. + +\unexpanded\def\vcenter + {\vbox\bgroup + \dowithnextboxcs\syst_boxes_vcenter_finish\vbox} + +\def\syst_boxes_vcenter_finish + {\hpack{\normalstartimath\vcenter{\box\nextbox}\normalstopimath}% + \egroup} + +% could be \everymathematics + +\prependtoks \let\vcenter\normalvcenter \to \everymath +\prependtoks \let\vcenter\normalvcenter \to \everydisplay + +% \appendtoks \let\vcenter\normalvcenter \to \everymathematics + +%D \macros +%D {frozenhbox} +%D +%D A not so well unhboxable box can be made with: + +\unexpanded\def\frozenhbox + {\hpack\bgroup + \dowithnextboxcs\syst_boxes_frozenhbox_finish\hbox} + +\def\syst_boxes_frozenhbox_finish + {\hpack{\hpack{\box\nextbox}}% + \egroup} + +%D \macros +%D {setboxllx,setboxlly,gsetboxllx,gsetboxlly,getboxllx,getboxlly} +%D +%D A prelude to an extended \TEX\ feature: + +\installcorenamespace {box_x} +\installcorenamespace {box_y} + +\unexpanded\def\setboxllx #1#2{\expandafter\edef\csname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}} +\unexpanded\def\setboxlly #1#2{\expandafter\edef\csname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}} + +\unexpanded\def\gsetboxllx#1#2{\expandafter\xdef\csname\??box_x\number#1\endcsname{\the\dimexpr#2\relax}} +\unexpanded\def\gsetboxlly#1#2{\expandafter\xdef\csname\??box_y\number#1\endcsname{\the\dimexpr#2\relax}} + +%def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\csname\??box_x\number#1\endcsname\else\zeropoint\fi} +%def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\csname\??box_y\number#1\endcsname\else\zeropoint\fi} +\def\getboxllx#1{\ifcsname\??box_x\number#1\endcsname\lastnamedcs\else\zeropoint\fi} +\def\getboxlly#1{\ifcsname\??box_y\number#1\endcsname\lastnamedcs\else\zeropoint\fi} + +\def\directgetboxllx#1{\csname\??box_x\number#1\endcsname} % use when sure existence +\def\directgetboxlly#1{\csname\??box_y\number#1\endcsname} % use when sure existence + +%D \macros +%D {shownextbox} +%D +%D Handy for tracing +%D +%D \starttyping +%D \shownextbox\vbox{test} +%D \shownextbox\vbox{test\endgraf} +%D \shownextbox\vbox{test\endgraf\strut\endgraf} +%D \shownextbox\vbox{test\endgraf\thinrule} +%D \shownextbox\vbox{\setupwhitespace[big]test\endgraf\thinrule} +%D \stoptyping + +\unexpanded\def\shownextbox % seldom used + {\dowithnextbox + {\bgroup + \showboxbreadth\maxdimen + \showboxdepth \maxdimen + \scratchcounter\interactionmode + \batchmode + \showbox\nextbox + \box\nextbox + \interactionmode\scratchcounter + \egroup}} + +\unexpanded\def\spreadhbox#1% rebuilds \hbox{} + {\bgroup + \ifhbox#1\relax + \setbox\scratchboxtwo\emptybox + \unhbox#1% + \doloop + {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip + \setbox\scratchboxone\lastbox + \ifvoid\scratchboxone + \exitloop + \else + \setbox\scratchboxtwo\hbox + {\ifhbox\scratchboxone \spreadhbox\scratchboxone\else\box\scratchboxone\fi + \ifvoid\scratchboxtwo \else\hss\unhbox\scratchboxtwo\fi}% + \fi}% + \ifvoid\scratchboxtwo\else\unhbox\scratchboxtwo\fi + \else + \box#1% + \fi + \egroup} + +% makes sense but too much log for overfull boxes: +% +% \showboxbreadth\maxdimen +% \showboxdepth \maxdimen + +%D Moved from cont-new: +%D +%D \starttyping +%D \minimalhbox 100pt {test} +%D \stoptyping + +\unexpanded\def\minimalhbox#1#% + {\dowithnextbox + {\bgroup + \setbox\scratchbox\hpack#1{\hss}% + \ifdim\wd\nextbox<\wd\scratchbox\wd\nextbox\wd\scratchbox\fi + \box\nextbox + \egroup} + \hbox} + +%D A bit dirty: + +% \unexpanded\def\nodestostring#1% \cs {content} +% {\dowithnextbox{\edef#1{\syst_boxes_nodestostring}}\hbox} +% +% \def\syst_boxes_nodestostring +% {\clf_boxtostring\nextbox} + +\unexpanded\def\nodestostring#1#2% more tolerant for #2=\cs + {\begingroup + \setbox\nextbox\hbox{#2}% + \normalexpanded{\endgroup\edef\noexpand#1{\clf_boxtostring\nextbox}}} + +%D Even more dirty: + +\let\hyphenatedhbox\hbox + +%D We can do this: +%D +%D \starttyping +%D \setbox0\hbox to 10cm{foo} \setbox2\hbox{\unhbox0} \the\wd2 +%D \stoptyping +%D +%D But this saves a copy (and hpack pass): +%D +%D \starttyping +%D \setbox0\hbox to 10cm{foo} \the\naturalwd0 +%D \stoptyping + +\newdimen\lastnaturalboxwd +\newdimen\lastnaturalboxht +\newdimen\lastnaturalboxdp + +\let\getnaturaldimensions\clf_getnaturaldimensions % sets three dimensions +\let\naturalwd \clf_naturalwd % calculates and returns wd + +\let\getnaturalwd\clf_getnaturalwd % no intermediate +\let\setnaturalwd\clf_setnaturalwd % no intermediate + +\unexpanded\def\doifelserighttoleftinbox{\clf_doifelserighttoleftinbox} + +\let\doifrighttoleftinboxelse\doifelserighttoleftinbox + +%D New, used in high/low: + +\definesystemattribute [runningtext] [public] + +%unexpanded\def\runninghbox{\hbox attr \runningtextattribute \plusone} % not yet in i-* +\unexpanded\def\runninghbox{\hbox attr \runningtextattribute \fontid\font} % not yet in i-* + +%D To complement lua (yet undocumented): + +\unexpanded\def\beginhbox{\hbox\bgroup} \let\endhbox\egroup +\unexpanded\def\beginvbox{\vbox\bgroup} \let\endvbox\egroup +\unexpanded\def\beginvtop{\vtop\bgroup} \let\endvtop\egroup + +\unexpanded\def\sethboxregister#1{\setbox#1\hbox} +\unexpanded\def\setvboxregister#1{\setbox#1\vbox} +\unexpanded\def\setvtopregister#1{\setbox#1\vtop} + +\unexpanded\def\flushboxregister#1{\box\numexpr#1\relax} + +\unexpanded\def\starthboxregister#1{\setbox#1\hbox\bgroup} \let\stophboxregister\egroup +\unexpanded\def\startvboxregister#1{\setbox#1\vbox\bgroup} \let\stopvboxregister\egroup +\unexpanded\def\startvtopregister#1{\setbox#1\vtop\bgroup} \let\stopvtopregister\egroup + +%D For whatever third party package needs it: +%D +%D \starttyping +%D \newlocalbox\BoxOne +%D \newlocalbox\BoxTwo +%D +%D \setbox\BoxOne\hbox{Box One} +%D \setbox\BoxTwo\hbox{Box Two} +%D +%D [\box\BoxTwo] [\box\BoxOne] +%D \stoptyping + +\installcorenamespace{localbox} + +\unexpanded\def\newlocalbox#1% + {\expandafter\let\expandafter#1\csname\??localbox\string#1\endcsname + \ifx#1\relax + \syst_aux_new_localbox#1% + \fi} + +\def\syst_aux_new_localbox#1% + {\expandafter\newbox\csname\??localbox\string#1\endcsname + \newlocalbox#1} + +%D Who knows when this comes in handy: + +\unexpanded\def\lastlinewidth{\dimexpr\clf_lastlinewidth\scaledpoint\relax} + +%D Keep as reference: + +% \unexpanded\def\tightvbox{\dowithnextbox{\dp\nextbox\zeropoint\box\nextbox}\vbox} +% \unexpanded\def\tightvtop{\dowithnextbox{\ht\nextbox\zeropoint\box\nextbox}\vtop} + +%D This one keeps dimensions and sets the shift field (and so it's more for testing +%D than for real usage): + +\unexpanded\def\shiftbox{\clf_shiftbox} + +%D This one has been moved from a 2 decade old file. It makes something boxed +%D sit on the baseline. + +\unexpanded\def\linebox + {\hpack\bgroup\dowithnextbox + {\scratchdimen\dimexpr\dimexpr\htdp\nextbox-\lineheight\relax/2+\dp\strutbox\relax + \setbox\nextbox\hpack{\lower\scratchdimen\box\nextbox}% + \ht\nextbox\ht\strutbox + \dp\nextbox\dp\strutbox + \box\nextbox + \egroup} + \hbox} + +\protect \endinput + +% a bit of test code: + +% \hbox \bgroup +% \ruledvbox {\hbox{\strut gans}} +% \ruledvbox to \lineheight {\hbox{\strut gans}} +% \ruledvbox to \lineheight {\hbox {gans}} +% \ruledvbox to \strutheight{\hbox {gans}} +% \ruledvbox to \strutheight{\hbox{\strut gans}} +% \ruledvbox to \strutheight{\vss\hbox{gans}} +% \egroup + +% to be considered + +% \startluacode +% +% local spacer = lpeg.patterns.spacer +% +% function commands.withwords(command,str) +% if str then +% command = command or "ruledhbox" +% local done = false +% local function apply(s) +% if done then +% context.space() +% done = true +% else +% context.dontleavehmode() +% end +% context[command](s) +% end +% lpeg.match(lpeg.splitter(spacer,apply),str) +% end +% +% end +% +% \stopluacode +% +% \unprotect +% +% \unexpanded\def\withwordsinstring#1#2% command str +% {\ctxcommand{withwords(\!!bs#1\!!es,\!!bs#2\!!es)}} +% +% \unexpanded\def\withwordsinfile#1#2% command name +% {\ctxcommand{withwords(\!!bs#1\!!es,io.loaddata(resolvers.findfile("#2")))}} +% +% \protect +% +% \starttext +% +% \defineframed[colored][foregroundcolor=red,foregroundstyle=\bfc\underbar,location=low] +% +% \withwordsinstring{colored}{bla bla} +% \withwordsinfile{colored}{ward.tex} +% +% \stoptext diff --git a/tex/context/base/mkiv/syst-aux.mkiv b/tex/context/base/mkiv/syst-aux.mkiv index 8336800fc..f6b094246 100644 --- a/tex/context/base/mkiv/syst-aux.mkiv +++ b/tex/context/base/mkiv/syst-aux.mkiv @@ -11,11 +11,6 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -%D There are some references to \LUA\ variants here but these concern (often old) -%D experiments, moved from local test modules to here, cleaned up, but not really -%D used. After all it's not that urgent and replacing helpers is a delicate process. -%D Don't depend on it. - \registerctxluafile{syst-aux}{} % A dedicated primitive \ifvoidmacro\cs == \ifx\cs\empty is some 10% faster but @@ -76,20 +71,6 @@ \fi -% %D \macros -% %D {expunded} -% %D -% %D \unexpanded\edef\TestA{zzz} -% %D \edef\TestB{zzz} -% %D -% %D \doifelse {\TestA} {\TestB} {WRONG} {OKAY} \par -% %D \doifelse {\TestA} {\expunded\TestB} {WRONG} {OKAY} \par -% %D \doifelse {\expunded\TestA} {\TestB} {OKAY} {WRONG} \par -% %D \doifelse {\expunded\TestA} {\expunded\TestB} {OKAY} {WRONG} \par - -% %def\expunded#1{\normalexpanded\expandafter{#1}} -% \def\expunded#1{\expandafter\empty#1} % used within an edef anyway - %D As we don't have namespace definers yet, we use a special one: \ifdefined\c_syst_helpers_n_of_namespaces @@ -315,33 +296,17 @@ \expandafter\m_syst_action_nop \fi} -\startmkivmode - - \unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} ! - {\let\charactertoken=#1% = needed here - \def\m_syst_action_yes{#2}% - \def\m_syst_action_nop{#3}% - \futurelet\nexttoken\syst_helpers_inspect_next_character} +\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} ! + {\let\charactertoken=#1% = needed here + \def\m_syst_action_yes{#2}% + \def\m_syst_action_nop{#3}% + \futurelet\nexttoken\syst_helpers_inspect_next_character} - \unexpanded\def\doifelsenextcharcs#1#2#3% #1 should not be {} ! - {\let\charactertoken=#1% = needed here - \let\m_syst_action_yes#2% - \let\m_syst_action_nop#3% - \futurelet\nexttoken\syst_helpers_inspect_next_character} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} ! - {\def\m_syst_action_yes{#2}% - \def\m_syst_action_nop{#3}% - \futureexpandis#1\m_syst_action_yes\m_syst_action_nop} - - \unexpanded\def\doifelsenextcharcs % #1#2#3% #1 should not be {} ! - {\futureexpandis} - -\stoplmtxmode +\unexpanded\def\doifelsenextcharcs#1#2#3% #1 should not be {} ! + {\let\charactertoken=#1% = needed here + \let\m_syst_action_yes#2% + \let\m_syst_action_nop#3% + \futurelet\nexttoken\syst_helpers_inspect_next_character} \let\doifnextcharelse \doifelsenextchar \let\doifnextcharcselse\doifelsenextcharcs @@ -378,33 +343,17 @@ \expandafter\m_syst_action_nop \fi} -\startmkivmode - - \unexpanded\def\doifelsenextoptional#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \unexpanded\def\doifelsenextoptionalcs#1#2% \cs \cs (upto 10% faster) - {\let\m_syst_action_yes#1% - \let\m_syst_action_nop#2% - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsenextoptional#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis[\m_syst_action_yes\m_syst_action_nop} - - \unexpanded\def\doifelsenextoptionalcs - {\futureexpandis[} +\unexpanded\def\doifelsenextoptional#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} -\stoplmtxmode +\unexpanded\def\doifelsenextoptionalcs#1#2% \cs \cs (upto 10% faster) + {\let\m_syst_action_yes#1% + \let\m_syst_action_nop#2% + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} \let\doifnextoptionalelse \doifelsenextoptional \let\doifnextoptionalcselse\doifelsenextoptionalcs @@ -437,33 +386,17 @@ \expandafter\m_syst_action_nop \fi} -\startmkivmode - - \unexpanded\def\doifelsenextbgroup#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} - - \unexpanded\def\doifelsenextbgroupcs#1#2% - {\let\m_syst_action_yes#1% - \let\m_syst_action_nop#2% - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsenextbgroup#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop} - - \unexpanded\def\doifelsenextbgroupcs % #1#2 - {\futureexpandis\bgroup} +\unexpanded\def\doifelsenextbgroup#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} -\stoplmtxmode +\unexpanded\def\doifelsenextbgroupcs#1#2% + {\let\m_syst_action_yes#1% + \let\m_syst_action_nop#2% + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} \let\doifnextbgroupelse \doifelsenextbgroup \let\doifnextbgroupcselse\doifelsenextbgroupcs @@ -484,24 +417,11 @@ \expandafter\m_syst_action_nop \fi} -\startmkivmode - - \unexpanded\def\doifelsenextparenthesis#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsenextparenthesis#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis(\m_syst_action_yes\m_syst_action_nop} - -\stoplmtxmode +\unexpanded\def\doifelsenextparenthesis#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character} \let\doifnextparenthesiselse\doifelsenextparenthesis @@ -514,31 +434,15 @@ \expandafter\m_syst_action_nop \fi} -\startmkivmode - - \unexpanded\def\doifelsefastoptionalcheck#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else} - - \unexpanded\def\doifelsefastoptionalcheckcs#1#2% \cs \cs - {\let\m_syst_action_yes#1% - \let\m_syst_action_nop#2% - \futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsefastoptionalcheck#1#2% - {\def\m_syst_action_yes{#1}% - \def\m_syst_action_nop{#2}% - \futureexpandis[\m_syst_action_yes\m_syst_action_nop} - - \unexpanded\def\doifelsefastoptionalcheckcs - {\futureexpandis[} +\unexpanded\def\doifelsefastoptionalcheck#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else} -\stoplmtxmode +\unexpanded\def\doifelsefastoptionalcheckcs#1#2% \cs \cs + {\let\m_syst_action_yes#1% + \let\m_syst_action_nop#2% + \futurelet\nexttoken\syst_helpers_do_if_fast_optional_check_else} \let\doiffastoptionalcheckelse \doifelsefastoptionalcheck \let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs @@ -816,61 +720,32 @@ %D \doifelse {string1} {string2} {then ...}{else ...} %D \stoptyping -\startmkivmode - - \unexpanded\def\doif#1#2% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \unexpanded\def\doifnot#1#2% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - \unexpanded\def\doifelse#1#2% - {\edef\m_syst_string_one{#1}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelse#1#2% - {\iftok{#1}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - - \unexpanded\def\doif#1#2% - {\iftok{#1}{#2}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} +\unexpanded\def\doif#1#2% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} - \unexpanded\def\doifnot#1#2% - {\iftok{#1}{#2}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\unexpanded\def\doifnot#1#2% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} -\stoplmtxmode +\unexpanded\def\doifelse#1#2% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} %D \macros %D {doifempty,doifemptyelse,doifnotempty} @@ -1648,55 +1523,26 @@ %D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and \type %D {\the\count...}. This macro is a rather dirty one. -\startmkivmode - - \def\doifelsenumber#1% does not accept counters (fully expandable) - {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - - \def\doifnumber#1% - {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \def\doifnotnumber#1% - {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - -\stopmkivmode - -\startlmtxmode - - \def\doifelsenumber#1% - {\ifchknum#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - - \def\doifnumber#1% - {\ifchknum#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\gobbleoneargument - \fi} +\def\doifelsenumber#1% does not accept counters (fully expandable) + {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} - \def\doifnotnumber#1% - {\ifchknum#1\or - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\def\doifnumber#1% + {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} -\stoplmtxmode +\def\doifnotnumber#1% + {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} \let\doifnumberelse\doifelsenumber @@ -2494,22 +2340,18 @@ % % But we use this as it keeps the original name visible: -\startmkivmode - - \def\syst_helpers_empty_spaced_six {\the\t_syst_aux[][][][][][] } - \def\syst_helpers_empty_normal_six {\the\t_syst_aux[][][][][][]} - \def\syst_helpers_empty_spaced_five {\the\t_syst_aux[][][][][] } - \def\syst_helpers_empty_normal_five {\the\t_syst_aux[][][][][]} - \def\syst_helpers_empty_spaced_four {\the\t_syst_aux[][][][] } - \def\syst_helpers_empty_normal_four {\the\t_syst_aux[][][][]} - \def\syst_helpers_empty_spaced_three{\the\t_syst_aux[][][] } - \def\syst_helpers_empty_normal_three{\the\t_syst_aux[][][]} - \def\syst_helpers_empty_spaced_two {\the\t_syst_aux[][] } - \def\syst_helpers_empty_normal_two {\the\t_syst_aux[][]} - \def\syst_helpers_empty_spaced_one {\the\t_syst_aux[] } - \def\syst_helpers_empty_normal_one {\the\t_syst_aux[]} - -\stopmkivmode +\def\syst_helpers_empty_spaced_six {\the\t_syst_aux[][][][][][] } +\def\syst_helpers_empty_normal_six {\the\t_syst_aux[][][][][][]} +\def\syst_helpers_empty_spaced_five {\the\t_syst_aux[][][][][] } +\def\syst_helpers_empty_normal_five {\the\t_syst_aux[][][][][]} +\def\syst_helpers_empty_spaced_four {\the\t_syst_aux[][][][] } +\def\syst_helpers_empty_normal_four {\the\t_syst_aux[][][][]} +\def\syst_helpers_empty_spaced_three{\the\t_syst_aux[][][] } +\def\syst_helpers_empty_normal_three{\the\t_syst_aux[][][]} +\def\syst_helpers_empty_spaced_two {\the\t_syst_aux[][] } +\def\syst_helpers_empty_normal_two {\the\t_syst_aux[][]} +\def\syst_helpers_empty_spaced_one {\the\t_syst_aux[] } +\def\syst_helpers_empty_normal_one {\the\t_syst_aux[]} \def\syst_helpers_single_empty_one_yes {\firstargumenttrue \the\t_syst_aux} \def\syst_helpers_double_empty_two_yes {\secondargumenttrue \the\t_syst_aux} @@ -2531,34 +2373,17 @@ % {\firstargumentfalse % #1[]} -\startmkivmode +\unexpanded\def\dosingleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_single_empty_one_yes + \let\m_syst_action_nop\syst_helpers_single_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - \unexpanded\def\dosingleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_single_empty_one_yes - \let\m_syst_action_nop\syst_helpers_single_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_single_empty_one_nop - {\firstargumentfalse - \the\t_syst_aux[]} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\dosingleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop} - - \def\syst_helpers_single_empty_one_nop - {\firstargumentfalse - \the\t_syst_aux[]} - -\stoplmtxmode +\def\syst_helpers_single_empty_one_nop + {\firstargumentfalse + \the\t_syst_aux[]} %D Double @@ -2590,61 +2415,34 @@ % \def\syst_helpers_double_empty_one_spaced#1#2{#1[{#2}][] } % \def\syst_helpers_double_empty_one_normal#1#2{#1[{#2}][]} -\startmkivmode - - \unexpanded\def\dodoubleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_double_empty_one_yes - \let\m_syst_action_nop\syst_helpers_double_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_double_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_double_empty_two_yes - \let\m_syst_action_nop\syst_helpers_double_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_double_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_double_empty_two_nop - {\secondargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\dodoubleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop} - - \def\syst_helpers_double_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop} - - \def\syst_helpers_double_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_double_empty_two_nop - {\secondargumentfalse - \the\t_syst_aux[]} - -\stoplmtxmode +\unexpanded\def\dodoubleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_double_empty_one_yes + \let\m_syst_action_nop\syst_helpers_double_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_double_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_double_empty_two_yes + \let\m_syst_action_nop\syst_helpers_double_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_double_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_double_empty_two_nop + {\secondargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} % Triple @@ -2694,90 +2492,52 @@ % \def\syst_helpers_triple_empty_three_spaced#1#2#3{#1[{#2}][{#3}][] } % \def\syst_helpers_triple_empty_three_normal#1#2#3{#1[{#2}][{#3}][]} -\startmkivmode - - \unexpanded\def\dotripleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_triple_empty_one_yes - \let\m_syst_action_nop\syst_helpers_triple_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_triple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_triple_empty_two_yes - \let\m_syst_action_nop\syst_helpers_triple_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_triple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_triple_empty_three_yes - \let\m_syst_action_nop\syst_helpers_triple_empty_three_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_triple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_triple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_two - \else - \expandafter\syst_helpers_empty_normal_two - \fi} - - \def\syst_helpers_triple_empty_three_nop - {\thirdargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\dotripleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop} - - \def\syst_helpers_triple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop} - - \def\syst_helpers_triple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop} - - \def\syst_helpers_triple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_triple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_triple_empty_three_nop - {\thirdargumentfalse - \the\t_syst_aux[]} +\unexpanded\def\dotripleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_triple_empty_one_yes + \let\m_syst_action_nop\syst_helpers_triple_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_triple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_triple_empty_two_yes + \let\m_syst_action_nop\syst_helpers_triple_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_triple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_triple_empty_three_yes + \let\m_syst_action_nop\syst_helpers_triple_empty_three_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_triple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_triple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_two + \else + \expandafter\syst_helpers_empty_normal_two + \fi} -\stoplmtxmode +\def\syst_helpers_triple_empty_three_nop + {\thirdargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} %D Quadruple: @@ -2846,121 +2606,71 @@ % \def\syst_helpers_quadruple_empty_four_spaced #1#2#3#4{#1[{#2}][{#3}][{#4}][] } % \def\syst_helpers_quadruple_empty_four_normal #1#2#3#4{#1[{#2}][{#3}][{#4}][]} -\startmkivmode - - \unexpanded\def\doquadrupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_quadruple_empty_one_yes - \let\m_syst_action_nop\syst_helpers_quadruple_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quadruple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quadruple_empty_two_yes - \let\m_syst_action_nop\syst_helpers_quadruple_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quadruple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quadruple_empty_three_yes - \let\m_syst_action_nop\syst_helpers_quadruple_empty_three_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quadruple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quadruple_empty_four_yes - \let\m_syst_action_nop\syst_helpers_quadruple_empty_four_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quadruple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][][][]} - - \def\syst_helpers_quadruple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_three - \else - \expandafter\syst_helpers_empty_normal_three - \fi} - - \def\syst_helpers_quadruple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_two - \else - \expandafter\syst_helpers_empty_normal_two - \fi} - - \def\syst_helpers_quadruple_empty_four_nop - {\fourthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doquadrupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop} - - \def\syst_helpers_quadruple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop} - - \def\syst_helpers_quadruple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop} - - \def\syst_helpers_quadruple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop} - - \def\syst_helpers_quadruple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][][][]} - - \def\syst_helpers_quadruple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_quadruple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux[][]} +\unexpanded\def\doquadrupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_quadruple_empty_one_yes + \let\m_syst_action_nop\syst_helpers_quadruple_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quadruple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quadruple_empty_two_yes + \let\m_syst_action_nop\syst_helpers_quadruple_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quadruple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quadruple_empty_three_yes + \let\m_syst_action_nop\syst_helpers_quadruple_empty_three_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quadruple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quadruple_empty_four_yes + \let\m_syst_action_nop\syst_helpers_quadruple_empty_four_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quadruple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux[][][][]} + +\def\syst_helpers_quadruple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_three + \else + \expandafter\syst_helpers_empty_normal_three + \fi} - \def\syst_helpers_quadruple_empty_four_nop - {\fourthargumentfalse - \the\t_syst_aux[]} +\def\syst_helpers_quadruple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_two + \else + \expandafter\syst_helpers_empty_normal_two + \fi} -\stoplmtxmode +\def\syst_helpers_quadruple_empty_four_nop + {\fourthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} %D Quintuple: @@ -3049,154 +2759,91 @@ % \def\syst_helpers_quintuple_empty_five_spaced #1#2#3#4#5{#1[{#2}][{#3}][{#4}][{#5}][] } % \def\syst_helpers_quintuple_empty_five_normal #1#2#3#4#5{#1[{#2}][{#3}][{#4}][{#5}][]} -\startmkivmode - - \unexpanded\def\doquintupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_quintuple_empty_one_yes - \let\m_syst_action_nop\syst_helpers_quintuple_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quintuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quintuple_empty_two_yes - \let\m_syst_action_nop\syst_helpers_quintuple_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quintuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quintuple_empty_three_yes - \let\m_syst_action_nop\syst_helpers_quintuple_empty_three_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quintuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quintuple_empty_four_yes - \let\m_syst_action_nop\syst_helpers_quintuple_empty_four_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quintuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_quintuple_empty_five_yes - \let\m_syst_action_nop\syst_helpers_quintuple_empty_five_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_quintuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][][][]} - - \def\syst_helpers_quintuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_four - \else - \expandafter\syst_helpers_empty_normal_four - \fi} - - \def\syst_helpers_quintuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_three - \else - \expandafter\syst_helpers_empty_normal_three - \fi} +\unexpanded\def\doquintupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_quintuple_empty_one_yes + \let\m_syst_action_nop\syst_helpers_quintuple_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quintuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quintuple_empty_two_yes + \let\m_syst_action_nop\syst_helpers_quintuple_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quintuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quintuple_empty_three_yes + \let\m_syst_action_nop\syst_helpers_quintuple_empty_three_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quintuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quintuple_empty_four_yes + \let\m_syst_action_nop\syst_helpers_quintuple_empty_four_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quintuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_quintuple_empty_five_yes + \let\m_syst_action_nop\syst_helpers_quintuple_empty_five_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_quintuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux[][][][][]} + +\def\syst_helpers_quintuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_four + \else + \expandafter\syst_helpers_empty_normal_four + \fi} - \def\syst_helpers_quintuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_two - \else - \expandafter\syst_helpers_empty_normal_two - \fi} +\def\syst_helpers_quintuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_three + \else + \expandafter\syst_helpers_empty_normal_three + \fi} - \def\syst_helpers_quintuple_empty_five_nop - {\fifthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} +\def\syst_helpers_quintuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_two + \else + \expandafter\syst_helpers_empty_normal_two + \fi} -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doquintupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop} - - \def\syst_helpers_quintuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop} - - \def\syst_helpers_quintuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop} - - \def\syst_helpers_quintuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop} - - \def\syst_helpers_quintuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop} - - \def\syst_helpers_quintuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][][][]} - - \def\syst_helpers_quintuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][][]} - - \def\syst_helpers_quintuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_quintuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_quintuple_empty_five_nop - {\fifthargumentfalse - \the\t_syst_aux[]} - -\stoplmtxmode +\def\syst_helpers_quintuple_empty_five_nop + {\fifthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} %D Sixtuple: @@ -3306,189 +2953,112 @@ % \def\syst_helpers_sixtuple_empty_six_spaced #1#2#3#4#5#6{#1[{#2}][{#3}][{#4}][{#5}][{#6}][] } % \def\syst_helpers_sixtuple_empty_six_normal #1#2#3#4#5#6{#1[{#2}][{#3}][{#4}][{#5}][{#6}][]} -\startmkivmode - - \unexpanded\def\dosixtupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_one_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_two_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_three_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_three_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_four_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_four_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_five_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_five_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_sixtuple_empty_six_yes - \let\m_syst_action_nop\syst_helpers_sixtuple_empty_six_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_sixtuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][][][]} - - \def\syst_helpers_sixtuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_five - \else - \expandafter\syst_helpers_empty_normal_five - \fi} - - \def\syst_helpers_sixtuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_four - \else - \expandafter\syst_helpers_empty_normal_four - \fi} +\unexpanded\def\dosixtupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_one_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_two_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_three_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_three_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_four_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_four_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_five_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_five_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_five_yes[#1]% + {\fifthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_sixtuple_empty_six_yes + \let\m_syst_action_nop\syst_helpers_sixtuple_empty_six_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_sixtuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][][][][][]} + +\def\syst_helpers_sixtuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_five + \else + \expandafter\syst_helpers_empty_normal_five + \fi} - \def\syst_helpers_sixtuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_three - \else - \expandafter\syst_helpers_empty_normal_three - \fi} +\def\syst_helpers_sixtuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_four + \else + \expandafter\syst_helpers_empty_normal_four + \fi} - \def\syst_helpers_sixtuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_two - \else - \expandafter\syst_helpers_empty_normal_two - \fi} +\def\syst_helpers_sixtuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_three + \else + \expandafter\syst_helpers_empty_normal_three + \fi} - \def\syst_helpers_sixtuple_empty_six_nop - {\sixthargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} +\def\syst_helpers_sixtuple_empty_five_nop + {\fifthargumentfalse + \sixthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_two + \else + \expandafter\syst_helpers_empty_normal_two + \fi} -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\dosixtupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop} - - \def\syst_helpers_sixtuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop} - - \def\syst_helpers_sixtuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop} - - \def\syst_helpers_sixtuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop} - - \def\syst_helpers_sixtuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop} - - \def\syst_helpers_sixtuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop} - - \def\syst_helpers_sixtuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][][][]} - - \def\syst_helpers_sixtuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][][]} - - \def\syst_helpers_sixtuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][][]} - - \def\syst_helpers_sixtuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_sixtuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_sixtuple_empty_six_nop - {\sixthargumentfalse - \the\t_syst_aux[]} - -\stoplmtxmode +\def\syst_helpers_sixtuple_empty_six_nop + {\sixthargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} %D Seventuple: @@ -3620,226 +3190,134 @@ % \def\syst_helpers_seventuple_empty_seven_spaced#1#2#3#4#5#6#7{#1[{#2}][{#3}][{#4}][{#5}][{#6}][{#7}][] } % \def\syst_helpers_seventuple_empty_seven_normal#1#2#3#4#5#6#7{#1[{#2}][{#3}][{#4}][{#5}][{#6}][{#7}][]} -\startmkivmode - - \unexpanded\def\doseventupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_one_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_one_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_two_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_two_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_three_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_three_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_four_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_four_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_five_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_five_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_six_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_six_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_six_yes[#1]% - {\sixthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \let\m_syst_action_yes\syst_helpers_seventuple_empty_seven_yes - \let\m_syst_action_nop\syst_helpers_seventuple_empty_seven_nop - \let\if_next_blank_space_token\iffalse - \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} - - \def\syst_helpers_seventuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][][][]} - - \def\syst_helpers_seventuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_six - \else - \expandafter\syst_helpers_empty_normal_six - \fi} - - \def\syst_helpers_seventuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_five - \else - \expandafter\syst_helpers_empty_normal_five - \fi} +\unexpanded\def\doseventupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_one_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_one_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_two_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_two_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_three_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_three_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_four_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_four_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_five_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_five_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_five_yes[#1]% + {\fifthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_six_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_six_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_six_yes[#1]% + {\sixthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \let\m_syst_action_yes\syst_helpers_seventuple_empty_seven_yes + \let\m_syst_action_nop\syst_helpers_seventuple_empty_seven_nop + \let\if_next_blank_space_token\iffalse + \futurelet\nexttoken\syst_helpers_inspect_next_optional_character} + +\def\syst_helpers_seventuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][][][][][]} + +\def\syst_helpers_seventuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_six + \else + \expandafter\syst_helpers_empty_normal_six + \fi} - \def\syst_helpers_seventuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_four - \else - \expandafter\syst_helpers_empty_normal_four - \fi} +\def\syst_helpers_seventuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_five + \else + \expandafter\syst_helpers_empty_normal_five + \fi} - \def\syst_helpers_seventuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_three - \else - \expandafter\syst_helpers_empty_normal_three - \fi} +\def\syst_helpers_seventuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_four + \else + \expandafter\syst_helpers_empty_normal_four + \fi} - \def\syst_helpers_seventuple_empty_six_nop - {\sixthargumentfalse - \seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_two - \else - \expandafter\syst_helpers_empty_normal_two - \fi} +\def\syst_helpers_seventuple_empty_five_nop + {\fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_three + \else + \expandafter\syst_helpers_empty_normal_three + \fi} - \def\syst_helpers_seventuple_empty_seven_nop - {\seventhargumentfalse - \if_next_blank_space_token - \expandafter\syst_helpers_empty_spaced_one - \else - \expandafter\syst_helpers_empty_normal_one - \fi} +\def\syst_helpers_seventuple_empty_six_nop + {\sixthargumentfalse + \seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_two + \else + \expandafter\syst_helpers_empty_normal_two + \fi} -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doseventupleempty#1% - {%syst_helpers_argument_reset - \t_syst_aux{#1}% - \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop} - - \def\syst_helpers_seventuple_empty_one_yes[#1]% - {\firstargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop} - - \def\syst_helpers_seventuple_empty_two_yes[#1]% - {\secondargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop} - - \def\syst_helpers_seventuple_empty_three_yes[#1]% - {\thirdargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop} - - \def\syst_helpers_seventuple_empty_four_yes[#1]% - {\fourthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop} - - \def\syst_helpers_seventuple_empty_five_yes[#1]% - {\fifthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop} - - \def\syst_helpers_seventuple_empty_six_yes[#1]% - {\sixthargumenttrue - \toksapp\t_syst_aux{[{#1}]}% - \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop} - - \def\syst_helpers_seventuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][][][]} - - \def\syst_helpers_seventuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][][]} - - \def\syst_helpers_seventuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][][]} - - \def\syst_helpers_seventuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][][]} - - \def\syst_helpers_seventuple_empty_five_nop - {\fifthargumentfalse - \sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][][]} - - \def\syst_helpers_seventuple_empty_six_nop - {\sixthargumentfalse - \seventhargumentfalse - \the\t_syst_aux[][]} - - \def\syst_helpers_seventuple_empty_seven_nop - {\seventhargumentfalse - \the\t_syst_aux[]} - -\stoplmtxmode +\def\syst_helpers_seventuple_empty_seven_nop + {\seventhargumentfalse + \if_next_blank_space_token + \expandafter\syst_helpers_empty_spaced_one + \else + \expandafter\syst_helpers_empty_normal_one + \fi} %D Aliases: @@ -3984,252 +3462,94 @@ %D \type {conditional} token. Okay, these macros are not called that often but it %D saves crap when tracing. -\startmkivmode - - \unexpanded\def\syst_helpers_get_grouped_argument#1#2% - {\let\syst_helpers_get_grouped_argument_yes#1% - \let\syst_helpers_get_grouped_argument_nop#2% - \futurelet\nextargument\syst_helpers_get_grouped_argument_indeed} +\unexpanded\def\syst_helpers_get_grouped_argument#1#2% + {\let\syst_helpers_get_grouped_argument_yes#1% + \let\syst_helpers_get_grouped_argument_nop#2% + \futurelet\nextargument\syst_helpers_get_grouped_argument_indeed} - \def\syst_helpers_get_grouped_argument_indeed - {\ifx\nextargument\bgroup - \expandafter\syst_helpers_get_grouped_argument_a - \else - \expandafter\syst_helpers_get_grouped_argument_b - \fi} +\def\syst_helpers_get_grouped_argument_indeed + {\ifx\nextargument\bgroup + \expandafter\syst_helpers_get_grouped_argument_a + \else + \expandafter\syst_helpers_get_grouped_argument_b + \fi} - \def\syst_helpers_get_grouped_argument_a - {%syst_helpers_argument_reset - \syst_helpers_get_grouped_argument_yes\syst_helpers_get_grouped_argument_nested} +\def\syst_helpers_get_grouped_argument_a + {%syst_helpers_argument_reset + \syst_helpers_get_grouped_argument_yes\syst_helpers_get_grouped_argument_nested} - \def\syst_helpers_get_grouped_argument_b - {\ifconditional\c_syst_helpers_permit_spaces_between_groups - \expandafter\syst_helpers_get_grouped_argument_f - \else - \expandafter\syst_helpers_get_grouped_argument_d - \fi} +\def\syst_helpers_get_grouped_argument_b + {\ifconditional\c_syst_helpers_permit_spaces_between_groups + \expandafter\syst_helpers_get_grouped_argument_f + \else + \expandafter\syst_helpers_get_grouped_argument_d + \fi} - \def\syst_helpers_get_grouped_argument_d - {%syst_helpers_argument_error - \syst_helpers_get_grouped_argument_nop\syst_helpers_get_grouped_argument_nested{}} +\def\syst_helpers_get_grouped_argument_d + {%syst_helpers_argument_error + \syst_helpers_get_grouped_argument_nop\syst_helpers_get_grouped_argument_nested{}} - \begingroup - \def\\ {\syst_helpers_get_grouped_argument\syst_helpers_get_grouped_argument_yes\syst_helpers_get_grouped_argument_nop} - \glet\syst_helpers_get_grouped_argument_e\\ - \endgroup +\begingroup + \def\\ {\syst_helpers_get_grouped_argument\syst_helpers_get_grouped_argument_yes\syst_helpers_get_grouped_argument_nop} + \glet\syst_helpers_get_grouped_argument_e\\ +\endgroup - \def\syst_helpers_get_grouped_argument_f - {\ifx\nextargument\blankspace - \expandafter\syst_helpers_get_grouped_argument_e % g - \else - \expandafter\syst_helpers_get_grouped_argument_d % h - \fi} +\def\syst_helpers_get_grouped_argument_f + {\ifx\nextargument\blankspace + \expandafter\syst_helpers_get_grouped_argument_e % g + \else + \expandafter\syst_helpers_get_grouped_argument_d % h + \fi} - \unexpanded\def\dosinglegroupempty#1% - {\def\syst_helpers_get_grouped_argument_nested - {\dontpermitspacesbetweengroups - #1}% - \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} - - \unexpanded\def\dodoublegroupempty#1% - {\def\syst_helpers_get_grouped_argument_nested##1% - {\def\syst_helpers_get_grouped_argument_nested - {\dontpermitspacesbetweengroups - #1{##1}}% - \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% - \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} - - \unexpanded\def\dotriplegroupempty#1% - {\def\syst_helpers_get_grouped_argument_nested##1% - {\def\syst_helpers_get_grouped_argument_nested####1% - {\def\syst_helpers_get_grouped_argument_nested - {\dontpermitspacesbetweengroups - #1{##1}{####1}}% - \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% - \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% - \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} - - \unexpanded\def\doquadruplegroupempty#1% - {\def\syst_helpers_get_grouped_argument_nested##1% - {\def\syst_helpers_get_grouped_argument_nested####1% - {\def\syst_helpers_get_grouped_argument_nested########1% - {\def\syst_helpers_get_grouped_argument_nested - {\dontpermitspacesbetweengroups - #1{##1}{####1}{########1}}% - \syst_helpers_get_grouped_argument\fourthargumenttrue\fourthargumentfalse}% - \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% - \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% - \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} - - \unexpanded\def\doquintuplegroupempty#1% - {\def\syst_helpers_get_grouped_argument_nested##1% - {\def\syst_helpers_get_grouped_argument_nested####1% - {\def\syst_helpers_get_grouped_argument_nested########1% - {\def\syst_helpers_get_grouped_argument_nested################1% - {\def\syst_helpers_get_grouped_argument_nested - {\dontpermitspacesbetweengroups - #1{##1}{####1}{########1}{################1}}% - \syst_helpers_get_grouped_argument\fifthargumenttrue\fifthargumentfalse}% - \syst_helpers_get_grouped_argument\fourthargumenttrue\fourthargumentfalse}% - \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% - \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% - \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\dosinglegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop} - - \def\syst_helpers_single_group_empty_one_nop - {\firstargumentfalse - \the\t_syst_aux{}} - - \unexpanded\def\dodoublegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop} - - \def\syst_helpers_group_double_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop} - - \def\syst_helpers_group_double_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \the\t_syst_aux{}{}} - - \def\syst_helpers_group_double_empty_two_nop - {\secondargumentfalse - \the\t_syst_aux{}} - - \unexpanded\def\dotriplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop} - - \def\syst_helpers_group_triple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop} - - \def\syst_helpers_group_triple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop} - - \def\syst_helpers_group_triple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux{}{}{}} - - \def\syst_helpers_group_triple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \the\t_syst_aux{}{}} - - \def\syst_helpers_group_triple_empty_three_nop - {\thirdargumentfalse - \the\t_syst_aux{}} - - \unexpanded\def\doquadruplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop} - - \def\syst_helpers_group_quadruple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop} - - \def\syst_helpers_group_quadruple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop} - - \def\syst_helpers_group_quadruple_empty_three_yes#1% - {\thirdargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop} - - \def\syst_helpers_group_quadruple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}{}{}} - - \def\syst_helpers_group_quadruple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}{}} - - \def\syst_helpers_group_quadruple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \the\t_syst_aux{}{}} - - \def\syst_helpers_group_quadruple_empty_four_nop - {\fourthargumentfalse - \the\t_syst_aux{}} - - \unexpanded\def\doquintuplegroupempty#1% - {\t_syst_aux{#1}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop} - - \def\syst_helpers_group_quintuple_empty_one_yes#1% - {\firstargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop} - - \def\syst_helpers_group_quintuple_empty_two_yes#1% - {\secondargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop} - - \def\syst_helpers_group_quintuple_empty_three_yes#1% - {\thirdargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop} - - \def\syst_helpers_group_quintuple_empty_four_yes#1% - {\fourthargumenttrue - \toksapp\t_syst_aux{{#1}}% - \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop} - - \def\syst_helpers_group_quintuple_empty_one_nop - {\firstargumentfalse - \secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}{}{}} - - \def\syst_helpers_group_quintuple_empty_two_nop - {\secondargumentfalse - \thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}{}} - - \def\syst_helpers_group_quintuple_empty_three_nop - {\thirdargumentfalse - \fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}{}} - - \def\syst_helpers_group_quintuple_empty_four_nop - {\fourthargumentfalse - \fifthargumentfalse - \the\t_syst_aux{}{}} - - \def\syst_helpers_group_quintuple_empty_five_nop - {\fifthargumentfalse - \the\t_syst_aux{}} - -\stoplmtxmode +\unexpanded\def\dosinglegroupempty#1% + {\def\syst_helpers_get_grouped_argument_nested + {\dontpermitspacesbetweengroups + #1}% + \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} + +\unexpanded\def\dodoublegroupempty#1% + {\def\syst_helpers_get_grouped_argument_nested##1% + {\def\syst_helpers_get_grouped_argument_nested + {\dontpermitspacesbetweengroups + #1{##1}}% + \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% + \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} + +\unexpanded\def\dotriplegroupempty#1% + {\def\syst_helpers_get_grouped_argument_nested##1% + {\def\syst_helpers_get_grouped_argument_nested####1% + {\def\syst_helpers_get_grouped_argument_nested + {\dontpermitspacesbetweengroups + #1{##1}{####1}}% + \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% + \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% + \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} + +\unexpanded\def\doquadruplegroupempty#1% + {\def\syst_helpers_get_grouped_argument_nested##1% + {\def\syst_helpers_get_grouped_argument_nested####1% + {\def\syst_helpers_get_grouped_argument_nested########1% + {\def\syst_helpers_get_grouped_argument_nested + {\dontpermitspacesbetweengroups + #1{##1}{####1}{########1}}% + \syst_helpers_get_grouped_argument\fourthargumenttrue\fourthargumentfalse}% + \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% + \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% + \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} + +\unexpanded\def\doquintuplegroupempty#1% + {\def\syst_helpers_get_grouped_argument_nested##1% + {\def\syst_helpers_get_grouped_argument_nested####1% + {\def\syst_helpers_get_grouped_argument_nested########1% + {\def\syst_helpers_get_grouped_argument_nested################1% + {\def\syst_helpers_get_grouped_argument_nested + {\dontpermitspacesbetweengroups + #1{##1}{####1}{########1}{################1}}% + \syst_helpers_get_grouped_argument\fifthargumenttrue\fifthargumentfalse}% + \syst_helpers_get_grouped_argument\fourthargumenttrue\fourthargumentfalse}% + \syst_helpers_get_grouped_argument\thirdargumenttrue\thirdargumentfalse}% + \syst_helpers_get_grouped_argument\secondargumenttrue\secondargumentfalse}% + \syst_helpers_get_grouped_argument\firstargumenttrue\firstargumentfalse} %D These macros can explictly take care of spaces, which means that the next %D definition and calls are valid: @@ -5918,71 +5238,34 @@ % \unexpanded\def\pickupgroupedcommand#1#2#3% % {\doifelsenextbgroup{\syst_helpers_handle_group_pickup{#1}{#2}{#3}}{\syst_helpers_handle_group_nop{#1}{#2}}} -\startmkivmode - - \unexpanded\def\groupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \doifelsenextbgroupcs\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - - \unexpanded\def\groupedcommandcs#1#2% - {\let\m_syst_helpers_handle_group_b#1% - \let\m_syst_helpers_handle_group_a#2% - \doifelsenextbgroupcs\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - - \unexpanded\def\simplegroupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \doifelsenextbgroupcs\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop} - - \unexpanded\def\pickupgroupedcommand#1#2#3% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \def\m_syst_helpers_handle_group_p{#2}% - \doifelsenextbgroupcs\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop} - - \unexpanded\def\triggergroupedcommand#1% - {\def\m_syst_helpers_handle_group_b{#1}% - \doifelsenextbgroupcs\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} +\unexpanded\def\groupedcommand#1#2% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \doifelsenextbgroupcs\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - \unexpanded\def\triggergroupedcommandcs#1% - {\let\m_syst_helpers_handle_group_b#1% - \doifelsenextbgroupcs\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} +\unexpanded\def\groupedcommandcs#1#2% + {\let\m_syst_helpers_handle_group_b#1% + \let\m_syst_helpers_handle_group_a#2% + \doifelsenextbgroupcs\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} -\stopmkivmode +\unexpanded\def\simplegroupedcommand#1#2% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \doifelsenextbgroupcs\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop} -\startlmtxmode +\unexpanded\def\pickupgroupedcommand#1#2#3% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \def\m_syst_helpers_handle_group_p{#2}% + \doifelsenextbgroupcs\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop} - \unexpanded\def\groupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} +\unexpanded\def\triggergroupedcommand#1% + {\def\m_syst_helpers_handle_group_b{#1}% + \doifelsenextbgroupcs\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} - \unexpanded\def\groupedcommandcs#1#2% - {\let\m_syst_helpers_handle_group_b#1% - \let\m_syst_helpers_handle_group_a#2% - \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} - - \unexpanded\def\simplegroupedcommand#1#2% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop} - - \unexpanded\def\pickupgroupedcommand#1#2#3% - {\def\m_syst_helpers_handle_group_b{#1}% - \def\m_syst_helpers_handle_group_a{#2}% - \def\m_syst_helpers_handle_group_p{#2}% - \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop} - - \unexpanded\def\triggergroupedcommand#1% - {\def\m_syst_helpers_handle_group_b{#1}% - \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} - - \unexpanded\def\triggergroupedcommandcs#1% - {\let\m_syst_helpers_handle_group_b#1% - \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} - -\stoplmtxmode +\unexpanded\def\triggergroupedcommandcs#1% + {\let\m_syst_helpers_handle_group_b#1% + \doifelsenextbgroupcs\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} %D Users should be aware of the fact that grouping can interfere with ones paragraph %D settings that are executed after the paragraph is closed. One should therefore @@ -7032,166 +6315,88 @@ %D three tokens per call. Anyone familiar with the not||values ones, can derive %D their meaning from the definitions. -\startmkivmode - - \unexpanded\def\doifvalue#1#2% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \unexpanded\def\doifnotvalue#1#2% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - \unexpanded\def\doifelsevalue#1#2% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \edef\m_syst_string_two{#2}% - \ifx\m_syst_string_one\m_syst_string_two - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - - \unexpanded\def\doifnothing#1% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \unexpanded\def\doifsomething#1% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - \unexpanded\def\doifelsenothing#1% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - - \unexpanded\def\doifelsesomething#1% - {\edef\m_syst_string_one{#1}% - \ifx\m_syst_string_one\empty - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - - \unexpanded\def\doifvaluenothing#1% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \ifx\m_syst_string_one\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \unexpanded\def\doifvaluesomething#1% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \ifx\m_syst_string_one\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - \unexpanded\def\doifelsevaluenothing#1% - {\edef\m_syst_string_one{\csname#1\endcsname}% - \ifx\m_syst_string_one\empty - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifvalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - - \unexpanded\def\doifnotvalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\unexpanded\def\doifvalue#1#2% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} - \unexpanded\def\doifelsevalue#1#2% - {\iftok{\csname#1\endcsname}{#2}% - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} +\unexpanded\def\doifnotvalue#1#2% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} - \unexpanded\def\doifnothing#1% - {\iftok{#1}\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} +\unexpanded\def\doifelsevalue#1#2% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} - \unexpanded\def\doifsomething#1% - {\iftok{#1}\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\unexpanded\def\doifnothing#1% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} - \unexpanded\def\doifelsenothing#1% - {\iftok{#1}\emptytoks - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} +\unexpanded\def\doifsomething#1% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} - \unexpanded\def\doifelsesomething#1% - {\iftok{#1}\emptytoks - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} +\unexpanded\def\doifelsenothing#1% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} - \unexpanded\def\doifvaluenothing#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} +\unexpanded\def\doifelsesomething#1% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} - \unexpanded\def\doifvaluesomething#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\unexpanded\def\doifvaluenothing#1% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} - \unexpanded\def\doifelsevaluenothing#1% - {\iftok{\csname#1\endcsname}\emptytoks - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} +\unexpanded\def\doifvaluesomething#1% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} -\stoplmtxmode +\unexpanded\def\doifelsevaluenothing#1% + {\edef\m_syst_string_one{\csname#1\endcsname}% + \ifx\m_syst_string_one\empty + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} \let\doifvalueelse \doifelsevalue \let\doifnothingelse \doifelsenothing @@ -7970,58 +7175,29 @@ %D %D Not that fast I guess, but here's a way to test for token registers being empty. -\startmkivmode - - \unexpanded\def\doifelsesometoks#1% - {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok - \ifx\m_syst_string_one\empty - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - - \unexpanded\def\doifsometoks#1% - {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok - \ifx\m_syst_string_one\empty - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} - - \unexpanded\def\doifemptytoks#1% - {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok - \ifx\m_syst_string_one\empty - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} - -\stopmkivmode - -\startlmtxmode - - \unexpanded\def\doifelsesometoks#1% - {\iftok#1\emptytoks - \expandafter\secondoftwoarguments - \else - \expandafter\firstoftwoarguments - \fi} - - \unexpanded\def\doifsometoks#1% - {\iftok#1\emptytoks - \expandafter\gobbleoneargument - \else - \expandafter\firstofoneargument - \fi} +\unexpanded\def\doifelsesometoks#1% + {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok + \ifx\m_syst_string_one\empty + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} - \unexpanded\def\doifemptytoks#1% - {\iftok#1\emptytoks - \expandafter\firstofoneargument - \else - \expandafter\gobbleoneargument - \fi} +\unexpanded\def\doifsometoks#1% + {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok + \ifx\m_syst_string_one\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} -\stoplmtxmode +\unexpanded\def\doifemptytoks#1% + {\edef\m_syst_string_one{\the#1}% one level expansion so quite ok + \ifx\m_syst_string_one\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} \let\doifsometokselse\doifelsesometoks @@ -8234,33 +7410,18 @@ %D %D This is a dirty one: we simply append a unit and discard it when needed. -\startmkivmode - - \def\doifelsedimension#1% - {\afterassignment\syst_helpers_if_dimension_else\privatescratchdimen#1pt\relax} - - % \def\doifelsedimension#1% - % {\expandafter\syst_helpers_if_dimension_else\immediateassignment\privatescratchdimen#1pt\relax} - - \def\syst_helpers_if_dimension_else#1% - {\ifx#1\relax - \expandafter\secondoftwoarguments - \else % #1=p ... t\relax - \expandafter\thirdoffourarguments - \fi} - -\stopmkivmode +\def\doifelsedimension#1% + {\afterassignment\syst_helpers_if_dimension_else\privatescratchdimen#1pt\relax} -\startlmtxmode +% \def\doifelsedimension#1% +% {\expandafter\syst_helpers_if_dimension_else\immediateassignment\privatescratchdimen#1pt\relax} - \def\doifelsedimension#1% - {\ifchkdim#1\or - \expandafter\firstoftwoarguments - \else - \expandafter\secondoftwoarguments - \fi} - -\stoplmtxmode +\def\syst_helpers_if_dimension_else#1% + {\ifx#1\relax + \expandafter\secondoftwoarguments + \else % #1=p ... t\relax + \expandafter\thirdoffourarguments + \fi} \let\doifdimensionelse\doifelsedimension @@ -8281,67 +7442,57 @@ %D \NC 1 \NC \doifdimenstringelse {1}{yes}{no} \NC \NR %D \stoptabulate -\startmkivmode - - \installsystemnamespace{dimenchecka} - \installsystemnamespace{dimencheckb} - \installsystemnamespace{dimencheckc} - - \def\doifelsedimenstring#1{\normalexpanded{\noexpand\dodimenteststageone#1}\empty\empty]} - - \def\dodimenteststageone #1#2{\csname \??dimenchecka\ifcsname \??dimenchecka#2\endcsname#2\else x\fi\endcsname#2} - \def\dodimenteststagetwo #1#2{\csname \??dimencheckb\ifcsname \??dimencheckb#2\endcsname#2\else x\fi\endcsname#2} - \def\dodimenteststagethree #1]{\csname \??dimencheckc\ifcsname \??dimencheckc#1\endcsname#1\else x\fi\endcsname} - - \expandafter\let\csname \??dimenchecka x\endcsname\dodimenteststagethree - \expandafter\let\csname \??dimencheckb x\endcsname\dodimenteststagethree - \expandafter\let\csname \??dimencheckc x\endcsname\secondoftwoarguments - - \expandafter\let\csname \??dimenchecka.\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimenchecka,\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimenchecka1\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka2\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka3\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka4\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka5\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka6\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka7\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka8\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka9\endcsname\dodimenteststageone - \expandafter\let\csname \??dimenchecka0\endcsname\dodimenteststageone - - \expandafter\let\csname \??dimencheckb1\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb2\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb3\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb4\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb5\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb6\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb7\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb8\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb9\endcsname\dodimenteststagetwo - \expandafter\let\csname \??dimencheckb0\endcsname\dodimenteststagetwo - - \expandafter\let\csname \??dimencheckc pt\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc pc\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc in\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc bp\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc cm\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc mm\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc dd\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc cc\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc sp\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc ex\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc em\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc nd\endcsname\firstoftwoarguments - \expandafter\let\csname \??dimencheckc nc\endcsname\firstoftwoarguments - -\stopmkivmode - -\startlmtxmode - - \let\doifelsedimenstring\doifelsedimension - -\stoplmtxmode +\installsystemnamespace{dimenchecka} +\installsystemnamespace{dimencheckb} +\installsystemnamespace{dimencheckc} + +\def\doifelsedimenstring#1{\normalexpanded{\noexpand\dodimenteststageone#1}\empty\empty]} + +\def\dodimenteststageone #1#2{\csname \??dimenchecka\ifcsname \??dimenchecka#2\endcsname#2\else x\fi\endcsname#2} +\def\dodimenteststagetwo #1#2{\csname \??dimencheckb\ifcsname \??dimencheckb#2\endcsname#2\else x\fi\endcsname#2} +\def\dodimenteststagethree #1]{\csname \??dimencheckc\ifcsname \??dimencheckc#1\endcsname#1\else x\fi\endcsname} + +\expandafter\let\csname \??dimenchecka x\endcsname\dodimenteststagethree +\expandafter\let\csname \??dimencheckb x\endcsname\dodimenteststagethree +\expandafter\let\csname \??dimencheckc x\endcsname\secondoftwoarguments + +\expandafter\let\csname \??dimenchecka.\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimenchecka,\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimenchecka1\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka2\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka3\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka4\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka5\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka6\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka7\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka8\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka9\endcsname\dodimenteststageone +\expandafter\let\csname \??dimenchecka0\endcsname\dodimenteststageone + +\expandafter\let\csname \??dimencheckb1\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb2\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb3\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb4\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb5\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb6\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb7\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb8\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb9\endcsname\dodimenteststagetwo +\expandafter\let\csname \??dimencheckb0\endcsname\dodimenteststagetwo + +\expandafter\let\csname \??dimencheckc pt\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc pc\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc in\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc bp\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc cm\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc mm\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc dd\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc cc\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc sp\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc ex\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc em\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc nd\endcsname\firstoftwoarguments +\expandafter\let\csname \??dimencheckc nc\endcsname\firstoftwoarguments \let\doifdimenstringelse\doifelsedimenstring diff --git a/tex/context/base/mkiv/syst-aux.mkxl b/tex/context/base/mkiv/syst-aux.mkxl new file mode 100644 index 000000000..725deb866 --- /dev/null +++ b/tex/context/base/mkiv/syst-aux.mkxl @@ -0,0 +1,6558 @@ +%D \module +%D [ file=syst-aux, % merge of syst-gen cum suis +%D version=1996.03.20, +%D title=\CONTEXT\ System Macros, +%D subtitle=General, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\registerctxluafile{syst-aux}{} + +%D This fils is a follow up in \type {syst-aux.mkii} and \type {syst-aux.mkiv} +%D where you can find some more pure \TEX\ or \LUATEX| variants. + +\unprotect + +%D \macros +%D {unexpanded} +%D +%D Because we use this module only in \MKIV, we have removed the old protection +%D code. +%D +%D \starttyping +%D \unexpanded\def\somecommand{... ... ...} +%D \stoptyping +%D +%D This overloads the \ETEX\ primitive but as we already had an \MKII\ solution we +%D keep the same name for a similar mechanism. + +\let\unexpanded\normalprotected + +\ifcase\contextlmtxmode + + \def\startlmtxmode#1\stoplmtxmode{} + \let\stoplmtxmode \relax + \let\startmkivmode\relax + \let\stopmkivmode \relax + +\else + + \let\startlmtxmode\relax + \let\stoplmtxmode \relax + \def\startmkivmode#1\stopmkivmode{} + \let\stopmkivmode \relax + +\fi + +%D As we don't have namespace definers yet, we use a special one: + +\ifdefined\c_syst_helpers_n_of_namespaces + + % lets plug in a better error message + +\else + + \newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes + + \def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>} + %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet + +\fi + +\unexpanded\def\installsystemnamespace#1% maybe move this to syst-ini + {\ifcsname ??#1\endcsname + \writestatus\m!system{duplicate system namespace '#1'}\wait + \else + \global\advance\c_syst_helpers_n_of_namespaces\plusone + \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}% + \fi} + +%D \macros +%D {normalspace} +%D +%D There is already \type{\space} but just to be sure we also provide: + +\def\normalspace{ } + +%D \macros +%D {!!count, !!toks, !!dimen, !!box, +%D !!width, !!height, !!depth, !!string, !!done} +%D +%D We define some more \COUNTERS\ and \DIMENSIONS. We also define some shortcuts to +%D the local scatchregisters~0, 2, 4, 6 and~8. + +\newcount\!!counta \newtoks\!!toksa \newdimen\!!dimena \newbox\!!boxa +\newcount\!!countb \newtoks\!!toksb \newdimen\!!dimenb \newbox\!!boxb +\newcount\!!countc \newtoks\!!toksc \newdimen\!!dimenc \newbox\!!boxc +\newcount\!!countd \newtoks\!!toksd \newdimen\!!dimend \newbox\!!boxd +\newcount\!!counte \newtoks\!!tokse \newdimen\!!dimene \newbox\!!boxe +\newcount\!!countf \newtoks\!!toksf \newdimen\!!dimenf \newbox\!!boxf + \newdimen\!!dimeng + \newdimen\!!dimenh + \newdimen\!!dimeni + \newdimen\!!dimenj + \newdimen\!!dimenk + +\let\!!stringa\empty \let\!!stringb\empty \let\!!stringc\empty +\let\!!stringd\empty \let\!!stringe\empty \let\!!stringf\empty + +\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha +\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb +\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc +\newdimen\!!widthd \newdimen\!!heightd \newdimen\!!depthd + +\newif\if!!donea \newif\if!!doneb \newif\if!!donec +\newif\if!!doned \newif\if!!donee \newif\if!!donef + +\def\!!zerocount {0} % alongside \zerocount +\def\!!minusone {-1} % ... +\def\!!plusone {1} % ... +\def\!!plustwo {2} % ... +\def\!!plusthree {3} % ... +\def\!!plusfour {4} % ... +\def\!!plusfive {5} % ... +\def\!!plussix {6} % ... +\def\!!plusseven {7} % ... +\def\!!pluseight {8} % ... +\def\!!plusnine {9} % alongside \plusnine + +\setnewconstant \uprotationangle 0 +\setnewconstant\rightrotationangle 90 +\setnewconstant \downrotationangle 180 +\setnewconstant \leftrotationangle 270 + +\ifdefined\data \else \let\data \relax \fi % dep checker + +%D \macros +%D {s!,c!,e!,p!,v!,@@,??} +%D +%D To save memory, we use constants (sometimes called variables). Redefining these +%D constants can have disastrous results. + +\def\v!prefix! {v!} +\def\c!prefix! {c!} +\def\s!prefix! {s!} + +\def\s!next {next} +\def\s!default {default} +\def\s!dummy {dummy} +\def\s!unknown {unknown} + +\def\s!do {do} +\def\s!dodo {dodo} + +\def\s!complex {complex} +\def\s!start {start} +\def\s!simple {simple} +\def\s!stop {stop} + +\def\s!empty {empty} + +%D Sometimes we pass macros as arguments to commands that don't expand them +%D before interpretation. Such commands can be enclosed with \type {\expanded}, +%D like: +%D +%D \starttyping +%D \expanded{\setupsomething[\alfa]} +%D \stoptyping +%D +%D Such situations occur for instance when \type{\alfa} is a commalist or when data +%D stored in macros is fed to index of list commands. If needed, one should use +%D \type{\noexpand} inside the argument. Later on we will meet some more clever +%D alternatives to this command. Beware, only the simple one has \type {\noexpand} +%D before its argument. + +\let\m_syst_helpers_expanded\empty + +\unexpanded\def\expanded#1% + {\xdef\m_syst_helpers_expanded{\noexpand#1}\m_syst_helpers_expanded} + +\unexpanded\def\startexpanded#1\stopexpanded + {\xdef\m_syst_helpers_expanded{#1}\m_syst_helpers_expanded} + +\let\stopexpanded\relax + +%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when +%D possible. After all, we can make not expandable macros now. + +% We cannot use the next variant as first we need to adapt \type {##}'s in callers: +% +% \def\expanded#1% +% {\normalexpanded{\noexpand#1}} +% +% \def\startexpanded#1\stopexpanded +% {\normalexpanded{#1}} + +%D \macros +%D {gobbleoneargument,gobble...arguments} +%D +%D The next set of macros just do nothing, except that they get rid of a number of +%D arguments. + +\def\gobbleoneargument #1{} +\def\gobbletwoarguments #1#2{} +\def\gobblethreearguments#1#2#3{} +\def\gobblefourarguments #1#2#3#4{} +\def\gobblefivearguments #1#2#3#4#5{} +\def\gobblesixarguments #1#2#3#4#5#6{} +\def\gobblesevenarguments#1#2#3#4#5#6#7{} +\def\gobbleeightarguments#1#2#3#4#5#6#7#8{} +\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{} +\def\gobbletenarguments #1{\gobbleninearguments} + +\def\gobbleoneoptional [#1]{} +\def\gobbletwooptionals [#1][#2]{} +\def\gobblethreeoptionals[#1][#2][#3]{} +\def\gobblefouroptionals [#1][#2][#3][#4]{} +\def\gobblefiveoptionals [#1][#2][#3][#4][#5]{} + +%D Reserved macros for tests: + +\let\donothing\empty + +\let\m_syst_string_one \empty +\let\m_syst_string_two \empty +\let\m_syst_string_three\empty +\let\m_syst_string_four \empty + +\let\m_syst_action_yes \empty +\let\m_syst_action_nop \empty + +%D \macros +%D {doifnextcharelse} +%D +%D When we started using \TEX\ in the late eighties, our first experiences with +%D programming concerned a simple shell around \LATEX. The commands probably use +%D most at \PRAGMA, are the itemizing ones. One of those few shell commands took +%D care of an optional argument, that enabled us to specify what kind of item symbol +%D we wanted. Without understanding anything we were able to locate a \LATEX\ macro +%D that could be used to inspect the next character. +%D +%D It's this macro that the ancester of the next one presented here. It executes one +%D of two actions, dependant of the next character. Disturbing spaces and line +%D endings, which are normally interpreted as spaces too, are skipped. +%D +%D \starttyping +%D \doifnextcharelse {karakter} {then ...} {else ...} +%D \stoptyping +%D +%D This macro differs from the original in the use of \type {\localnext} because we +%D don't want clashes with \type {\next}. + +\let\next \relax +\let\nextnext \relax +\let\nextnextnext \relax +\let\nexttoken \relax +\let\charactertoken\relax + +\let\m_syst_action_yes\relax +\let\m_syst_action_nop\relax + +% \def\syst_helpers_inspect_next_character +% {\ifx\nexttoken\blankspace +% \expandafter\syst_helpers_reinspect_next_character +% \else +% \expandafter\syst_helpers_inspect_next_character_indeed +% \fi} +% +% \def\syst_helpers_inspect_next_character_indeed +% {\ifx\nexttoken\charactertoken +% \expandafter\m_syst_action_yes +% \else +% \expandafter\m_syst_action_nop +% \fi} + +\unexpanded\def\doifelsenextchar#1#2#3% #1 should not be {} ! + {\def\m_syst_action_yes{#2}% + \def\m_syst_action_nop{#3}% + \futureexpandis#1\m_syst_action_yes\m_syst_action_nop} + +\unexpanded\def\doifelsenextcharcs % #1#2#3% #1 should not be {} ! + {\futureexpandis} + +\let\doifnextcharelse \doifelsenextchar +\let\doifnextcharcselse\doifelsenextcharcs + +%D Because we will mostly use this macro for testing if the next character is \type +%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of +%D thousands of calls to this test in a run. Of course it also is more convenient to +%D read a trace then. + +% \newif\if_next_blank_space_token + +% \let\syst_helpers_next_optional_character_token=[ +% +% \def\syst_helpers_inspect_next_optional_character +% {\ifx\nexttoken\blankspace +% \expandafter\syst_helpers_reinspect_next_optional_character +% \else +% \expandafter\syst_helpers_inspect_next_optional_character_indeed +% \fi} +% +% \def\syst_helpers_inspect_next_optional_character_indeed +% {\ifx\nexttoken\syst_helpers_next_optional_character_token +% \expandafter\m_syst_action_yes +% \else +% \expandafter\m_syst_action_nop +% \fi} + +\unexpanded\def\doifelsenextoptional#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futureexpandis[\m_syst_action_yes\m_syst_action_nop} + +\unexpanded\def\doifelsenextoptionalcs + {\futureexpandis[} + +\let\doifnextoptionalelse \doifelsenextoptional +\let\doifnextoptionalcselse\doifelsenextoptionalcs + +% \let\syst_helpers_next_bgroup_character_token\bgroup +% +% \def\syst_helpers_inspect_next_bgroup_character +% {\ifx\nexttoken\blankspace +% \expandafter\syst_helpers_reinspect_next_bgroup_character +% \else +% \expandafter\syst_helpers_inspect_next_bgroup_character_indeed +% \fi} +% +% \def\syst_helpers_inspect_next_bgroup_character_indeed +% {\ifx\nexttoken\syst_helpers_next_bgroup_character_token +% \expandafter\m_syst_action_yes +% \else +% \expandafter\m_syst_action_nop +% \fi} + +\unexpanded\def\doifelsenextbgroup#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop} + +\unexpanded\def\doifelsenextbgroupcs % #1#2 + {\futureexpandis\bgroup} + +\let\doifnextbgroupelse \doifelsenextbgroup +\let\doifnextbgroupcselse\doifelsenextbgroupcs + +% \let\syst_helpers_next_parenthesis_character_token( +% +% \def\syst_helpers_inspect_next_parenthesis_character +% {\ifx\nexttoken\blankspace +% \expandafter\syst_helpers_reinspect_next_parenthesis_character +% \else +% \expandafter\syst_helpers_inspect_next_parenthesis_character_indeed +% \fi} +% +% \def\syst_helpers_inspect_next_parenthesis_character_indeed +% {\ifx\nexttoken\syst_helpers_next_parenthesis_character_token +% \expandafter\m_syst_action_yes +% \else +% \expandafter\m_syst_action_nop +% \fi} + +\unexpanded\def\doifelsenextparenthesis#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futureexpandis(\m_syst_action_yes\m_syst_action_nop} + +\let\doifnextparenthesiselse\doifelsenextparenthesis + +%D The next one is handy in predictable situations: + +\def\syst_helpers_do_if_fast_optional_check_else + {\ifx\nexttoken\syst_helpers_next_optional_character_token + \expandafter\m_syst_action_yes + \else + \expandafter\m_syst_action_nop + \fi} + +\unexpanded\def\doifelsefastoptionalcheck#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futureexpandis[\m_syst_action_yes\m_syst_action_nop} + +\unexpanded\def\doifelsefastoptionalcheckcs + {\futureexpandis[} + +\let\doiffastoptionalcheckelse \doifelsefastoptionalcheck +\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs + +%D Here's one for skipping spaces and pars, handy for: +%D +%D \starttyping +%D \hbox +%D +%D {a few lines later} +%D \stoptyping +%D +%D like: +%D +%D \starttyping +%D \def\somecommand{\dowithnextbox{\box\nextbox}\ruledhbox} +%D +%D \assumelongusagecs\somecommand +%D +%D \bgroup +%D oeps +%D \egroup +%D \stoptyping + +%D The cumbersome original: + +% \unexpanded\def\assumelongusagecs#1% +% {\let\m_syst_action#1% +% \futurelet\nexttoken\syst_helpers_ignore_spacing} +% +% \def\syst_helpers_ignore_spacing +% {\ifx\nexttoken\blankspace +% \expandafter\syst_helpers_ignore_spacing_blankspace +% \orelse\ifx\nexttoken\par +% \expandafter\syst_helpers_ignore_spacing_partoken +% \else +% \expandafter\m_syst_action +% \fi} +% +% \def\syst_helpers_ignore_spacing_partoken\par +% {\futurelet\nexttoken\syst_helpers_ignore_spacing} + +%D A bit less tracing noise: + +% \def\assume_long_usage_cs +% {\futureexpandis\par\assume_long_usage_par\m_syst_action} +% +% \def\assume_long_usage_par\par% +% {\assume_long_usage_cs} +% +% \unexpanded\def\assumelongusagecs#1{\let\m_syst_action#1\assume_long_usage_cs} + +%D Ok, using \type {\futureexpandisap} is maybe feature creep but I'd like to experiment +%D with more tolerant user input. It might go away in which case we use the above. + +\unexpanded\def\assumelongusagecs#1% + {\futureexpandisap\relax#1#1} + +% D These macros use some auxiliary macros. Although we were able to program quite +% D complicated things, I only understood these after rereading the \TEX book. The +% D trick is in using a command with a one character name. Such commands differ from +% D the longer ones in the fact that trailing spaces are {\em not} skipped. This +% D enables us to indirectly define a long named macro that gobbles a space. In the +% D first line we define \type {\blankspace}. Next we make \type {\:} equivalent to +% D \type {\reinspect...}. This one||character command is expanded before the next +% D \type {\def} comes into action. This way the space after \type {\:} becomes a +% D delimiter of the longer named \type {\reinspectnextcharacter}. + +\let\next\: + +\def\:{\let\blankspace= } \: + +% \def\:{\syst_helpers_reinspect_next_character} +% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_character} +% +% \def\:{\syst_helpers_reinspect_next_optional_character} +% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_optional_character} +% +% \def\:{\syst_helpers_reinspect_next_bgroup_character} +% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_bgroup_character} +% +% \def\:{\syst_helpers_reinspect_next_parenthesis_character} +% \expandafter\def\: {\let\if_next_blank_space_token\iftrue\futurelet\nexttoken\syst_helpers_inspect_next_parenthesis_character} +% +% \def\:{\syst_helpers_ignore_spacing_blankspace} +% \expandafter\def\: {\futurelet\nexttoken\syst_helpers_ignore_spacing} + +\let\:\next + +%D \macros +%D {setvalue,setgvalue,setevalue,setxvalue, +%D letvalue,letgvalue,getvalue,resetvalue, +%D undefinevalue,ignorevalue} +%D +%D \TEX's primitive \type {\csname} can be used to construct all kind of commands +%D that cannot be defined with \type {\def} and \type {\let}. Every macro programmer +%D sooner or later wants macros like these. +%D +%D \starttyping +%D \setvalue {name}{...} = \def\name{...} +%D \setgvalue {name}{...} = \gdef\name{...} +%D \setevalue {name}{...} = \edef\name{...} +%D \setxvalue {name}{...} = \xdef\name{...} +%D \letvalue {name}=\... = \let\name=\... +%D \letgvalue {name}=\... = \glet\name=\... +%D \getvalue {name} = \name +%D \resetvalue {name} = \def\name{} +%D \stoptyping +%D +%D As we will see, \CONTEXT\ uses these commands many times, which is mainly due to +%D its object oriented and parameter driven character. + +\def\setvalue #1{\expandafter\def \csname#1\endcsname} +\def\setgvalue #1{\expandafter\gdef\csname#1\endcsname} +\def\setevalue #1{\expandafter\edef\csname#1\endcsname} +\def\setxvalue #1{\expandafter\xdef\csname#1\endcsname} +\def\getvalue #1{\csname#1\endcsname} % maybe: \begincsname#1\endcsname +\def\letvalue #1{\expandafter\let \csname#1\endcsname} +\def\letgvalue #1{\expandafter\glet\csname#1\endcsname} +\def\resetvalue #1{\expandafter\let \csname#1\endcsname\empty} +\def\undefinevalue#1{\expandafter\let \csname#1\endcsname\undefined} +\def\ignorevalue#1#2{\expandafter\let \csname#1\endcsname\empty} + +\def\setuvalue #1{\normalprotected\expandafter \def\csname#1\endcsname} +\def\setuevalue #1{\normalprotected\expandafter\edef\csname#1\endcsname} +\def\setugvalue #1{\normalprotected\expandafter\gdef\csname#1\endcsname} +\def\setuxvalue #1{\normalprotected\expandafter\xdef\csname#1\endcsname} + +\unexpanded\def\getuvalue#1{\csname#1\endcsname} + +%D \macros +%D {globallet,glet} +%D +%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will +%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that +%D it matters much today. This shortcut is already defined: + +\let\globallet\glet + +%D \macros +%D {doifundefined,doifdefined, +%D doifundefinedelse,doifdefinedelse, +%D doifalldefinedelse} +%D +%D The standard way of testing if a macro is defined is comparing its meaning with +%D another undefined one, usually \type{\undefined}. To garantee correct working of +%D the next set of macros, \type{\undefined} may never be defined! +%D +%D \starttyping +%D \doifundefined {string} {...} +%D \doifdefined {string} {...} +%D \doifundefinedelse {string} {then ...} {else ...} +%D \doifdefinedelse {string} {then ...} {else ...} +%D \doifalldefinedelse {commalist} {then ...} {else ...} +%D \stoptyping +%D +%D Every macroname that \TEX\ builds gets an entry in the hash table, which is of +%D limited size. It is expected that \ETEX\ will offer a less memory||consuming +%D alternative. + +%D Although it will probably never be a big problem, it is good to be aware of the +%D difference between testing on a macro name to be build by using \type{\csname} and +%D \type{\endcsname} and testing the \type{\name} directly. +%D +%D \starttyping +%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi +%D +%D \ifundefined\NameB ... \else ... \fi +%D \stoptyping + +% \suppressifcsnameerror\plusone % already set + +\def\doifelseundefined#1% + {\ifcsname#1\endcsname + \expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments + \fi} + +\def\doifelsedefined#1% + {\ifcsname#1\endcsname + \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments + \fi} + +\def\doifundefined#1% + {\ifcsname#1\endcsname + \expandafter\gobbleoneargument\else\expandafter\firstofoneargument + \fi} + +\def\doifdefined#1% + {\ifcsname#1\endcsname + \expandafter\firstofoneargument\else\expandafter\gobbleoneargument + \fi} + +\let\doifundefinedelse\doifelseundefined +\let\doifdefinedelse \doifelsedefined + +%D \macros +%D {letbeundefined} +%D +%D Testing for being undefined comes down to testing on \type {\relax} when we use +%D \type {\csname}, but when using \type {\ifx}, we test on being \type +%D {\undefined}! In \ETEX\ we have \type {\ifcsname} and that way of testing on +%D existance is not the same as the one described here. Therefore we introduce: + +\unexpanded\def\letbeundefined#1% potential stack buildup when used \global + {\expandafter\let\csname#1\endcsname\undefined} % or use \undefinevalue to match \setvalue + +\unexpanded\def\localundefine#1% conditional + {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi} + +\unexpanded\def\globalundefine#1% conditional + {\ifcsname#1\endcsname\expandafter\glet\csname#1\endcsname\undefined\fi} + +%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined! +%D +%D When we were developing the scientific units module, we encountered different +%D behavior in text and math mode, which was due to this grouping subtilities. We +%D therefore decided to use \type{\begingroup} instead of \type{\bgroup}. + +\unexpanded\def\doifelsealldefined#1% + {\begingroup + \donetrue % we could use a reserved one and avoid the group + \processcommalist[#1]\syst_helpers_do_if_all_defined_else + \ifdone + \endgroup\expandafter\firstoftwoarguments + \else + \endgroup\expandafter\secondoftwoarguments + \fi} + +\let\doifalldefinedelse\doifelsealldefined + +\def\syst_helpers_do_if_all_defined_else#1% + {\ifcsname#1\endcsname\else + \donefalse + \expandafter\quitcommalist % added + \fi} + +%D \macros +%D {doif,doifelse,doifnot} +%D +%D Programming in \TEX\ differs from programming in procedural languages like +%D \MODULA. This means that one --- well, let me speek for myself --- tries to do +%D the things in the well known way. Therefore the next set of \type{\ifthenelse} +%D commands were between the first ones we needed. A few years later, the opposite +%D became true: when programming in \MODULA, I sometimes miss handy things like +%D grouping, runtime redefinition, expansion etc. While \MODULA\ taught me to +%D structure, \TEX\ taught me to think recursive. +%D +%D \starttyping +%D \doif {string1} {string2} {...} +%D \doifnot {string1} {string2} {...} +%D \doifelse {string1} {string2} {then ...}{else ...} +%D \stoptyping + +\unexpanded\def\doifelse#1#2% + {\iftok{#1}{#2}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\doif#1#2% + {\iftok{#1}{#2}% + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnot#1#2% + {\iftok{#1}{#2}% + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +%D \macros +%D {doifempty,doifemptyelse,doifnotempty} +%D +%D We complete our set of conditionals with: +%D +%D \starttyping +%D \doifempty {string} {...} +%D \doifnotempty {string} {...} +%D \doifemptyelse {string} {then ...} {else ...} +%D \stoptyping +%D +%D This time, the string is not expanded. + +\unexpanded\def\doifelseempty#1% + {\def\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifemptyelse\doifelseempty + +\unexpanded\def\doifempty#1% + {\def\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotempty#1% + {\def\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +%D \macros +%D {doifinset,doifnotinset,doifinsetelse} +%D +%D We can check if a string is present in a comma separated set of strings. +%D Depending on the result, some action is taken. +%D +%D \starttyping +%D \doifinset {string} {string,...} {...} +%D \doifnotinset {string} {string,...} {...} +%D \doifinsetelse {string} {string,...} {then ...} {else ...} +%D \stoptyping + +% !0nop=\doifinsetelse{ccc}{,}{yes}{nop} +% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop} +% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop} + +% !1nop=\doifinsetelse{}{}{yes}{nop} +% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop} +% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop} +% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop} +% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop} +% !6nop=\doifinsetelse{}{}{yes}{nop} +% !7nop=\doifinsetelse{}{aaa}{yes}{nop} +% !8nop=\doifinsetelse{aaa}{}{yes}{nop} + +% !1=\doifinset{}{}{yes} +% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes} +% !3=\doifinset{aaa}{bbb}{yes} +% !4yes=\doifinset{aaa}{aaa}{yes} +% !5=\doifinset{}{}{yes} +% !6=\doifinset{aaa}{}{yes} + +% !1yes=\doifnotinset{}{}{yes} +% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes} +% !3yes=\doifnotinset{aaa}{bbb}{yes} +% !4=\doifnotinset{aaa}{aaa}{yes} +% !5yes=\doifnotinset{}{}{yes} +% !6yes=\doifnotinset{aaa}{}{yes} + +\unexpanded\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}} +\unexpanded\def\doifinset #1#2{\clf_doifinset {#1}{#2}} +\unexpanded\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}} + % \let\firstinset \clf_firstinset + +\let\doifinsetelse\doifelseinset + +%D \macros +%D {doifcommon,doifnotcommon,doifcommonelse} +%D +%D Probably the most time consuming tests are those that test for overlap in sets +%D of strings. +%D +%D \starttyping +%D \doifcommon {string,...} {string,...} {...} +%D \doifnotcommon {string,...} {string,...} {...} +%D \doifcommonelse {string,...} {string,...} {then ...} {else ...} +%D \stoptyping + +% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop} +% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop} +% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop} +% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop} +% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop} +% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop} +% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop} +% !8nop=\doifcommonelse{}{}{yes}{nop} + +% !9nop=\doifcommonelse{,,}{,,}{yes}{nop} +% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop} +% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop} +% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop} +% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop} +% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop} + +\unexpanded\def\doifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}} +\unexpanded\def\doifcommon #1#2{\clf_doifcommon {#1}{#2}} +\unexpanded\def\doifnotcommon #1#2{\clf_doifnotcommon {#1}{#2}} + +\let\doifcommonelse\doifelsecommon + +%D \macros +%D {processcommalist,processcommacommand,quitcommalist, +%D processcommalistwithparameters} +%D +%D We've already seen some macros that take care of comma separated lists. Such +%D list can be processed with +%D +%D \starttyping +%D \processcommalist[string,string,...]\commando +%D \stoptyping +%D +%D The user supplied command \type{\commando} receives one argument: the string. +%D This command permits nesting and spaces after commas are skipped. Empty sets +%D are no problem. +%D +%D \startbuffer +%D \def\dosomething#1{(#1)} +%D +%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par +%D 2: \processcommalist [{a,b,c,d,e,f}] \dosomething \par +%D 3: \processcommalist [{a,b,c},d,e,f] \dosomething \par +%D 4: \processcommalist [a,b,{c,d,e},f] \dosomething \par +%D 5: \processcommalist [a{b,c},d,e,f] \dosomething \par +%D 6: \processcommalist [{a,b}c,d,e,f] \dosomething \par +%D 7: \processcommalist [] \dosomething \par +%D 8: \processcommalist [{[}] \dosomething \par +%D \stopbuffer +%D +%D \typebuffer +%D +%D Before we show the result, we present the macro's: + +\newcount\commalevel + +\installsystemnamespace{nextcommalevel} + +\def\syst_helpers_do_do_do_process_comma_item + {\csname\??nextcommalevel\the\commalevel\endcsname} + +% \ifcase\contextlmtxmode + + \def\syst_helpers_do_process_comma_item + {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item} + + \def\syst_helpers_do_do_process_comma_item + {\ifx\nexttoken\blankspace + \expandafter\syst_helpers_re_do_process_comma_item + \else + \expandafter\syst_helpers_do_do_process_comma_item_indeed + \fi} + + \def\syst_helpers_do_do_process_comma_item_indeed + {\ifx\nexttoken]% + \expandafter\gobbleoneargument + \else + \expandafter\syst_helpers_do_do_do_process_comma_item + \fi} + +% \else +% +% \def\syst_helpers_do_process_comma_item +% {\futureexpandis]\gobbleoneargument\syst_helpers_do_do_do_process_comma_item} +% +% \fi + +%D Empty arguments are not processed. Empty items (\type {,,}) however are +%D treated. We have to check for the special case \type {[{a,b,c}]}. + +\unexpanded\def\processcommalist[% + {\futurelet\nexttoken\syst_helpers_do_check_comma_item} + +\def\syst_helpers_do_check_comma_item + {\ifx\nexttoken]% + \expandafter\gobblethreearguments + \else + \expandafter\syst_helpers_do_process_comma_list + \fi + \relax} % this one preserved the next {} + +\def\syst_helpers_do_process_comma_list#1]#2% + {\global\advance\commalevel \plusone + \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,% + {#2{##1}\syst_helpers_do_process_comma_item}% + \syst_helpers_do_do_process_comma_item_gobble#1,]\relax + \global\advance\commalevel \minusone } + +\def\syst_helpers_do_do_process_comma_item_gobble#1{\syst_helpers_do_do_process_comma_item} + +%D One way of quitting a commalist halfway is: + +\unexpanded\def\quitcommalist + {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list} + +\def\syst_helpers_do_quit_comma_list#1]% + {\endgroup} + +\unexpanded\def\quitprevcommalist + {\begingroup\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_prev_comma_list} + +\def\syst_helpers_do_quit_prev_comma_list#1]% + {\let\syst_helpers_do_process_comma_item\syst_helpers_do_quit_comma_list} + +%D The hack we used for checking the next character \type {\doifnextcharelse} +%D is also used here. + +% \ifcase\contextlmtxmode + + \let\next\: + + \def\:{\syst_helpers_re_do_process_comma_item} % \:not saved ? + + \expandafter\def\: {\futurelet\nexttoken\syst_helpers_do_do_process_comma_item} + + \let\:\next + +% \fi + +%D The previous examples lead to: +%D +%D \getbuffer + +%D When a list is saved in a macro, we can use a construction like: +%D +%D \starttyping +%D \expandafter\processcommalist\expandafter[\list]\command +%D \stoptyping +%D +%D Such solutions suit most situations, but we wanted a bit more. +%D +%D \starttyping +%D \processcommacommand[string,\stringset,string]\commando +%D \stoptyping +%D +%D where \type{\stringset} is a predefined set, like: +%D +%D \starttyping +%D \def\first{aap,noot,mies} +%D \def\second{laatste} +%D +%D \processcommacommand[\first]\message +%D \processcommacommand[\first,second,third]\message +%D \processcommacommand[\first,between,\second]\message +%D \stoptyping +%D +%D Commands that are part of the list are expanded, so the use of this macro has its +%D limits. + +\unexpanded\def\processcommacommand[#1]% + {\normalexpanded{\processcommalist[#1]}} + +%D The argument to \type{\command} is not delimited. Because we often use \type {[]} +%D as delimiters, we also have: +%D +%D \starttyping +%D \processcommalistwithparameters[string,string,...]\command +%D \stoptyping +%D +%D where \type{\command} looks like: +%D +%D \starttyping +%D \def\command[#1]{... #1 ...} +%D \stoptyping + +\unexpanded\def\processcommalistwithparameters[#1]#2% + {\def\syst_helpers_do_process_comma_list_with_parameters##1{#2[##1]}% + \processcommalist[#1]\syst_helpers_do_process_comma_list_with_parameters} + +%D \macros +%D {startprocesscommalist,startprocesscommacommand} +%D +%D Two more: + +\let\syst_helpers_comma_list_step\relax + +\unexpanded\def\startprocesscommalist[#1]#2\stopprocesscommalist + {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}% + \processcommalist[#1]\syst_helpers_comma_list_step} + +\unexpanded\def\startprocesscommacommand[#1]#2\stopprocesscommacommand + {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}% + \normalexpanded{\processcommalist[#1]}\syst_helpers_comma_list_step} + +\let\stopprocesscommalist \relax +\let\stopprocesscommacommand\relax + +%D \macros +%D {processaction, +%D processfirstactioninset, +%D processallactionsinset} +%D +%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of +%D the presence of one or more provided items, some actions is taken. These macros +%D can be nested without problems. +%D +%D \starttyping +%D \processaction [x] [a=>\a,b=>\b,c=>\c] +%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c] +%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c] +%D \stoptyping +%D +%D We can supply both a \type {default} action and an action to be undertaken when +%D an \type {unknown} value is met: +%D +%D \starttyping +%D \processallactionsinset +%D [x,y,z] +%D [ a=>\a, +%D b=>\b, +%D c=>\c, +%D default=>\default, +%D unknown=>\unknown{... \commalistelement ...}] +%D \stoptyping +%D +%D When \type {#1} is empty, this macro scans list \type {#2} for the keyword \type +%D {default} and executed the related action if present. When \type {#1} is non +%D empty and not in the list, the action related to \type {unknown} is executed. +%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually +%D found keyword is available in \type {\commalistelement}. An advanced example of +%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\ +%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type +%D {SB125} etc. + +\newcount\processlevel + +\unexpanded\def\syst_helpers_do_compare_process_action_a[#1=>#2][#3]% + {\edef\m_syst_string_two{#1}% + \ifx\m_syst_string_two\s!default + \let\commalistelement\empty + #2% + \fi} + +% met \quitcommalist tot meer dan 25\% sneller + +\unexpanded\def\syst_helpers_do_compare_process_action_b[#1=>#2][#3]% + {\edef\m_syst_string_two{#1}% + \ifx\m_syst_string_one\m_syst_string_two + \def\commalistelement{#3}% + #2% + \expandafter\quitcommalist + \orelse\ifx\m_syst_string_two\s!unknown + \def\commalistelement{#3}% beware of loops + #2% + \fi} + +\unexpanded\def\processaction[#1]#2[% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_a + \else + \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_b + \fi + \edef\syst_helpers_do_process_action##1{\syst_helpers_do_compare_process_action[##1][#1]}% expands #1 + \processnextcommalist\relax\relax\syst_helpers_do_process_action[} + +\unexpanded\def\syst_helpers_do_compare_process_action_c[#1=>#2][#3]% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#3}% + \ifx\m_syst_string_one\m_syst_string_two + \def\commalistelement{#3}% + #2% + \expandafter\quitprevcommalist + \else + \edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\s!unknown + \def\commalistelement{#3}% + #2% + \fi + \fi} + +\unexpanded\def\processfirstactioninset[#1]% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\processaction + \else + \expandafter\syst_helpers_process_first_action_in_set_indeed + \fi + [#1]} + +\unexpanded\def\syst_helpers_process_first_action_in_set_indeed[#1]#2[#3]% + {\def\syst_helpers_do_process_action##1% + {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_c[####1][##1]}% + \processcommalist[#3]\syst_helpers_do_do_process_action}% + \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_action} + +\unexpanded\def\syst_helpers_do_compare_process_action_d[#1=>#2][#3]% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#3}% + \ifx\m_syst_string_one\m_syst_string_two + \def\commalistelement{#3}% + #2% + \expandafter\quitcommalist + \else + \edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\s!unknown + \def\commalistelement{#3}% + #2% + \fi + \fi} + +\installsystemnamespace{nextactionlevel} + +\unexpanded\def\syst_helpers_do_process_all_actions_in_set + {\csname\??nextactionlevel\the\processlevel\endcsname} + +\unexpanded\def\processallactionsinset[#1]% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty + \expandafter\processaction + \else + \expandafter\syst_helpers_process_all_actions_in_set_indeed + \fi + [#1]} + +\unexpanded\def\syst_helpers_process_all_actions_in_set_indeed[#1]#2[#3]% + {\advance\processlevel \plusone + \expandafter\def\csname\??nextactionlevel\the\processlevel\endcsname##1% + {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_d[####1][##1]}% + \processcommalist[#3]\syst_helpers_do_do_process_action}% + \normalexpanded{\processcommalist[#1]}\syst_helpers_do_process_all_actions_in_set + \advance\processlevel\minusone} + +%D These macros use: + +\unexpanded\def\processnextcommalist#1#2#3[#4#5]% + {#1% + \let\nexttoken#4% + \global\advance\commalevel \plusone + \expandafter\def\csname\??nextcommalevel\the\commalevel\endcsname##1,% + {#3{##1}\syst_helpers_do_process_comma_item}% + \syst_helpers_do_do_process_comma_item#4#5,]\relax + \global\advance\commalevel\minusone + #2} + +%D \macros +%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter} +%D +%D Sometimes the action to be undertaken depends on the next character. This macro +%D get this character and puts it in \type {\firstcharacter}. +%D +%D \starttyping +%D \getfirstcharacter {string} +%D \stoptyping +%D +%D A two step expansion is used to prevent problems with complicated arguments, for +%D instance arguments that consist of two or more expandable tokens. + +\let\firstcharacter \empty +\let\remainingcharacters\empty + +\unexpanded\def\getfirstcharacter #1{\clf_getfirstcharacter{#1}} +\unexpanded\def\doifelsefirstchar #1#2{\clf_doifelsefirstchar{#1}{#2}} +\unexpanded\def\thefirstcharacter #1{\clf_thefirstcharacter{#1}} +\unexpanded\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}} + +\let\doiffirstcharelse\doifelsefirstchar + +%D \macros +%D {doifinstringelse, doifincsnameelse} +%D +%D We can check for the presence of a substring in a given sequence of characters. +%D +%D \starttyping +%D \doifinsetelse {substring} {string} {then ...} {else ...} +%D \stoptyping + +\let\m_syst_sub_string\empty + +\unexpanded\def\doifelseinstring#1% + {\edef\m_syst_sub_string{#1}% expand #1 here + \ifx\m_syst_sub_string\empty + \expandafter\thirdofthreearguments + \else + \expandafter\syst_helpers_do_if_in_string_else_indeed + \fi} + +\let\doifinstringelse\doifelseinstring + +\unexpanded\def\syst_helpers_do_if_in_string_else_indeed#1% + {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\doifinstring#1%% + {\edef\m_syst_sub_string{#1}% expand #1 here + \ifx\m_syst_sub_string\empty + \expandafter\gobbletwoarguments + \else + \expandafter\syst_helpers_do_if_in_string_indeed + \fi} + +\unexpanded\def\syst_helpers_do_if_in_string_indeed#1% + {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotinstring#1%% + {\edef\m_syst_sub_string{#1}% expand #1 here + \ifx\m_syst_sub_string\empty + \expandafter\gobbletwoarguments + \else + \expandafter\syst_helpers_do_if_not_in_string_indeed + \fi} + +\unexpanded\def\syst_helpers_do_if_not_in_string_indeed#1% + {\syst_helpers_do_if_in_string_else\m_syst_sub_string{#1}% + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +% replaces prev + +\unexpanded\def\syst_helpers_do_if_in_string_else#1#2% ##2 can be {abc} + {\expandafter\def\expandafter\syst_helpers_do_do_if_in_string_else + \expandafter##\expandafter1#1##2##3^^^^0004{\unless\if##2@}% expand #1 here + \expandafter\syst_helpers_do_do_if_in_string_else\normalexpanded{#2#1}@@^^^^0004} % expand #2 here + +%D The next alternative proved to be upto twice as fast on tasks like checking +%D reserved words in pretty verbatim typesetting! This is mainly due to the fact +%D that passing (expanded) strings is much slower that passing a macro. +%D +%D \starttyping +%D \doifincsnameelse {substring} {\string} {then ...} {else ...} +%D \stoptyping +%D +%D Where \type {\doifinstringelse} does as much expansion as possible, the latter +%D alternative does minimal (one level) expansion. + +\unexpanded\def\syst_helpers_do_if_in_csname_else#1#2% + {\def\syst_helpers_do_do_if_in_csname_else##1#1##2##3^^^^0004% + {\unless\if##2@}% + \expandafter\syst_helpers_do_do_if_in_csname_else#2#1@@^^^^0004} + +\unexpanded\def\doifelseincsname#1#2% + {\normalexpanded{\syst_helpers_do_if_in_csname_else{#1}}{#2}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifincsnameelse\doifelseincsname + +%D \macros +%D {doifnumberelse,doifnumber,doifnotnumber} +%D +%D The next macro executes a command depending of the outcome of a test on numerals. +%D This is probably one of the fastest test possible, exept from a less robust +%D 10||step \type {\if}||ladder or some tricky \type {\lcode} checking. +%D +%D \starttyping +%D \doifnumberelse {string} {then ...} {else ...} +%D \stoptyping +%D +%D The macro accepts \type {123}, \type {abc}, \type {{}}, \type {\getal} and \type +%D {\the\count...}. This macro is a rather dirty one. + +\def\doifelsenumber#1% + {\ifchknum#1\or + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\def\doifnumber#1% + {\ifchknum#1\or + \expandafter\firstoftwoarguments + \else + \expandafter\gobbleoneargument + \fi} + +\def\doifnotnumber#1% + {\ifchknum#1\or + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\let\doifnumberelse\doifelsenumber + +%D \macros +%D {setpercentdimen} +%D +%D \starttyping +%D \scratchdimen=100pt \setpercentdimen\scratchdimen{10\letterpercent} +%D \scratchdimen=100pt \setpercentdimen\scratchdimen{5pt} +%D \scratchdimen \percentdimen \hsize {10\letterpercent} +%D \stoptyping + +\def\percentdimen#1#2% dimen percentage (with %) + {\dimexpr\clf_percentageof{#2}\dimexpr#1\relax} + +\unexpanded\def\setpercentdimen#1#2% dimen percentage (with %) + {#1=\clf_percentageof{#2}\dimexpr#1\relax} + +%D \macros +%D {makerawcommalist, +%D rawdoinsetelse, +%D rawprocesscommalist, +%D rawprocessaction} +%D +%D Some of the commands mentioned earlier are effective but slow. When one is +%D desperately in need of faster alternatives and when the conditions are +%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback +%D is that they do not take \type {\c!constants} into account, simply because no +%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because +%D this macro does not compare anything. Expandable macros are permitted as search +%D string. +%D +%D \starttyping +%D \makerawcommalist[string,string,...]\stringlist +%D \rawdoifelseinset{string}{string,...}{...}{...} +%D \rawprocesscommalist[string,string,...]\commando +%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c] +%D \stoptyping +%D +%D Spaces embedded in the list, for instance after commas, spoil the search process. +%D The gain in speed depends on the length of the argument (the longer the argument, +%D the less we gain). + +\unexpanded\def\makerawcommalist[#1]#2% use \processnext ... here + {\def\syst_helpers_do_make_raw_comma_list##1% we don't expand ##1 + {\ifx#2\empty + \def#2{##1}% + \else + \expandafter\def\expandafter#2\expandafter{#2,##1}% + \fi}% + \let#2\empty + \processcommalist[#1]\syst_helpers_do_make_raw_comma_list} + +\def\syst_helpers_raw_process_comma_item#1,#2% #2 eats up preceding space + {\if]#1\else + \csname\??nextcommalevel\the\commalevel\endcsname{#1}% + \expandafter\syst_helpers_raw_process_comma_item + \fi#2} + +\unexpanded\def\rawprocesscommalist[#1]#2% accepteert ook [\cs] + {\global\advance\commalevel \plusone + \expandafter\let\csname\??nextcommalevel\the\commalevel\endcsname#2% + \expandafter\syst_helpers_raw_process_comma_item#1,],% \relax + \global\advance\commalevel \minusone } + +\unexpanded\def\rawprocesscommacommand[#1]% not really needed + {\normalexpanded{\rawprocesscommalist[#1]}} + +%D Here is one without nesting: + +\unexpanded\def\syst_helpers_fast_process_comma_item#1,#2% #2 eats up preceding space + {\if]#1\else + \syst_helpers_fast_process_comma_command{#1}% + \expandafter\syst_helpers_fast_process_comma_item + \fi#2} + +\unexpanded\def\fastprocesscommalist[#1]#2% accepteert ook [\cs] + {\let\syst_helpers_fast_process_comma_command#2% + \expandafter\syst_helpers_fast_process_comma_item#1,],}% \relax + +\unexpanded\def\fastprocesscommacommand[#1]#2% accepteert ook [\cs] + {\let\syst_helpers_fast_process_comma_command#2% + \normalexpanded{\syst_helpers_fast_process_comma_item#1},],}% \relax + +% \def\rawdoifelseinset#1#2{\doifinstringelse{,#1,}{,#2,}} +% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}} + +\def\m_syst_two_commas{,,} + +\unexpanded\def\rawdoifelseinset#1% + {\edef\m_syst_sub_string{,#1,}% expand #1 here + \ifx\m_syst_sub_string\m_syst_two_commas + \expandafter\thirdofthreearguments + \else + \expandafter\syst_helpers_raw_do_if_in_set_else + \fi} + +\let\rawdoifinsetelse\rawdoifinsetelse + +\unexpanded\def\syst_helpers_raw_do_if_in_set_else#1% + {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\rawdoifinset#1% + {\edef\m_syst_sub_string{,#1,}% expand #1 here + \ifx\m_syst_sub_string\m_syst_two_commas + \expandafter\gobbletwoarguments + \else + \expandafter\syst_helpers_raw_do_if_in_set + \fi} + +\unexpanded\def\syst_helpers_raw_do_if_in_set#1%% + {\syst_helpers_do_if_in_string_else\m_syst_sub_string{,#1,}% + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +%D Some more raw material: + +\def\syst_helpers_do_raw_process_action[#1][#2]% + {\def\syst_helpers_do_do_raw_process_action##1,#1=>##2,##3^^^^0004% + {\if##3@\else + \def\m_syst_helpers_process_action{##2}% + \fi}% + \syst_helpers_do_do_raw_process_action,#2,#1=>,@^^^^0004} + +\unexpanded\def\rawprocessaction[#1]#2[#3]% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{undefined}% better \!!undefined + \let\m_syst_helpers_process_action\m_syst_string_two + \ifx\m_syst_string_one\empty + \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!default][#3]% + \else + \expandafter\syst_helpers_do_raw_process_action\expandafter[\m_syst_string_one][#3]% + \ifx\m_syst_helpers_process_action\m_syst_string_two + \expandafter\syst_helpers_do_raw_process_action\expandafter[\s!unknown][#3]% + \fi + \fi + \ifx\m_syst_helpers_process_action\m_syst_string_two + \else + \m_syst_helpers_process_action + \fi} + +%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less +%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which +%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type +%D {\let} and \type {\expandafter} in the test. +%D +%D \macros +%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue, +%D dogetvalue} +%D +%D When we are going to do assignments, we have to take multi||linguality into account. +%D For the moment we keep things simple and single||lingual. +%D +%D \starttyping +%D \dosetvalue {label} {variable} {value} +%D \dosetevalue {label} {variable} {value} +%D \dosetgvalue {label} {variable} {value} +%D \docopyvalue {to label} {from label} {variable} +%D \doresetvalue {label} {variable} +%D \stoptyping +%D +%D These macros are in fact auxiliary ones and are not meant for use outside the +%D assignment macros. + +\def\dosetvalue#1#2% #3 + {\expandafter\def\csname#1#2\endcsname} % {#3}} + +\def\dosetevalue#1#2% #3 + {\expandafter\edef\csname#1#2\endcsname} % {#3}} + +\def\dosetgvalue#1#2% #3 + {\expandafter\gdef\csname#1#2\endcsname} % {#3}} + +\def\doresetvalue#1#2% + {\expandafter\let\csname#1#2\endcsname\empty} + +\def\doignorevalue#1#2#3% + {\expandafter\let\csname#1#2\endcsname\empty} + +\def\docopyvalue#1#2#3% + {\expandafter\def\csname#1#3\endcsname{\csname#2#3\endcsname}} + +%D \macros +%D {doassign,undoassign,doassignempty} +%D +%D Assignments are the backbone of \CONTEXT. Abhorred by the concept of style file +%D hacking, we took a considerable effort in building a parameterized system. +%D Unfortunately there is a price to pay in terms of speed. Compared to other +%D packages and taking the functionality of \CONTEXT\ into account, the total size +%D of the format file is still very acceptable. Now how are these assignments done. +%D +%D Assignments can be realized with: +%D +%D \starttyping +%D \doassign[label][variable=value] +%D \undoassign[label][variable=value] +%D \stoptyping +%D +%D and: +%D +%D \starttyping +%D \doassignempty[label][variable=value] +%D \stoptyping +%D +%D Assignments like \type{\doassign} are compatible with: +%D +%D \starttyping +%D \def\labelvariable{value} +%D \stoptyping +%D +%D We do check for the presence of an \type{=} and loudly complain of it's missed. We +%D will redefine this macro later on, when a more advanced message mechanism is +%D implemented. + +\newif\iferrorisfatal + +\unexpanded\def\waitonfatalerror + {\iferrorisfatal\wait\fi} + +\unexpanded\def\showassignerror#1#2% + {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}% + \waitonfatalerror} + +\unexpanded\def\doassignempty[#1][#2=#3]% + {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi} + +%D \macros +%D {getparameters,geteparameters,getgparameters, +%D forgetparameters} +%D +%D Using the assignment commands directly is not our ideal of user friendly interfacing, +%D so we take some further steps. +%D +%D \starttyping +%D \getparameters [label] [...=...,...=...] +%D \forgetparameters [label] [...=...,...=...] +%D \stoptyping +%D +%D Again, the label identifies the category a variable belongs to. The second argument +%D can be a comma separated list of assignments. +%D +%D \starttyping +%D \getparameters +%D [demo] +%D [alfa=1, +%D beta=2] +%D \stoptyping +%D +%D is equivalent to +%D +%D \starttyping +%D \def\demoalfa{1} +%D \def\demobeta{2} +%D \stoptyping +%D +%D +%D In the pre||multi||lingual stadium \CONTEXT\ took the next approach. With +%D +%D \starttyping +%D \def\??demo {@@demo} +%D \def\!!alfa {alfa} +%D \def\!!beta {beta} +%D \stoptyping +%D +%D calling +%D +%D \starttyping +%D \getparameters +%D [\??demo] +%D [\!!alfa=1, +%D \!!beta=2] +%D \stoptyping +%D +%D lead to: +%D +%D \starttyping +%D \def\@@demoalfa{1} +%D \def\@@demobeta{2} +%D \stoptyping +%D +%D Because we want to be able to distinguish the \type{!!} pre||tagged user supplied +%D variables from internal counterparts, we will introduce a slightly different tag +%D in the multi||lingual modules. There we will use \type{c!} or \type{v!}, +%D depending on the context. +%D +%D By calling \type{doassign} directly, we save ourselves some argument passing +%D and gain some speed. Whatever optimizations we do, this command will always be +%D one of the bigger bottlenecks. The alternative \type{\geteparameters} --- it's +%D funny to see that this alternative saw the light so lately --- can be used to do +%D expanded assigments. + +\let\currentvalue\empty + +\unexpanded\def\getparameters {\dogetparameters\dosetvalue} +\unexpanded\def\geteparameters {\dogetparameters\dosetevalue} +\unexpanded\def\getgparameters {\dogetparameters\dosetgvalue} +\unexpanded\def\getxparameters {\dogetparameters\dosetxvalue} +\unexpanded\def\forgetparameters{\dogetparameters\doignorevalue} + +\let\getexpandedparameters\geteparameters + +\unexpanded\def\dogetparameters#1[#2]#3[#4% + {\if\noexpand#4]% + \expandafter\gobbleoneargument + \else + \let\setsomevalue#1% + \def\syst_helpers_get_parameters_assign{\syst_helpers_get_parameters_assign_indeed#2}% + \expandafter\syst_helpers_get_parameters + \fi#4} + +\def\syst_helpers_get_parameters#1]% + {\xprocesscommaitem#1,],^^^^0004} + +\def\syst_helpers_process_comma_item#1,#2% #2 takes space before , + {\if,#1,% dirty trick for testing #1=empty + \expandafter\syst_helpers_process_comma_item + \orelse\if]#1% + \expandafter\gobbleoneargument + \else + \syst_helpers_get_parameters_assign^^^^0004#1==\empty^^^^0004% + \expandafter\syst_helpers_process_comma_item + \fi#2} + +\def\syst_helpers_assign_error#1#2#3% + {\showassignerror{#2}{\the\inputlineno\space(#1)}} + +\def\syst_helpers_get_parameters_assign_normal#1^^^^0004#2=#3=#4#5^^^^0004% + {\ifx\empty#2\empty + \expandafter\syst_helpers_assign_error + \orelse\ifx#4\empty + \expandafter\syst_helpers_assign_error + \else + \expandafter\setsomevalue + \fi + {#1}{#2}{#3}} + +\def\syst_helpers_get_parameters_assign_error#1^^^^0004#2=#3=#4#5^^^^0004% + {\ifx\empty#2\empty + \expandafter\syst_helpers_assign_error + \orelse\ifx#4\empty + \expandafter\syst_helpers_assign_error + \orelse\ifcsname#1#2\endcsname + \expandafter\let\expandafter\currentvalue\csname#1#2\endcsname + \expandafter\setsomevalue + \else + \let\currentvalue\empty + \expandafter\setsomevalue + \fi + {#1}{#2}{#3}} + +\let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal + +\unexpanded\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} +\unexpanded\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} +\unexpanded\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\syst_helpers_get_parameters_assign_indeed#1^^^^0004#2==\empty^^^^0004} + +%D \macros +%D {processassignmentlist,processassignmentcommand, +%D startprocessassignmentlist,startprocessassignmentcommand} +%D +%D For Wolfgang: +%D +%D \starttyping +%D \def\showpair#1#2{key:#1, value:#2\par} +%D \processassignmentlist[a=1,b=2]\showpair +%D \stoptyping +%D +%D We can optimize this one if needed but it's not a core macro so hardly worth the +%D trouble and tokens. + +\unexpanded\def\processassignmentlist[#1]#2% #2 == \command{key}{value] + {\def\syst_helpers_process_assignment_entry##1{#2}% {##2}{##3} % namespace is ignored + \dogetparameters\syst_helpers_process_assignment_entry[][#1]} + +\unexpanded\def\processassignmentcommand[#1]% + {\normalexpanded{\processassignmentlist[#1]}} + +\unexpanded\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist + {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% + \processassignmentlist[#1]\currentassignmentlistcommand} + +\unexpanded\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand + {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}% + \normalexpanded{\processassignmentlist[#1]}\currentassignmentlistcommand} + +%D \macros{currentvalue} +%D +%D Just in case a \type{\getparameter} argument itself ends up inside a \type +%D {\write} or other expandable location, our new macro needs a default value. +%D +%D \starttyping +%D \getparameters[xxx][aaa=bbb]\par +%D \getparameters[xxx][=bbb]\par +%D \getparameters[xxx][aaa=]\par +%D \getparameters[xxx][=]\par +%D \getparameters[xxx][aaa]\par +%D \stoptyping + +%D \macros +%D {expandparameters} +%D +%D Example usage: +%D +%D \startbuffer +%D \getparameters[taco][name=taco] +%D \convertcommand\taconame\to\ascii \ascii +%D \expandparameters \getparameters[taco][name=\currentvalue\space hoekwater] +%D \convertcommand\taconame\to\ascii \ascii +%D \getparameters[taco][name=\currentvalue\space hoekwater] +%D \convertcommand\taconame\to\ascii \ascii +%D \stopbuffer +%D +%D \typebuffer +%D \startlines +%D \getbuffer +%D \stoplines +%D +%D Here we hook in the code (beware, this is the optimized get **): + +\def\syst_helpers_get_parameters_normal#1]% + {\syst_helpers_process_comma_item#1,],^^^^0004} + +\def\syst_helpers_get_parameters_expanded#1]% + {\let\dosetnvalue\setsomevalue + \let\setsomevalue\dosetevalue + \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_error + \let\setsomevalue\dosetevalue + \syst_helpers_process_comma_item#1,],^^^^0004% + \let\syst_helpers_get_parameters_assign_indeed\syst_helpers_get_parameters_assign_normal + \let\setsomevalue\dosetnvalue + \let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal + \let\currentvalue\empty} + +\let\syst_helpers_get_parameters\syst_helpers_get_parameters_normal % ** + +\unexpanded\def\expandparameters + {\let\syst_helpers_get_parameters\syst_helpers_get_parameters_expanded} + +%D \macros +%D {getemptyparameters} +%D +%D Sometimes we explicitly want variables to default to an empty string, so we +%D welcome: +%D +%D \starttyping +%D \getemptyparameters [label] [...=...,...=...] +%D \stoptyping + +\unexpanded\def\getemptyparameters[#1]#2[#3]% + {\def\syst_helpers_get_empty_parameters##1{\doassignempty[#1][##1]}% + \processcommalist[#3]\syst_helpers_get_empty_parameters} + +%D \macros +%D {copyparameters} +%D +%D Some \CONTEXT\ commands take their default setups from others. All commands that +%D are able to provide backgounds or rules around some content, for instance default +%D to the standard command for ruled boxes. Is situations like this we can use: +%D +%D \starttyping +%D \copyparameters [to-label] [from-label] [name1,name2,...] +%D \stoptyping +%D +%D For instance +%D +%D \starttyping +%D \copyparameters +%D [internal][external] +%D [alfa,beta] +%D \stoptyping +%D +%D Leads to: +%D +%D \starttyping +%D \def\internalalfa {\externalalfa} +%D \def\internalbeta {\externalbeta} +%D \stoptyping +%D +%D By using \type {\docopyvalue} we've prepared this command for use in a +%D multi||lingual environment. + +\unexpanded\def\copyparameters[#1]#2[#3]#4[#5]% + {\doifnot{#1}{#3} + {\def\syst_helpers_copy_parameter{\docopyvalue{#1}{#3}}% ##1 + \processcommalist[#5]\syst_helpers_copy_parameter}} + +%D \macros +%D {ifparameters,checkparameters} +%D +%D A slightly different one is \type {\checkparameters}, which also checks on the +%D presence of a~\type {=}. +%D +%D The boolean \type {\ifparameters} can be used afterwards. Combining both in one +%D \type {\if}||macro would lead to problems with nested \type {\if}'s. +%D +%D \starttyping +%D \checkparameters[argument] +%D \stoptyping + +\newif\ifparameters + +\def\syst_helpers_check_parameters#1=#2#3^^^^0004% + {\if#2^^^^0003\parametersfalse\else\parameterstrue\fi} + +\unexpanded\def\checkparameters[#1]% + {\syst_helpers_check_parameters#1=^^^^0003^^^^0003^^^^0004} + +%D \macros +%D {getfromcommalist,getfromcommacommand, +%D commalistelement, +%D getcommalistsize,getcommacommandsize} +%D +%D It's possible to get an element from a commalist or a command representing +%D a commalist. +%D +%D \starttyping +%D \getfromcommalist [string] [n] +%D \getfromcommacommand [string,\strings,string,...] [n] +%D \stoptyping +%D +%D The difference betwee the two of them is the same as the difference between +%D \type {\processcomma...}. The found string is stored in \type +%D {\commalistelement}. +%D +%D We can calculate the size of a comma separated list by using: +%D +%D \starttyping +%D \getcommalistsize [string,string,...] +%D \getcommacommandsize [string,\strings,string,...] +%D \stoptyping +%D +%D Afterwards, the length is available in the macro \type {\commalistsize} +%D (not a \COUNTER). + +\newcount\commalistcounter + +\def\commalistsize{0} + +\def\syst_helpers_get_comma_list_size#1% + {\advance\commalistcounter\plusone} + +\unexpanded\def\getcommalistsize#1]% don't loose [{#1}] + {\commalistcounter\zerocount + \processcommalist#1]\syst_helpers_get_comma_list_size % was [{#1}] + \edef\commalistsize{\the\commalistcounter}} + +% \def\getcommacommandsize[#1]% +% {\edef\commacommand{#1}% +% \scratchtoks\expandafter{\expandafter[\commacommand]}% +% \expandafter\getcommalistsize\the\scratchtoks } + +\unexpanded\def\getcommacommandsize[#1]% + {\normalexpanded{\getcommalistsize[#1]}} + +\def\syst_helpers_get_from_comma_list#1% + {\advance\commalistcounter \minusone + \ifcase\commalistcounter + \def\commalistelement{#1}% + \expandafter\quitcommalist + \fi} + +\unexpanded\def\getfromcommalist[#1]#2[#3]% + {\let\commalistelement\empty + \commalistcounter#3\relax + \processcommalist[#1]\syst_helpers_get_from_comma_list} + +\unexpanded\def\getfromcommacommand[#1]% + {\normalexpanded{\getfromcommalist[#1]}} + +%D Watertight (and efficient) solutions are hard to find, due to the handling of +%D braces during parameters passing and scanning. Nevertheless: +%D +%D \startbuffer +%D \def\dosomething#1{(#1=\commalistsize) } +%D +%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1 +%D \getcommalistsize [{a,b,c,d,e,f}] \dosomething 1 +%D \getcommalistsize [{a,b,c},d,e,f] \dosomething 4 +%D \getcommalistsize [a,b,{c,d,e},f] \dosomething 4 +%D \getcommalistsize [a{b,c},d,e,f] \dosomething 4 +%D \getcommalistsize [{a,b}c,d,e,f] \dosomething 4 +%D \getcommalistsize [] \dosomething 0 +%D \getcommalistsize [{[}] \dosomething 1 +%D \stopbuffer +%D +%D \typebuffer +%D +%D reports: +%D +%D \getbuffer + +%D \macros +%D {dogetcommalistelement,dogetcommacommandelement} +%D +%D For low level (fast) purposes, we can also use the next alternative, which can +%D handle 8~elements at most. +%D +%D \starttyping +%D \dogetcommalistelement1\from a,b,c\to\commalistelement +%D \stoptyping + +\def\syst_helpers_get_comma_list_element#1\from#2,#3,#4,#5,#6,#7,#8\to#9% + {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}} + +\def\dogetcommacommandelement#1\from#2\to% + {\expandafter\syst_helpers_get_comma_list_element\expandafter#1\expandafter\from#2,,,,,,\to} + +%D \macros +%D {dosingleargument,dodoubleargument,dotripleargument, +%D doquadrupleargument,doquintupleargument,dosixtupleargument, +%D doseventupleargument} +%D +%D When working with delimited arguments, spaces and lineendings can interfere. The +%D next set of macros uses \TEX' internal scanner for grabbing everything between +%D arguments. Forgive me the funny names. +%D +%D \starttyping +%D \dosingleargument\commando = \commando[#1] +%D \dodoubleargument\commando = \commando[#1][#2] +%D \dotripleargument\commando = \commando[#1][#2][#3] +%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4] +%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5] +%D \dosixtupleargument\commando = \commando[#1][#2][#3][#4][#5][#6] +%D \doseventupleargument\command = \commando[#1][#2][#3][#4][#5][#6][#7] +%D \stoptyping +%D +%D These macros are used in the following way: +%D +%D \starttyping +%D \def\dosetupsomething[#1][#2]% +%D {... #1 ... #2 ...} +%D +%D \unexpanded\def\setupsomething +%D {\dodoubleargument\dosetupsomething} +%D \stoptyping +%D +%D The implementation can be surprisingly simple and needs no +%D further explanation, like: +%D +%D \starttyping +%D \def\dosingleargument#1[#2]% +%D {#1[#2]} +%D \def\dotripleargument#1[#2]#3[#4]#5[#6]% +%D {#1[#2][#4][#6]} +%D \def\doquintupleargument#1% +%D {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]% +%D {#1[##1][##3][##5][##7][##9]}% +%D \dodoquintupleargument} +%D \stoptyping +%D +%D Because \TEX\ accepts 9~arguments at most, we have to use two||step solution when +%D getting five or more arguments. +%D +%D When developing more and more of the real \CONTEXT, we started using some +%D alternatives that provided empty arguments (in fact optional ones) whenever the +%D user failed to supply them. Because this more complicated macros enable us to do +%D some checking, we reimplemented the non||empty ones. + +%D \macros +%D {iffirstagument,ifsecondargument,ifthirdargument, +%D iffourthargument,iffifthargument,ifsixthargument, +%D ifseventhargument} +%D +%D We use some signals for telling the calling macros if all wanted arguments are +%D indeed supplied by the user. + +\newif\iffirstargument +\newif\ifsecondargument +\newif\ifthirdargument +\newif\iffourthargument +\newif\iffifthargument +\newif\ifsixthargument +\newif\ifseventhargument + +%D \macros +%D {dosingleempty,dodoubleempty,dotripleempty, +%D doquadrupleempty,doquintupleempty,dosixtupeempty, +%D doseventupleempty} +%D +%D The empty argument supplying macros mentioned before, look like: +%D +%D \starttyping +%D \dosingleempty \command +%D \dodoubleempty \command +%D \dotripleempty \command +%D \doquadrupleempty \command +%D \doquintupleempty \command +%D \dosixtuple_empty \command +%D \doseventupleempty\command +%D \stoptyping +%D +%D So \type{\dodoubleempty} leads to: +%D +%D \starttyping +%D \command[#1][#2] +%D \command[#1][] +%D \command[][] +%D \stoptyping +%D +%D Depending of the generousity of the user. Afterwards one can use the \type +%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s. + +%D Common: + +\newtoks\t_syst_aux + +\def\syst_helpers_single_empty_one_yes {\firstargumenttrue \the\t_syst_aux} +\def\syst_helpers_double_empty_two_yes {\secondargumenttrue \the\t_syst_aux} +\def\syst_helpers_triple_empty_three_yes {\thirdargumenttrue \the\t_syst_aux} +\def\syst_helpers_quadruple_empty_four_yes {\fourthargumenttrue \the\t_syst_aux} +\def\syst_helpers_quintuple_empty_five_yes {\fifthargumenttrue \the\t_syst_aux} +\def\syst_helpers_sixtuple_empty_six_yes {\sixthargumenttrue \the\t_syst_aux} +\def\syst_helpers_seventuple_empty_seven_yes{\seventhargumenttrue\the\t_syst_aux} + +%D Single: + +\unexpanded\def\dosingleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop} + +\def\syst_helpers_single_empty_one_nop + {\firstargumentfalse + \the\t_syst_aux[]} + +%D Double + +\unexpanded\def\dodoubleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop} + +\def\syst_helpers_double_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop} + +\def\syst_helpers_double_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_double_empty_two_nop + {\secondargumentfalse + \the\t_syst_aux[]} + +% Triple + +\unexpanded\def\dotripleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop} + +\def\syst_helpers_triple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop} + +\def\syst_helpers_triple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop} + +\def\syst_helpers_triple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_triple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_triple_empty_three_nop + {\thirdargumentfalse + \the\t_syst_aux[]} + +%D Quadruple: + +\unexpanded\def\doquadrupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop} + +\def\syst_helpers_quadruple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop} + +\def\syst_helpers_quadruple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop} + +\def\syst_helpers_quadruple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop} + +\def\syst_helpers_quadruple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux[][][][]} + +\def\syst_helpers_quadruple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_quadruple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_quadruple_empty_four_nop + {\fourthargumentfalse + \the\t_syst_aux[]} + +%D Quintuple: + +\unexpanded\def\doquintupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop} + +\def\syst_helpers_quintuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop} + +\def\syst_helpers_quintuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop} + +\def\syst_helpers_quintuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop} + +\def\syst_helpers_quintuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop} + +\def\syst_helpers_quintuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux[][][][][]} + +\def\syst_helpers_quintuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux[][][][]} + +\def\syst_helpers_quintuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_quintuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_quintuple_empty_five_nop + {\fifthargumentfalse + \the\t_syst_aux[]} + +%D Sixtuple: + +\unexpanded\def\dosixtupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop} + +\def\syst_helpers_sixtuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop} + +\def\syst_helpers_sixtuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop} + +\def\syst_helpers_sixtuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop} + +\def\syst_helpers_sixtuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop} + +\def\syst_helpers_sixtuple_empty_five_yes[#1]% + {\fifthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop} + +\def\syst_helpers_sixtuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][][][][][]} + +\def\syst_helpers_sixtuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][][][][]} + +\def\syst_helpers_sixtuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][][][]} + +\def\syst_helpers_sixtuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_sixtuple_empty_five_nop + {\fifthargumentfalse + \sixthargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_sixtuple_empty_six_nop + {\sixthargumentfalse + \the\t_syst_aux[]} + +%D Seventuple: + +\unexpanded\def\doseventupleempty#1% + {%syst_helpers_argument_reset + \t_syst_aux{#1}% + \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop} + +\def\syst_helpers_seventuple_empty_one_yes[#1]% + {\firstargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop} + +\def\syst_helpers_seventuple_empty_two_yes[#1]% + {\secondargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop} + +\def\syst_helpers_seventuple_empty_three_yes[#1]% + {\thirdargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop} + +\def\syst_helpers_seventuple_empty_four_yes[#1]% + {\fourthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop} + +\def\syst_helpers_seventuple_empty_five_yes[#1]% + {\fifthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop} + +\def\syst_helpers_seventuple_empty_six_yes[#1]% + {\sixthargumenttrue + \toksapp\t_syst_aux{[{#1}]}% + \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop} + +\def\syst_helpers_seventuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][][][][][]} + +\def\syst_helpers_seventuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][][][][]} + +\def\syst_helpers_seventuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][][][]} + +\def\syst_helpers_seventuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][][]} + +\def\syst_helpers_seventuple_empty_five_nop + {\fifthargumentfalse + \sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][][]} + +\def\syst_helpers_seventuple_empty_six_nop + {\sixthargumentfalse + \seventhargumentfalse + \the\t_syst_aux[][]} + +\def\syst_helpers_seventuple_empty_seven_nop + {\seventhargumentfalse + \the\t_syst_aux[]} + +%D Aliases: + +\let\dosingleargument \dosingleempty +\let\dodoubleargument \dodoubleempty +\let\dotripleargument \dotripleempty +\let\doquadrupleargument \doquadrupleempty +\let\doquintupleargument \doquintupleempty +\let\dosixtupleargument \dosixtupleempty +\let\doseventupleargument\doseventupleempty + +%D \macros +%D {strippedcsname} +%D +%D The next macro can be very useful when using \type{\csname} like in: +%D +%D \starttyping +%D \csname if\strippedcsname\something\endcsname +%D \stoptyping +%D +%D This expands to \type{\ifsomething}. + +% \def\strippedcsname +% {\expandafter\gobbleoneargument\string} + +\let\strippedcsname\csstring + +%D \macros +%D {complexorsimple,complexorsimpleempty} +%D +%D Setups can be optional. A command expecting a setup is prefixed by \type +%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like +%D this can be defined by: +%D +%D \starttyping +%D \complexorsimple\command +%D \stoptyping +%D +%D When \type{\command} is followed by a \type{[setup]}, then +%D +%D \starttyping +%D \complexcommand [setup] +%D \stoptyping +%D +%D executes, else we get +%D +%D \starttyping +%D \simplecommand +%D \stoptyping +%D +%D An alternative for \type{\complexorsimple} is: +%D +%D \starttyping +%D \complexorsimpleempty {command} +%D \stoptyping +%D +%D Depending on the presence of \type{[setup]}, this one leads to one of: +%D +%D \starttyping +%D \complexcommando [setup] +%D \complexcommando [] +%D \stoptyping +%D +%D Many \CONTEXT\ commands started as complex or simple ones, but changed into more +%D versatile (more object oriented) ones using the \type {\get..argument} commands. + +\unexpanded\def\complexorsimple#1% + {% \relax % prevents lookahead, brrr + \doifelsenextoptional + {\firstargumenttrue \csname\s!complex\csstring#1\endcsname} + {\firstargumentfalse\csname\s!simple \csstring#1\endcsname}} + +\unexpanded\def\complexorsimpleempty#1% + {% \relax % prevents lookahead, brrr + \doifelsenextoptional + {\firstargumenttrue \csname\s!complex\csstring#1\endcsname} + {\firstargumentfalse\csname\s!complex\csstring#1\endcsname[]}} + +%D \macros +%D {definecomplexorsimple,definecomplexorsimpleempty} +%D +%D The previous commands are used that often that we found it worthwile to offer two +%D more alternatives. Watch the build in protection. + +\unexpanded\def\syst_helpers_complex_or_simple#1#2% + {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}} + +\unexpanded\def\syst_helpers_complex_or_simple_empty#1% + {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}} + +\unexpanded\def\definecomplexorsimple#1% + {\unexpanded\edef#1{\syst_helpers_complex_or_simple + \expandafter\noexpand\csname\s!complex\csstring#1\endcsname + \expandafter\noexpand\csname\s!simple \csstring#1\endcsname}} + +\unexpanded\def\definecomplexorsimpleempty#1% + {\unexpanded\edef#1{\syst_helpers_complex_or_simple_empty + \expandafter\noexpand\csname\s!complex\csstring#1\endcsname}} + +%D These commands are called as: +%D +%D \starttyping +%D \definecomplexorsimple\command +%D \stoptyping +%D +%D Of course, we must have available +%D +%D \starttyping +%D \def\complexcommand[#1]{...} +%D \def\simplecommand {...} +%D \stoptyping +%D +%D Using this construction saves a few string now and then. + +%D \macros +%D {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty, +%D doquadruplegroupempty, doquintuplegroupempty} +%D +%D We've already seen some commands that take care of +%D optional arguments between \type{[]}. The next two commands +%D handle the ones with \type{{}}. They are called as: +%D +%D \starttyping +%D \dosinglegroupempty \ineedONEargument +%D \dodoublegroupempty \ineedTWOarguments +%D \dotriplegroupempty \ineedTHREEarguments +%D \doquadruplegroupempty \ineedFOURarguments +%D \doquintuplegroupempty \ineedFIVEarguments +%D \stoptyping +%D +%D We can add additional definitions later when we have defined \type {\appendtoks}. + +\newconditional\c_syst_helpers_permit_spaces_between_groups + +\unexpanded\def \permitspacesbetweengroups{\settrue \c_syst_helpers_permit_spaces_between_groups} +\unexpanded\def\dontpermitspacesbetweengroups{\setfalse\c_syst_helpers_permit_spaces_between_groups} + +\dontpermitspacesbetweengroups + +%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in +%D pieces so that we have no nested \type {\nextarguments} potentially being an +%D \type {conditional} token. Okay, these macros are not called that often but it +%D saves crap when tracing. + +\unexpanded\def\dosinglegroupempty#1% + {\t_syst_aux{#1}% + \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop} + +\def\syst_helpers_single_group_empty_one_nop + {\firstargumentfalse + \the\t_syst_aux{}} + +\unexpanded\def\dodoublegroupempty#1% + {\t_syst_aux{#1}% + \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop} + +\def\syst_helpers_group_double_empty_one_yes#1% + {\firstargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop} + +\def\syst_helpers_group_double_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \the\t_syst_aux{}{}} + +\def\syst_helpers_group_double_empty_two_nop + {\secondargumentfalse + \the\t_syst_aux{}} + +\unexpanded\def\dotriplegroupempty#1% + {\t_syst_aux{#1}% + \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop} + +\def\syst_helpers_group_triple_empty_one_yes#1% + {\firstargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop} + +\def\syst_helpers_group_triple_empty_two_yes#1% + {\secondargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop} + +\def\syst_helpers_group_triple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \the\t_syst_aux{}{}{}} + +\def\syst_helpers_group_triple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \the\t_syst_aux{}{}} + +\def\syst_helpers_group_triple_empty_three_nop + {\thirdargumentfalse + \the\t_syst_aux{}} + +\unexpanded\def\doquadruplegroupempty#1% + {\t_syst_aux{#1}% + \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop} + +\def\syst_helpers_group_quadruple_empty_one_yes#1% + {\firstargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop} + +\def\syst_helpers_group_quadruple_empty_two_yes#1% + {\secondargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop} + +\def\syst_helpers_group_quadruple_empty_three_yes#1% + {\thirdargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop} + +\def\syst_helpers_group_quadruple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux{}{}{}{}} + +\def\syst_helpers_group_quadruple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux{}{}{}} + +\def\syst_helpers_group_quadruple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \the\t_syst_aux{}{}} + +\def\syst_helpers_group_quadruple_empty_four_nop + {\fourthargumentfalse + \the\t_syst_aux{}} + +\unexpanded\def\doquintuplegroupempty#1% + {\t_syst_aux{#1}% + \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop} + +\def\syst_helpers_group_quintuple_empty_one_yes#1% + {\firstargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop} + +\def\syst_helpers_group_quintuple_empty_two_yes#1% + {\secondargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop} + +\def\syst_helpers_group_quintuple_empty_three_yes#1% + {\thirdargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop} + +\def\syst_helpers_group_quintuple_empty_four_yes#1% + {\fourthargumenttrue + \toksapp\t_syst_aux{{#1}}% + \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop} + +\def\syst_helpers_group_quintuple_empty_one_nop + {\firstargumentfalse + \secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux{}{}{}{}{}} + +\def\syst_helpers_group_quintuple_empty_two_nop + {\secondargumentfalse + \thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux{}{}{}{}} + +\def\syst_helpers_group_quintuple_empty_three_nop + {\thirdargumentfalse + \fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux{}{}{}} + +\def\syst_helpers_group_quintuple_empty_four_nop + {\fourthargumentfalse + \fifthargumentfalse + \the\t_syst_aux{}{}} + +\def\syst_helpers_group_quintuple_empty_five_nop + {\fifthargumentfalse + \the\t_syst_aux{}} + +%D These macros can explictly take care of spaces, which means that the next +%D definition and calls are valid: +%D +%D \starttyping +%D \def\test#1#2#3{[#1#2#3]} +%D +%D \dotriplegroupempty\test {a}{b}{c} +%D \dotriplegroupempty\test {a}{b} +%D \dotriplegroupempty\test {a} +%D \dotriplegroupempty\test +%D \dotriplegroupempty\test {a} {b} {c} +%D \dotriplegroupempty\test {a} {b} +%D \dotriplegroupempty\test +%D {a} +%D {b} +%D \stoptyping +%D +%D And alike. + +%D \macros +%D {firstofoneargument, firstoftwoarguments, firstofthreearguments +%D secondoftwoarguments, secondofthreearguments, +%D thirdofthreearguments} +%D +%D The next six macros (dedicated to Taco) can conveniently used to select +%D arguments. Their names explain their functionality. + +\def\firstofoneargument #1{#1} + +\def\firstoftwoarguments #1#2{#1} +\def\secondoftwoarguments #1#2{#2} + +\def\firstofthreearguments #1#2#3{#1} +\def\secondofthreearguments #1#2#3{#2} +\def\thirdofthreearguments #1#2#3{#3} + +\def\firstoffourarguments #1#2#3#4{#1} +\def\secondoffourarguments #1#2#3#4{#2} +\def\thirdoffourarguments #1#2#3#4{#3} +\def\fourthoffourarguments #1#2#3#4{#4} + +\def\firstoffivearguments #1#2#3#4#5{#1} +\def\secondoffivearguments #1#2#3#4#5{#2} +\def\thirdoffivearguments #1#2#3#4#5{#3} +\def\fourthoffivearguments #1#2#3#4#5{#4} +\def\fifthoffivearguments #1#2#3#4#5{#5} + +\def\firstofsixarguments #1#2#3#4#5#6{#1} +\def\secondofsixarguments#1#2#3#4#5#6{#2} +\def\thirdofsixarguments #1#2#3#4#5#6{#3} +\def\fourthofsixarguments#1#2#3#4#5#6{#4} +\def\fifthofsixarguments #1#2#3#4#5#6{#5} +\def\sixthofsixarguments #1#2#3#4#5#6{#6} + +\unexpanded\def\firstofoneunexpanded #1{#1} + +\unexpanded\def\firstoftwounexpanded #1#2{#1} +\unexpanded\def\secondoftwounexpanded #1#2{#2} + +\unexpanded\def\firstofthreeunexpanded #1#2#3{#1} +\unexpanded\def\secondofthreeunexpanded#1#2#3{#2} +\unexpanded\def\thirdofthreeunexpanded #1#2#3{#3} + +%D \macros +%D {globalletempty,letempty, +%D letvalueempty,letgvalueempty, +%D letvaluerelax,letgvaluerelax} +%D +%D Trivial: + +\unexpanded\def\letempty #1{\let #1\empty} +\unexpanded\def\globalletempty#1{\glet#1\empty} + +\unexpanded\def\letvalueempty #1{\expandafter\let \csname#1\endcsname\empty} +\unexpanded\def\letgvalueempty#1{\expandafter\glet\csname#1\endcsname\empty} +\unexpanded\def\letvaluerelax #1{\expandafter\let \csname#1\endcsname\relax} +\unexpanded\def\letgvalurelax #1{\expandafter\glet\csname#1\endcsname\relax} + +\unexpanded\def\relaxvalueifundefined#1% + {\ifcsname#1\endcsname \else + \expandafter\let\csname#1\endcsname\relax + \fi} + +%D \macros +%D {wait} +%D +%D The next macro hardly needs explanation. Because no nesting is to be expected, we +%D can reuse \type {\wait} within \type {\wait} itself. + +\unexpanded\def\wait + {\begingroup + \read16 to \wait + \endgroup} + +%D \macros +%D {writestring,writeline, +%D writestatus,statuswidth,normalwritestatus} +%D +%D Maybe one didn't notice, but we've already introduced a macro for showing +%D messages. In the multi||lingual modules, we will also introduce a mechanism for +%D message passing. For the moment we stick to the core macros: +%D +%D \starttyping +%D \writestring {string} +%D \writeline +%D \writestatus {category} {message} +%D \stoptyping +%D +%D Messages are formatted. One can provide the maximum with of the identification +%D string with the macro \type {\statuswidth}. + +\setnewconstant\statuswidth 15 +\setnewconstant\statuswrite 128 % \pluscxxviii + +\ifdefined\writestring \else + + \unexpanded\def\writestring{\immediate\write\statuswrite} + \unexpanded\def\writeline {\writestring{}} + +\fi + +\unexpanded\def\normalwritestatus#1#2% + {\writestring{\expandafter\syst_helpers_split_status_yes\expandafter\statuswidth#1% + \space\space\space\space\space\space\space + \space\space\space\space\space\space\space + \space\space\space\space\space\space\end + \space:\space#2}} + +\def\syst_helpers_split_status_yes#1#2% + {\ifcase#1 \expandafter\syst_helpers_split_status_nop\fi#2% + \expandafter\syst_helpers_split_status_yes\expandafter{\the\numexpr#1+\minusone\relax}} + +\def\syst_helpers_split_status_nop#1\end + {} + +%D \macros +%D {immediatemessage} +%D +%D A fully expandable message: + +\let\immediatemessage\clf_immediatemessage % {} mandate + +%D \macros +%D {rawgetparameters} +%D +%D A raw and dirty alternative for \type {\getparameters}; no checking is done! + +\unexpanded\def\rawsetparameter#1=#2,% + {\if]#1\else + \expandafter\def\csname\rawparameterprefix#1\endcsname{#2}% + \expandafter\rawsetparameter + \fi} + +\unexpanded\def\rawgetparameters[#1][#2% some 5-10% faster + {\ifx#2]% test is needed, else bomb on [#1][] + \expandafter\gobbleoneargument + \else + \def\rawparameterprefix{#1}% + \expandafter\dorawgetparameters + \fi#2} + +\def\dorawgetparameters#1]% + {\expandafter\rawsetparameter#1,]=,} + +%D \macros +%D {doglobal, +%D redoglobal,dodoglobal,resetglobal} +%D +%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and +%D some other modules to enforce a user specified \type {\doglobal} action. The last +%D and often only global assignment in a macro is done with \type {\dodoglobal}, but +%D all preceding ones with \type {\redoglobal}. When using only alternatives, one +%D can reset this mechanism with \type {\resetglobal}. + +\unexpanded\def\resetglobal + {\let\redoglobal\relax + \let\dodoglobal\relax} + +\resetglobal + +\unexpanded\def\doglobal + {\ifx\redoglobal\relax + \let\redoglobal\global + \let\dodoglobal\syst_helpers_dodo_global + \fi} + +\def\syst_helpers_dodo_global + {\resetglobal\global} + +\def\saveglobal + {\let\syst_helpers_dodo_global\dodoglobal + \let\syst_helpers_redo_global\redoglobal} + +\def\restoreglobal + {\let\redoglobal\syst_helpers_redo_global + \let\dodoglobal\syst_helpers_dodo_global} + +%D A very useful application of this macro is \type {\newif}, \TEX's fake boolean +%D type. Not being a primitive, \type {\global} hopelessly fails here. But a slight +%D adaption of Knuth's original macro permits: +%D +%D \starttyping +%D \doglobal\newif\iftest +%D \stoptyping +%D +%D Of course one can still say: +%D +%D \starttyping +%D \global\testtrue +%D \global\testfalse +%D \stoptyping +%D +%D Apart from the prefixes, a few more \type {\expandafters} are needed: + +% \unexpanded\def\newif#1% uses the original plain \@if +% {\privatescratchcounter\escapechar +% \escapechar\minusone +% \expandafter\expandafter\expandafter +% \redoglobal\expandafter\expandafter\expandafter +% \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}% +% \expandafter\expandafter\expandafter +% \redoglobal\expandafter\expandafter\expandafter +% \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}% +% \dodoglobal\@if#1{false}% +% \escapechar\privatescratchcounter} + +\normalprotected\def\newif#1% see syst-ini.mkiv + {\let\new_if_saved\newif + \let\newif\new_if_check + \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }% + \expandafter\redoglobal\expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}% + \dodoglobal\csname\expandafter\newif\csstring#1false\endcsname + \let\newif\new_if_saved} + +%D Also new: + +\unexpanded\def\define#1% + {\ifdefined#1% + \message{[\noexpand#1is already defined]}% + \unexpanded\expandafter\def\expandafter\gobbleddefinition + \else + \unexpanded\expandafter\def + \fi#1} + +\unexpanded\def\redefine#1% + {\ifdefined#1% + \message{[\noexpand#1is redefined]}% + \fi + \unexpanded\def#1} + +\unexpanded\def\definemacro#1% + {\ifdefined#1% + \message{[\noexpand#1is already defined]}% + \unexpanded\expandafter\def\expandafter\gobbleddefinition + \else + \unexpanded\expandafter\def + \fi#1} + +% \define\hans{hans} +% \redefine\hans{hans} +% \define\hans#1[]#2#3{hans} + +%D The next variant fits nicely in the setups syntax: +%D +%D \starttyping +%D \starttexdefinition bagger [#1] #2 +%D oeps +%D #1 +%D oeps +%D \stoptexdefinition +%D +%D \bagger [a] {b} +%D \stoptyping + +% \starttexdefinition test +% oeps +% \stoptexdefinition +% +% [\test] + +\def\s!unexpanded{unexpanded} + +\bgroup \obeylines + +\glet\stoptexdefinition\relax + +\unexpanded\gdef\starttexdefinition% + {\bgroup% + \obeylines% + \syst_helpers_start_tex_definition} + +\gdef\syst_helpers_start_tex_definition#1 + {\catcode\endoflineasciicode\ignorecatcode% + \clf_texdefinition_one{#1}} + +\gdef\dostarttexdefinition#1\stoptexdefinition% + {\egroup% + \clf_texdefinition_two{#1}} + +\egroup + +% \unexpanded\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace + +\unexpanded\def\texdefinition#1{\begincsname#1\endcsname} + +% This is a first variant, more might be added: + +\unexpanded\def\starttexcode{\unprotect} +\unexpanded\def\stoptexcode {\protect} + +%D \macros +%D {newcounter, +%D increment,decrement} +%D +%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we +%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type +%D {\increment}. +%D +%D \starttyping +%D \increment(\counter,20) +%D \increment(\counter,-4) +%D \increment(\counter) +%D \increment\counter +%D \stoptyping +%D +%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17 +%D and~18. Of course there is also the complementary command \type {\decrement}. +%D +%D Global assignments are possible too, using \type{\doglobal}: +%D +%D \starttyping +%D \doglobal\increment\counter +%D \stoptyping +%D +%D When \type {\counter} is undefined, it's value is initialized at~0. It is +%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that +%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does +%D not accept undefined macro's. The \COUNTER\ in our example can for instance be +%D defined with: +%D +%D \starttyping +%D \newcounter\counter +%D \stoptyping +%D +%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of +%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In +%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the +%D bottleneck in the processing of a text. Apart from some other incompatilities we +%D want to mention a pitfal when using \type {\ifnum}. +%D +%D \starttyping +%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi +%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi +%D \stoptyping +%D +%D In the first test, \TEX\ continues it's search for the second number after +%D reading \type {\pseudocounter}, while in the second test, it stops reading after +%D having encountered a real one. Tests like the first one therefore can give +%D unexpected results, for instance execution of \type {\doif} even if both numbers +%D are unequal. + +\def\zerocountervalue{0} + +\unexpanded\def\newcounter#1% + {\dodoglobal\let#1\zerocountervalue} + +%D Nowadays we don't mind a few more tokens if we can gain a bit of speed. + +\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\plusone \relax}} +\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\minusone\relax}} + +\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}} +\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}} + +\def\syst_helpers_do_do_increment(#1% + {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}% + \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}% + \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop} + +\def\syst_helpers_do_do_decrement(#1% + {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}% + \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}% + \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop} + +\unexpanded\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment} +\unexpanded\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement} + +\unexpanded\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}} +\unexpanded\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}} + +\unexpanded\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname} +\unexpanded\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname} + +%D \macros +%D {newsignal} +%D +%D When writing advanced macros, we cannot do without signaling. A signal is a small +%D (invisible) kern or penalty that signals the next macro that something just +%D happened. This macro can take any action depending on the previous signal. +%D Signals must be unique and the next macro takes care of that. +%D +%D \starttyping +%D \newsignal\somesignal +%D \stoptyping +%D +%D Signals old dimensions and can be used in skips, kerns and tests like \type +%D {\ifdim}. + +\newdimen\maximumsignal % step is about 0.00025pt + +\unexpanded\def\newsignal#1% + {\ifdefined#1\else + \advance\maximumsignal 2\scaledpoint % to be save in rounding + \edef#1{\the\maximumsignal}% + \fi} + +%D \macros +%D {strippedcsname} +%D +%D The next macro can be very useful when using \type {\csname} like in: +%D +%D \starttyping +%D \csname if\strippedcsname\something\endcsname +%D \stoptyping + +\let\checkedstrippedcsname\csstring + +%D \macros +%D {savenormalmeaning} +%D +%D We will use this one in: + +\unexpanded\def\savenormalmeaning#1% + {\ifcsname normal\csstring#1\endcsname \else + \expandafter\let\csname normal\csstring#1\endcsname#1% + \fi} + +%D \macros +%D {dorecurse,recurselevel,recursedepth, +%D dostepwiserecurse} +%D +%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its +%D recursion engine is quite unique. We therefore identify the for||looping macros +%D by this method. The most simple alternative is the one that only needs a number. +%D +%D \starttyping +%D \dorecurse {n} {whatever we want} +%D \stoptyping +%D +%D This macro can be nested without problems and therefore be used in situations +%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of +%D the counter is available in \type {\recurselevel}, before as well as after the +%D \typ {whatever we wat} stuff. +%D +%D \starttyping +%D \dorecurse % inner loop +%D {10} +%D {\recurselevel: % outer value +%D \dorecurse % inner loop +%D {\recurselevel} % outer value +%D {\recurselevel} % inner value +%D \dorecurse % inner loop +%D {\recurselevel} % outer value +%D {\recurselevel} % inner value +%D \endgraf} +%D \stoptyping +%D +%D In this example the first, second and fourth \type {\recurselevel} concern the +%D outer loop, while the third and fifth one concern the inner loop. The depth of +%D the nesting is available for inspection in \type {\recursedepth}. +%D +%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real +%D \COUNTERS\ are hidden from the user because we don't want any interference. + +\newcount\outerrecurse +\newcount\innerrecurse + +\def\recursedepth{\the\outerrecurse} +\def\recurselevel{0} + +\let\syst_helpers_stepwise_next\relax + +\installsystemnamespace{recurseindex} +\installsystemnamespace{recurseaction} + +\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#4}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \ifnum#3>\zerocount\relax + \ifnum#2<#1\relax + \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit + \else + \let\syst_helpers_stepwise_next\syst_helpers_stepwise_recurse + \fi + \orelse\ifnum#3<\zerocount\relax + \ifnum#1<#2\relax + \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit + \else + \let\syst_helpers_stepwise_next\syst_helpers_stepwise_reverse + \fi + \else + \let\syst_helpers_stepwise_next\syst_helpers_stepwise_exit + \fi\normalexpanded{\syst_helpers_stepwise_next{\number#1}{\number#2}{\number#3}}} + +\unexpanded\def\syst_helpers_stepwise_recurse#1#2#3% from to step + {\ifnum#1>#2\relax + \expandafter\syst_helpers_stepwise_recurse_nop + \else + \def\recurselevel{#1}% + \doubleexpandafter\syst_helpers_stepwise_recurse_yes\expandafter + \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}} + +\unexpanded\def\syst_helpers_recurse_content + {\csname\??recurseaction\the\outerrecurse\endcsname} + +\unexpanded\def\syst_helpers_stepwise_recurse_yes + {\syst_helpers_recurse_content + \syst_helpers_stepwise_recurse} + +\unexpanded\def\syst_helpers_stepwise_reverse#1#2#3% from to step + {\ifnum#1<#2\relax + \expandafter\syst_helpers_stepwise_recurse_nop + \else + \def\recurselevel{#1}% + \innerrecurse#1\relax + \advance\innerrecurse#3\relax + \doubleexpandafter\syst_helpers_stepwise_reverse_yes\expandafter + \fi\expandafter{\the\innerrecurse}{#2}{#3}} + +\unexpanded\def\syst_helpers_stepwise_reverse_yes + {\syst_helpers_recurse_content + \syst_helpers_stepwise_reverse} + +\unexpanded\def\syst_helpers_stepwise_exit + {\syst_helpers_stepwise_recurse_nop\relax} + +\unexpanded\def\syst_helpers_stepwise_recurse_nop#1#2#3#4% + {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse\minusone} + +\unexpanded\def\dorecurse#1% + {\dostepwiserecurse\plusone{#1}\plusone} + +\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse) + {\ifnum#1>\zerocount + #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}% + \fi} + +%D As we can see here, the simple command \type{\dorecurse} is a special case of the +%D more general: +%D +%D \starttyping +%D \dostepwiserecurse {from} {to} {step} {action} +%D \stoptyping +%D +%D This commands accepts positive and negative steps. Illegal values are handles as +%D good as possible and the macro accepts numbers and \COUNTERS. +%D +%D \starttyping +%D \dostepwiserecurse {1} {10} {2} {...} +%D \dostepwiserecurse {10} {1} {-2} {...} +%D \stoptyping +%D +%D Because the simple case is used often, we implement it more efficiently: + +\unexpanded\def\dorecurse#1% + {\ifcase#1\relax + \expandafter\gobbletwoarguments + \or + \expandafter\syst_helpers_recurse_y + \else + \expandafter\syst_helpers_recurse_x + \fi{#1}} + +\unexpanded\def\syst_helpers_recurse_x#1#2% + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#2}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}} + +\unexpanded\def\syst_helpers_recurse_y#1#2% + {\global\advance\outerrecurse \plusone + \expandafter\glet\csname\??recurseindex\the\outerrecurse\endcsname\recurselevel + \let\recurselevel\!!plusone + #2% + \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse \minusone} + +\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to + {\ifnum#1>#2\relax + \expandafter\syst_helpers_recurse_indeed_nop + \else + \def\recurselevel{#1}% + \doubleexpandafter\syst_helpers_recurse_indeed_yes + \fi\expandafter{\the\numexpr\recurselevel+\plusone\relax}{#2}} + +\unexpanded\def\syst_helpers_recurse_indeed#1#2% from to + {\ifnum#1>#2\relax + \expandafter\syst_helpers_recurse_indeed_nop + \else + \def\recurselevel{#1}% + \innerrecurse#1\advance\innerrecurse\plusone + \doubleexpandafter\syst_helpers_recurse_indeed_yes + \fi\expandafter{\the\innerrecurse}{#2}} + +\unexpanded\def\syst_helpers_recurse_indeed_yes + {\syst_helpers_recurse_content + \syst_helpers_recurse_indeed} + +\unexpanded\def\syst_helpers_recurse_indeed_nop#1#2#3% + {\expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse \minusone } + +%D \macros +%D {dowith} +%D +%D Here's a loop over whatever is in a list: +%D +%D \starttyping +%D \dowith{a,b,c}{[#1]} +%D \stoptyping + +\unexpanded\def\dowith#1#2% + {\def\syst_helpers_with##1{#2}% + \normalexpanded{\processcommalist[#1]}\syst_helpers_with} + +%D \macros +%D {doloop,exitloop} +%D +%D Sometimes loops are not determined by counters, but by (a combinations of) +%D conditions. We therefore implement a straightforward loop, which can only be left +%D when we explictly exit it. Nesting is supported. First we present a more +%D extensive alternative. +%D +%D \starttyping +%D \doloop +%D {Some kind of typesetting punishment \par +%D \ifnum\pageno>100 \exitloop \fi} +%D \stoptyping +%D +%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}. + +\let\endofloop\donothing % maybe \syst_helpers_loop_end + +\unexpanded\def\doloop#1% + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname{#1}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \let\endofloop\syst_helpers_loop + \syst_helpers_loop1} % no \plusone else \recurselevel wrong + +\unexpanded\def\syst_helpers_loop#1% + {\def\recurselevel{#1}% + \expandafter\syst_helpers_loop_yes\expandafter{\the\numexpr\recurselevel+\plusone\relax}} + +\unexpanded\def\syst_helpers_loop_yes + {\syst_helpers_recurse_content + \endofloop} + +\unexpanded\def\syst_helpers_loop_nop#1% + {\let\endofloop\syst_helpers_loop % new, permits nested \doloop's + \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse\minusone} + +\unexpanded\def\exitloop % \exitloop quits at end + {\let\endofloop\syst_helpers_loop_nop} + +\unexpanded\def\exitloopnow#1\endofloop % \exitloopnow quits directly + {\syst_helpers_loop_nop} + +%D The loop is executed at least once, so beware of situations +%D like: +%D +%D \starttyping +%D \doloop {\exitloop some commands} +%D \stoptyping +%D +%D It's just a matter of putting the text into the \type {\if} statement that should +%D be there anyway, like in: +%D +%D \starttyping +%D \doloop {\ifwhatever \exitloop \else some commands\fi} +%D \stoptyping +%D +%D You can also quit a loop immediately, by using \type +%D {\exitloopnow} instead. Beware, this is more sensitive +%D for conditional errors. + +%D Krzysztof Leszczynski suggested to provide access to the level by means of a +%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and +%D the less favoured depth as \type {#2}. The intended usage is: +%D +%D \starttyping +%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]} +%D +%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test +%D +%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3] +%D \stoptyping +%D +%D Since the hashed arguments are expanded, we don't need tricky expansion here. +%D +%D \starttyping +%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}} +%D \stoptyping + +\def\syst_helpers_recurse_content + {\csname\??recurseaction\the\outerrecurse\expandafter\expandafter\expandafter\endcsname + \expandafter\expandafter\expandafter{\expandafter\recurselevel\expandafter}\expandafter{\the\outerrecurse}} + +\unexpanded\def\syst_helpers_recurse_x#1#2% + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}} + +\unexpanded\def\syst_helpers_recurse_y#1#2% + {\global\advance\outerrecurse \plusone + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \let\recurselevel\!!plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#2}% + \syst_helpers_recurse_content + \expandafter\let\expandafter\recurselevel\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse \minusone} + +\unexpanded\def\doloop#1% + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#1}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \let\endofloop\syst_helpers_loop + \syst_helpers_loop1} % no \plusone else \recurselevel wrong + +\installsystemnamespace{recursestepwise} + +\unexpanded\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 + {\global\advance\outerrecurse \plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1##2{#4}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recurselevel + \csname\??recursestepwise + % we need the x in order to avoid the \relax that tex adds + \ifnum#3>\zerocount + \ifnum#2<#1x\else d\fi + \orelse\ifnum#3<\zerocount + \ifnum#1<#2x\else r\fi + \fi + \expandafter\endcsname\normalexpanded{{\number#1}{\number#2}{\number#3}}} + % \expandafter\endcsname\expandafter{\number#1\expandafter}\expandafter{\number#2\expandafter}\expandafter{\number#3}} + +\letvalue{\??recursestepwise x}\syst_helpers_stepwise_exit +\letvalue{\??recursestepwise d}\syst_helpers_stepwise_recurse +\letvalue{\??recursestepwise r}\syst_helpers_stepwise_reverse + +\newcount\fastloopindex +\newcount\fastloopfinal + +\let\m_syst_helpers_fast_loop_cs\relax + +\unexpanded\def\dofastloopcs#1% + {\fastloopfinal#1\relax + \ifcase\fastloopfinal + \expandafter\gobbleoneargument + \else + \expandafter\syst_helpers_fast_loop_cs + \fi} + +\unexpanded\def\syst_helpers_fast_loop_cs#1% + {\let\m_syst_helpers_fast_loop_cs#1% + \fastloopindex\plusone + \syst_helpers_fast_loop_cs_step} + +\unexpanded\def\syst_helpers_fast_loop_cs_step + {\ifnum\fastloopindex>\fastloopfinal + \let\m_syst_helpers_fast_loop_cs\relax + \else + \m_syst_helpers_fast_loop_cs + \advance\fastloopindex\plusone + \expandafter\syst_helpers_fast_loop_cs_step + \fi} + +% Helper: + +\unexpanded\def\resetrecurselevel{\let\recurselevel\!!zerocount} + +\let\recurselevel\!!zerocount + +% \appendtoks \resetrecurselevel \to \everydump + +%D \macros +%D {doloopoverlist} +%D +%D \starttyping +%D \doloopoverlist {red,green,blue} { +%D \setuppalet[\recursestring] +%D \doloopoverlist {light,normal,dark} { +%D \blackrule[color=\recursestring,width=20cm,height=2cm,depth=0cm]\par +%D } +%D } +%D \stoptyping +%D +%D or: +%D +%D \starttyping +%D \doloopoverlist {red,green,blue} { +%D \setuppalet[#1] +%D \doloopoverlist {light,normal,dark} { +%D \blackrule[color=##1,width=20cm,height=2cm,depth=0cm]\par +%D } +%D } +%D \stoptyping + +\unexpanded\def\doloopoverlist#1#2% + {\global\advance\outerrecurse\plusone + \expandafter\gdef\csname\??recurseaction\the\outerrecurse\endcsname##1{\edef\recursestring{##1}#2}% + \expandafter\glet\csname\??recurseindex \the\outerrecurse\endcsname\recursestring + \normalexpanded{\processcommalist[#1]{\expandafter\noexpand\csname\??recurseaction\the\outerrecurse\endcsname}}% + \expandafter\let\expandafter\recursestring\csname\??recurseindex\the\outerrecurse\endcsname + \global\advance\outerrecurse\minusone} + +%D \macros +%D {newevery,everyline,EveryLine,EveryPar} +%D +%D Lets skip to something quite different. It's common use to use \type {\everypar} +%D for special purposes. In \CONTEXT\ we use this primitive for locating sidefloats. +%D This means that when user assignments to \type {\everypar} can interfere with +%D those of the package. We therefore introduce \type {\EveryPar}. +%D +%D The same goes for \type {\EveryLine}. Because \TEX\ offers no \type {\everyline} +%D primitive, we have to call for \type {\everyline} when we are working on a line +%D by line basis. Just by calling \type {\EveryPar{}} and \type {\EveryLine{}} we +%D restore the old situation. + +% \dorecurse{2}{ +% \expanded{\everypar{before \recurselevel\space}} +% \EveryPar{x } [before \recurselevel\space x] \par +% \EveryPar{y } [before \recurselevel\space y] \par +% \EveryPar{} [before \recurselevel] \par +% \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par +% \EveryPar{y } \everypar{before } [before] \par +% } + +\installsystemnamespace{extraevery} + +\unexpanded\def\newevery#1#2% + {\ifx#1\everypar\else\newtoks#1\fi% we test for redefinition elsewhere + \ifx#2\relax\orelse\ifdefined#2\else + \expandafter\newtoks\csname\??extraevery\csstring#1\endcsname + \edef#2{\syst_helpers_every#1\csname\??extraevery\csstring#1\endcsname}% + \fi} + +\unexpanded\def\syst_helpers_every#1#2% + {\removetoks\the#2\from#1% + \appendtoks\the#2\to #1% + #2} + +%D This one permits definitions like: + +\newevery \everypar \EveryPar % we get a warning which is ok +\newevery \everyline \EveryLine + +%D and how about: + +\newtoks \neverypar + +\unexpanded\def\forgeteverypar + {\everypar{\the\neverypar}} + +%D Which we're going to use indeed! When the second argument equals \type {\relax}, +%D the first token list is created unless it is already defined. +%D +%D Technically spoken we could have used the method we are going to present in the +%D visual debugger. First we save the primitive \type{\everypar}: +%D +%D \starttyping +%D \let\normaleverypar=\everypar +%D \stoptyping +%D +%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that +%D \type{\everypar} is no longer a primitive but something like \type{\toks44}. +%D +%D \starttyping +%D \newtoks\everypar +%D \stoptyping +%D +%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we +%D are ready to assign some tokens to this internally known and used \TOKENLIST. +%D +%D \starttyping +%D \normaleverypar={all the things the system wants to do \the\everypar} +%D \stoptyping +%D +%D Where the user can provide his own tokens to be expanded every time he expects +%D them to expand. +%D +%D \starttyping +%D \everypar={something the user wants to do} +%D \stoptyping +%D +%D We don't use this method because it undoubtly leads to confusing situations, +%D especially when other packages are used, but it's this kind of tricks that make +%D \TEX\ so powerful. + +%D \macros +%D {convertargument,convertcommand,convertvalue} +%D +%D Some persistent experimenting led us to the next macro. This macro converts a +%D parameter or an expanded macro to it's textual meaning. +%D +%D \starttyping +%D \convertargument ... \to \command +%D \stoptyping +%D +%D For example, +%D +%D \starttyping +%D \convertargument{one \two \three{four}}\to\ascii +%D \stoptyping +%D +%D The resulting macro \type{\ascii} can be written to a file or the terminal +%D without problems. In \CONTEXT\ we use this macro for generating registers and +%D tables of contents. +%D +%D The second conversion alternative accepts a command: +%D +%D \starttyping +%D \convertcommand\command\to\ascii +%D \stoptyping +%D +%D Both commands accept the prefix \type{\doglobal} for global assignments. + +\unexpanded\def\convertvalue#1\to + {\expandafter\convertcommand\csname#1\endcsname\to} + +\unexpanded\def\defconvertedvalue#1#2% less sensitive for \to + {\expandafter\defconvertedcommand\expandafter#1\csname#2\endcsname} + +%D \macros +%D {doifassignmentelse} +%D +%D A lot of \CONTEXT\ commands take optional arguments, for instance: +%D +%D \starttyping +%D \dothisorthat[alfa,beta] +%D \dothisorthat[first=foo,second=bar] +%D \dothisorthat[alfa,beta][first=foo,second=bar] +%D \stoptyping +%D +%D Although a combined solution is possible, we prefer a seperation. The next +%D command takes care of propper handling of such multi||faced commands. +%D +%D \starttyping +%D \doifassignmentelse {...} {then ...} {else ...} +%D \stoptyping + +\def\syst_helpers_check_if_assignment_else#1=#2#3^^^^0004{\if#2^^^^0003}% +\def\syst_helpers_check_else_assignment_if#1=#2#3^^^^0004{\unless\if#2^^^^0003}% + +\unexpanded\def\doifelseassignment#1% + {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\unexpanded\def\doifelseassignmentcs#1#2#3% + {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% + \expandafter#3% + \else + \expandafter#2% + \fi} + +\let\doifassignmentelse \doifelseassignment +\let\doifassignmentelsecs\doifelseassignmentcs + +\newif\ifassignment + +\unexpanded\def\docheckassignment#1% + {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004% + \assignmentfalse + \else + \assignmenttrue + \fi} + +%D These can be used for cases where we want less tracing noise. + +\unexpanded\def\validassignment#1% + {\expandafter\syst_helpers_check_else_assignment_if\detokenize{#1}=^^^^0003^^^^0003^^^^0004} + +\unexpanded\def\novalidassignment#1% + {\expandafter\syst_helpers_check_if_assignment_else\detokenize{#1}=^^^^0003^^^^0003^^^^0004} + +%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far +%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}. +%D This macro is more robust than the pure \TEX\ one, something I found out when +%D primitives like \type {\jobname} were fed (or something undefined). + +\unexpanded\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}} +\unexpanded\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok + +\unexpanded\def\defconvertedargument #1#2{\edef#1{\detokenize{#2}}} +\unexpanded\def\defconvertedcommand #1#2{\edef#1{\detokenize\expandafter{#2}}} +\unexpanded\def\edefconvertedargument#1#2{\edef#1{#2}% + \edef#1{\detokenize\expandafter{#1}}} +\unexpanded\def\gdefconvertedargument#1#2{\xdef#1{\detokenize{#2}}} +\unexpanded\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\expandafter{#2}}} +\unexpanded\def\xdefconvertedargument#1#2{\xdef#1{#2}% + \xdef#1{\detokenize\expandafter{#1}}} + +%D When you try to convert a primitive command, you'll find out that the \ETEX\ +%D method fails on for instance \type {\jobname} in the sense that it returns the +%D filename instead of just \type {\jobname}. So far this does not give real +%D problems. + +%D This is typically a macro that one comes to after reading the \TEX book +%D carefully. Even then, the definite solution was found after rereading the \TEX +%D book. The first implementation was: +%D +%D \starttyping +%D \def\doconvertargument#1->#2\\\\{#2} +%D \stoptyping +%D +%D The \type {-}, the delimiter \type {\\\\} and the the second argument are +%D completely redundant. + +%D \macros +%D {showvalue} +%D +%D Ahandy macro, for testing purposes only: + +\unexpanded\def\showvalue#1% + {\ifcsname#1\endcsname + \expandafter\show\csname#1\endcsname + \else + \show\undefined + \fi} + +%D \macros +%D {doifmeaningelse} +%D +%D We can use both commands in testing, but alas, not all meanings expand to +%D something \type {->}. This is no problem in the \ETEX\ implementation, but since +%D we want compatibility, we need: +%D +%D \starttyping +%D \doifmeaningelse {\next} {\something} {true} {false} +%D \stoptyping +%D +%D Watch the one level expansion of the second argument. + +\unexpanded\def\doifelsemeaning#1#2% + {\edef\m_syst_string_one{\normalmeaning#1}% + \def \m_syst_string_two{#2}% + \edef\m_syst_string_two{\normalmeaning\m_syst_string_two}% + \ifx\m_syst_string_one\m_syst_string_two + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifmeaningelse\doifelsemeaning + +%D \macros +%D {doifsamestringselse,doifsamestring,doifnotsamestring} +%D +%D The next comparison macro converts the arguments into expanded strings. This +%D command can be used to compare for instance \type {\jobname} with a name stored +%D in a macro. +%D +%D \starttyping +%D \doifelse {\jobname}{oeps}{YES}{NO} +%D \doifsamestringelse{\jobname}{oeps}{YES}{NO} +%D \stoptyping + +\def\syst_helpers_if_samestring_else#1#2#3#4% + {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#3}}}% + \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#4}}}% + \ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi} + +\unexpanded\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments} +\unexpanded\def\doifsamestring {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument } +\unexpanded\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument \firstofoneargument } + +\let\doifsamestringelse\doifelsesamestring + +%D \macros +%D {ConvertToConstant,ConvertConstantAfter} +%D +%D When comparing arguments with a constant, we can get into trouble when this +%D argument consists of tricky expandable commands. One solution for this is +%D converting the argument to a string of unexpandable characters. To make +%D comparison possible, we have to convert the constant too. +%D +%D \starttyping +%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...} +%D \stoptyping +%D +%D This construction is only needed when the first argument can give troubles. +%D Misuse can slow down processing. +%D +%D \starttyping +%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...} +%D \ConvertToConstant\doifelse{alfa} {\c!alfa}{...}{...} +%D \ConvertToConstant\doifelse{alfa} {alfa} {...}{...} +%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...} +%D \stoptyping +%D +%D In examples~2 and~3 both arguments equal, in~1 and~4 they differ. + +\unexpanded\def\ConvertToConstant#1#2#3% + {\edef\m_syst_string_one{\expandafter\detokenize\expandafter{#2}}% + \edef\m_syst_string_two{\expandafter\detokenize\expandafter{#3}}% + #1{\m_syst_string_one}{\m_syst_string_two}} + +%D When the argument \type{#1} consists of commands, we had better use +%D +%D \starttyping +%D \ConvertConstantAfter\processaction[#1][...] +%D \ConvertConstantAfter\doifelse{#1}{\v!something}{}{} +%D \stoptyping +%D +%D This commands accepts things like: +%D +%D \starttyping +%D \v!constant +%D constant +%D \hbox to \hsize{\rubish} +%D \stoptyping +%D +%D As we will see in the core modules, this macro permits constructions like: +%D +%D \starttyping +%D \setupfootertexts[...][...] +%D \setupfootertexts[margin][...][...] +%D \setupfootertexts[\v!margin][...][...] +%D \stoptyping +%D +%D where \type {...} can be anything legally \TEX. + +\unexpanded\def\CheckConstantAfter#1#2% + {\expandafter\convertargument\v!prefix!\to\ascii + \convertargument#1\to#2\relax + \doifelseinstring\ascii{#2} + {\expandafter\convertargument#1\to#2} + {}} + +\unexpanded\def\ConvertConstantAfter#1#2#3% + {\CheckConstantAfter{#2}\asciia + \CheckConstantAfter{#3}\asciib + #1{\asciia}{\asciib}} + +%D \macros +%D {assignifempty} +%D +%D We can assign a default value to an empty macro using: +%D +%D \starttyping +%D \assignifempty \macros {default value} +%D \stoptyping +%D +%D We don't explicitly test if the macro is defined. + +\unexpanded\def\assignifempty#1#2% can be sped up + {\doifsomething{#1}{\def#1{#2}}} % {\doifnot{#1}{}{\def#1{#2}}} + +%D \macros +%D {gobbleuntil,grabuntil,gobbleuntilrelax, +%D processbetween,processuntil} +%D +%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling +%D macros. +%D +%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions. +%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D +%D \starttyping +%D \unexpanded\def\startcommand#1\stopcommand% +%D {... #1 ...} +%D \stoptyping +%D +%D In many cases the \type {\start}||\type {\stop} pair is defined at format +%D generation time or during a job. This means that we cannot hardcode the \type +%D {\stop} criterium. Only after completely understanding \type {\csname} and \type +%D {\expandafter} I was able to to implement a solution, starting with: +%D +%D \starttyping +%D \grabuntil{stop}\command +%D \stoptyping +%D +%D This commands executes, after having encountered \type {\stop} the command \type +%D {\command}. This command receives as argument the text preceding the \type +%D {\stop}. This means that: +%D +%D \starttyping +%D \unexpanded\def\starthello% +%D {\grabuntil{stophello}\message} +%D +%D \starthello Hello world!\stophello +%D \stoptyping +%D +%D results in: \type{\message{Hello world!}}. + +\let\syst_helpers_grab_indeed\relax + +\unexpanded\def\syst_helpers_grab#1#2% + {\def\syst_helpers_grab_indeed##1#1{#2{##1}}\syst_helpers_grab_indeed} + +\unexpanded\def\grabuntil#1% + {\expandafter\syst_helpers_grab\expandafter{\csname#1\endcsname}} + +%D The next command build on this mechanism: +%D +%D \starttyping +%D \processbetween{string}\command +%D \stoptyping +%D +%D Here: +%D +%D \starttyping +%D \processbetween{hello}\message +%D \starthello Hello again!\stophello +%D \stoptyping +%D +%D leads to: \type{\message{Hello again!}}. The command +%D +%D \starttyping +%D \gobbleuntil{sequence} +%D \stoptyping +%D +%D is related to these commands. This one simply throws away +%D everything preceding \type{\command}. + +\let\syst_helpers_gobble_indeed\relax + +\unexpanded\def\processbetween#1#2% + {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}} + +\unexpanded\def\gobbleuntil#1% + {\def\syst_helpers_gobble_indeed##1#1{}\syst_helpers_gobble_indeed} + +\unexpanded\def\gobbleuntilrelax#1\relax + {} + +%D The next one simply expands the pickup up tokens. +%D +%D \starttyping +%D \processuntil{sequence} +%D \stoptyping + +\let\syst_helpers_until_indeed\relax + +\unexpanded\def\processuntil#1% + {\def\syst_helpers_until_indeed##1#1{##1}\syst_helpers_until_indeed} + +%D \macros +%D {groupedcommand} +%D +%D Commands often manipulate argument as in: +%D +%D \starttyping +%D \def\doezomaarwat#1{....#1....} +%D \stoptyping +%D +%D A disadvantage of this approach is that the tokens that form \type{#1} are fixed +%D the the moment the argument is read in. Normally this is no problem, but for +%D instance verbatim environments adapt the \CATCODES\ of characters and therefore +%D are not always happy with already fixed tokens. +%D +%D Another problem arises when the argument is grouped not by \type {{}} but by +%D \type {\bgroup} and \type {\egroup}. Such an argument fails, because the \type +%D {\bgroup} is een as the argument (which is quite normal). +%D +%D The next macro offers a solution for both unwanted situations: +%D +%D \starttyping +%D \groupedcommand {before} {after} +%D \stoptyping +%D +%D Which can be used like: +%D +%D \starttyping +%D \def\cite% +%D {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}} +%D \stoptyping +%D +%D This command is equivalent to, but more 'robust' than: +%D +%D \starttyping +%D \def\cite#1% +%D {\rightquote\rightquote#1\leftquote\leftquote} +%D \stoptyping +%D +%D \starttyping +%D \def\rightword% +%D {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}} +%D +%D .......... \rightword{the right way} +%D \stoptyping +%D +%D Here \TEX\ typesets \type {\bf the right way} unbreakable at the end of the line. +%D The solution mentioned before does not work here. We also handle +%D +%D \starttyping +%D to be \bold{bold} or not, that's the question +%D \stoptyping +%D +%D and +%D +%D \starttyping +%D to be {\bold bold} or not, that's the question +%D \stoptyping +%D +%D This alternative checks for a \type {\bgroup} token first. The internal +%D alternative does not accept the box handling mentioned before, but further +%D nesting works all right. The extra \type {\bgroup}||\type {\egroup} is needed to +%D keep \type {\m_syst_helpers_handle_group_after} both into sight and local. + +\let\m_syst_helpers_handle_group_after \relax +\let\m_syst_helpers_handle_group_before\relax + +\unexpanded\def\syst_helpers_handle_group_nop + {\ifnum\currentgrouptype=\semisimplegroupcode + \expandafter\syst_helpers_handle_group_nop_a + \else + \expandafter\syst_helpers_handle_group_nop_b + \fi} + +\def\syst_helpers_handle_group_nop_a + {\begingroup + \aftergroup\m_syst_helpers_handle_group_a + \aftergroup\endgroup + \m_syst_helpers_handle_group_b} + +\def\syst_helpers_handle_group_nop_b + {\bgroup + \aftergroup\m_syst_helpers_handle_group_a + \aftergroup\egroup + \m_syst_helpers_handle_group_b} + +\unexpanded\def\syst_helpers_handle_group_normal + {\bgroup + \afterassignment\m_syst_helpers_handle_group_normal_before + \let\next=} + +\def\m_syst_helpers_handle_group_normal_before + {\bgroup + \m_syst_helpers_handle_group_b + \bgroup + \aftergroup\m_syst_helpers_handle_group_a + \aftergroup\egroup + \aftergroup\egroup} + +\unexpanded\def\syst_helpers_handle_group_simple% no inner group (so no kerning interference) + {\bgroup + \afterassignment\m_syst_helpers_handle_group_simple_before + \let\next=} + +\def\m_syst_helpers_handle_group_simple_before + {\bgroup + \aftergroup\m_syst_helpers_handle_group_simple_after + \m_syst_helpers_handle_group_b} + +\def\m_syst_helpers_handle_group_simple_after + {\m_syst_helpers_handle_group_a + \egroup}% + +\unexpanded\def\syst_helpers_handle_group_pickup% no inner group (so no kerning interference) + {\bgroup + \afterassignment\m_syst_helpers_handle_group_pickup_before + \let\next=} + +\def\m_syst_helpers_handle_group_pickup_before + {\bgroup + \aftergroup\m_syst_helpers_handle_group_a + \aftergroup\egroup + \aftergroup\m_syst_helpers_handle_group_p + \m_syst_helpers_handle_group_b} + +\unexpanded\def\syst_helpers_handle_group_nop_x + {\ifnum\currentgrouptype=\semisimplegroupcode + \begingroup + \aftergroup\endgroup + \else + \bgroup + \aftergroup\egroup + \fi + \m_syst_helpers_handle_group_b} + +\unexpanded\def\syst_helpers_handle_group_normal_x + {\bgroup + \afterassignment\m_syst_helpers_handle_group_normal_before_x + \let\next=} + +\def\m_syst_helpers_handle_group_normal_before_x + {\bgroup + \m_syst_helpers_handle_group_b + \bgroup + \aftergroup\egroup + \aftergroup\egroup} + +%D I considered it a nuisance that +%D +%D \starttyping +%D \color[green] +%D {as grass} +%D \stoptyping +%D +%D was not interpreted as one would expect. This is due to the fact that \type +%D {\futurelet} obeys blank spaces, and a line||ending token is treated as a blank +%D space. So the final implementation became: + +\unexpanded\def\groupedcommand#1#2% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} + +\unexpanded\def\groupedcommandcs#1#2% + {\let\m_syst_helpers_handle_group_b#1% + \let\m_syst_helpers_handle_group_a#2% + \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop} + +\unexpanded\def\simplegroupedcommand#1#2% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop} + +\unexpanded\def\pickupgroupedcommand#1#2#3% + {\def\m_syst_helpers_handle_group_b{#1}% + \def\m_syst_helpers_handle_group_a{#2}% + \def\m_syst_helpers_handle_group_p{#2}% + \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop} + +\unexpanded\def\triggergroupedcommand#1% + {\def\m_syst_helpers_handle_group_b{#1}% + \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} + +\unexpanded\def\triggergroupedcommandcs#1% + {\let\m_syst_helpers_handle_group_b#1% + \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x} + +%D Users should be aware of the fact that grouping can interfere with ones paragraph +%D settings that are executed after the paragraph is closed. One should therefore +%D explictly close the paragraph with \type {\par}, else the settings will be +%D forgotten and not applied. So it's: +%D +%D \starttyping +%D \def\BoldRaggedCenter% +%D {\groupedcommand{\raggedcenter\bf}{\par}} +%D \stoptyping + +%D \macros +%D {checkdefined} +%D +%D The bigger the system, the greater the change that user defined commands collide +%D with those that are part of the system. The next macro gives a warning when a +%D command is already defined. We considered blocking the definition, but this is +%D not always what we want. +%D +%D \starttyping +%D \checkdefined {category} {class} {command} +%D \stoptyping +%D +%D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion +%D is feasible, because \CONTEXT only defines lowcased macros. + +\unexpanded\def\showdefinederror#1#2% + {\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}} + +\unexpanded\def\checkdefined#1#2#3% + {\doifdefined{#3}{\showdefinederror{#2}{#3}}} + +%D \macros +%D {GotoPar,GetPar} +%D +%D Typesetting a paragraph in a special way can be done by first grabbing the +%D contents of the paragraph and processing this contents grouped. The next macro +%D for instance typesets a paragraph in boldface. +%D +%D \starttyping +%D \def\remark#1\par% +%D {\bgroup\bf#1\egroup} +%D \stoptyping +%D +%D This macro has to be called like +%D +%D \starttyping +%D \remark some text ... ending with \par +%D \stoptyping +%D +%D Instead of \type {\par} we can of course use an empty line. When we started +%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In +%D producing such simple formatted texts, we adopted an open layout, and when +%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped +%D and badly formatted source, it adds to confusion and sometimes introduces errors. +%D So we prefer: +%D +%D \starttyping +%D \remark +%D +%D some text ... ending with an empty line +%D \stoptyping +%D +%D We are going to implement a mechanism that allows such open specifications. The +%D definition of the macro handling \type {\remark} becomes: +%D +%D \starttyping +%D \def\remark% +%D {\BeforePar{\bgroup\bf}% +%D \AfterPar{\egroup}% +%D \GetPar} +%D \stoptyping +%D +%D A macro like \type {\GetPar} can be defined in several ways. The recent version, +%D the fourth one in a row, originally was far more complicated, but some +%D functionality has been moved to other macros. +%D +%D We start with the more simple but in some cases more appropriate alternative is +%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more +%D robust. On the other hand, \type {\AfterPar} is not supported. + +\newtoks\BeforePar +\newtoks\AfterPar + +\def\redowithpar\par + {\doifelsenextchar\par\redowithpar\dodowithpar}% + +\def\dowithpar#1#2% + {\def\dodowithpar##1\par{#1##1#2}% + \redowithpar\par} + +\def\redogotopar\par + {\doifelsenextchar\par\redogotopar\dodogotopar}% + +\def\dogotopar#1% + {\def\dodogotopar{#1}% + \redogotopar\par} + +\def\dogotoparcs#1% + {\let\dodogotopar#1% + \redogotopar\par} + +\unexpanded\def\GetPar + {\expanded + {\dowithpar + {\the\BeforePar + \BeforePar\emptytoks} + {\the\AfterPar + \BeforePar\emptytoks + \AfterPar\emptytoks}}} + +\unexpanded\def\GotoPar + {\expanded + {\dogotopar + {\the\BeforePar + \BeforePar\emptytoks}}} + +%D \macros +%D {dowithpargument,dowithwargument} +%D +%D The next macros are a variation on \type {\GetPar}. When macros expect an +%D argument, it interprets a grouped sequence of characters a one token. While this +%D adds to robustness and less ambiguous situations, we sometimes want to be a bit +%D more flexible, or at least want to be a bit more tolerant to user input. +%D +%D We start with a commands that acts on paragraphs. This +%D command is called as: +%D +%D \starttyping +%D \dowithpargument\command +%D \dowithpargument{\command ... } +%D \stoptyping +%D +%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The +%D commands responsible for these activities accept several alternative ways of +%D argument passing. In these examples, the \type {\par} can be omitted when an +%D empty line is present. +%D +%D \starttyping +%D \command{...} +%D \command ... \par +%D \command +%D {...} +%D \command +%D ... \par +%D \stoptyping + +\let\syst_helpers_next_par\relax +\let\syst_helpers_next_arg\relax + +\unexpanded\def\dowithpargument#1% + {\def\syst_helpers_next_par##1 \par{#1{##1}}% + \def\syst_helpers_next_arg##1{#1{##1}}% + \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}} + +%D The \type {p} in the previous command stands for paragraph. When we want to act +%D upon words we can use the \type{w} alternative. +%D +%D \starttyping +%D \dowithwargument\command +%D \dowithwargument{... \command ...} +%D \stoptyping +%D +%D The main difference bwteen two alternatives is in the handling of \type {\par}'s. +%D This time the space token acts as a delimiter. +%D +%D \starttyping +%D \command{...} +%D \command ... +%D \command +%D {...} +%D \command +%D ... +%D \stoptyping + +\let\syst_helpers_next_war\relax +\let\syst_helpers_next_arg\relax + +\unexpanded\def\dowithwargument#1% + {\def\syst_helpers_next_war##1 {#1{##1}}% + \def\syst_helpers_next_arg##1{#1{##1}}% + \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war} + +%D \macros +%D {dorepeat,dorepeatwithcommand} +%D +%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The +%D next alternative however, suits better some of the \CONTEXT\ interface commands. +%D +%D \starttyping +%D \dorepeat[n*\command] +%D \stoptyping +%D +%D The value of the used \COUNTER\ can be called within +%D \type{\command} by \type{\repeater}. +%D +%D A slightly different alternative is: +%D +%D \starttyping +%D \dorepeatwithcommand[n*{...}]\command +%D \stoptyping +%D +%D When we call for something like: +%D +%D \starttyping +%D \dorepeatwithcommand[3*{Hello}]\message +%D \stoptyping +%D +%D we get ourselves three \type {\message{Hello}} messages in a row. In both +%D commands, the \type {n*} is optional. When this specification is missing, the +%D command executes once. + +\unexpanded\def\dorepeatwithcommand[#1]% + {\syst_helpers_repeat_with_command#1*\empty*\relax} + +\def\syst_helpers_repeat_with_command#1*#2#3*#4\relax#5% + {\ifx#2\empty\syst_helpers_repeat_with_command_again[#1]#5\else\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5\fi} + +\def\syst_helpers_repeat_with_command_indeed#1#2#3#4% + {\ifx#2\empty % redundant but gives cleaner extensions + #4{#1}% + \orelse\ifnum#1<\zerocount + %\normalexpanded{\dorecurse{\number-\number#1}}{#4{-#2#3}}% + \dorecurse{-#1}{#4{-#2#3}}% + \orelse\ifx#2+% + \dorecurse{#1}{#4{#3}}% + \else + \dorecurse{#1}{#4{#2#3}}% + \fi} + +\def\syst_helpers_repeat_with_command_again[#1]#2% + {#2{#1}} + +%D The extension hook permits something like: +%D +%D \starttyping +%D \bgroup +%D +%D \catcode`\*=\superscriptcatcode +%D +%D \gdef\syst_helpers_repeat_with_command_again[#1]% +%D {\redodorepeatwithcommand#1*\empty*\relax} +%D +%D \gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5% +%D {\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5} +%D +%D \egroup +%D \stoptyping +%D +%D although one may wonder if changing the catcode of \type {*} is wise. + +%D \macros +%D {doifstringinstringelse} +%D +%D The next macro is meant for situations where both strings are macros. This save +%D some unneeded expansion. +%D +%D \starttyping +%D \def\doifstringinstringelse#1#2% +%D {\syst_helpers_do_if_in_string_else#1#2% +%D \expandafter\firstoftwoarguments +%D \else +%D \expandafter\secondoftwoarguments +%D \fi} +%D \stoptyping +%D +%D A bit faster is: + +\def\syst_helpers_if_instring_else_indeed#1% + {\if#1@% + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\def\doifelsestringinstring#1#2% + {\expandafter\def\expandafter\syst_helpers_if_instring_else\expandafter##\expandafter1#1##2##3^^^^0004% + {\syst_helpers_if_instring_else_indeed##2}% + \expandafter\expandafter\expandafter\syst_helpers_if_instring_else\expandafter#2#1@@^^^^0004} + +\let\doifstringinstringelse\doifelsestringinstring + +%D \macros +%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce, +%D doifintokselse,flushtoks,dotoks} +%D +%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are +%D more suitable for the user interface. Nevertheless we have: +%D +%D \starttyping +%D (\doglobal) \appendtoks ... \to\tokenlist +%D (\doglobal) \prependtoks ... \to\tokenlist +%D (\doglobal) \flushtoks\tokenlist +%D \dotoks\tokenlist +%D \stoptyping +%D +%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book. + +\newtoks\t_syst_helpers_scratch +\let \m_syst_helpers_scratch\empty + +\unexpanded\def\appendtoks#1\to#2% + {\ifx\dodoglobal\relax + \expandafter\toksapp + \else + \resetglobal + \expandafter\gtoksapp + \fi#2{#1}} + +\unexpanded\def\prependtoks#1\to#2% + {\ifx\dodoglobal\relax + \expandafter\tokspre + \else + \resetglobal + \expandafter\gtokspre + \fi#2{#1}} + +\def\syst_helpers_append_toks_indeed + {\ifx\dodoglobal\relax + \expandafter\toksapp + \else + \resetglobal + \expandafter\gtoksapp + \fi\m_syst_helpers_scratch\t_syst_helpers_scratch} + +\def\syst_helpers_prepend_toks_indeed + {\ifx\dodoglobal\relax + \expandafter\tokspre + \else + \resetglobal + \expandafter\gtokspre + \fi\m_syst_helpers_scratch\t_syst_helpers_scratch} + +\unexpanded\def\appendtoksonce#1\to#2% + {\let\m_syst_helpers_scratch#2% + \t_syst_helpers_scratch{#1}% + \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch + \donothing + \syst_helpers_append_toks_indeed} + +\unexpanded\def\prependtoksonce#1\to#2% + {\let\m_syst_helpers_scratch#2% + \t_syst_helpers_scratch{#1}% + \doifelseintoks\t_syst_helpers_scratch\m_syst_helpers_scratch + \donothing + \syst_helpers_prepend_toks_indeed} + +%D The test macro: + +\unexpanded\def\doifelseintoks#1#2% #1 en #2 zijn toks + {\edef\asciia{\detokenize\expandafter{\the#1}}% + \edef\asciib{\detokenize\expandafter{\the#2}}% + \doifelsestringinstring\asciia\asciib} + +\let\doifintokselse\doifelseintoks + +%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect +%D stuff piecewise, which is sometimes hard on mechanisms that grab content using +%D delimiters: +%D +%D \starttyping +%D \startcollecting +%D \startcollect \bTABLE \stopcollect +%D \startcollect \bTR \stopcollect +%D \startcollect \bTD \stopcollect +%D \startcollect foo\stopcollect +%D \startcollect \eTD \stopcollect +%D \startcollect \bTD \stopcollect +%D \startcollect bar\stopcollect +%D \startcollect \eTD \stopcollect +%D \startcollect \eTR \stopcollect +%D \startcollect \eTABLE \stopcollect +%D \stopcollecting +%D \stoptyping + +\newtoks \collectingtoks + +\unexpanded\def\startcollect #1\stopcollect {\toksapp \collectingtoks{#1}} +\unexpanded\def\startexpandedcollect#1\stopexpandedcollect{\etoksapp\collectingtoks{#1}} + +\unexpanded\def\startcollecting{\collectingtoks\emptytoks} +\unexpanded\def\stopcollecting {\the\collectingtoks} + +\unexpanded\def\collect {\toksapp \collectingtoks} +\unexpanded\def\collectexpanded{\etoksapp\collectingtoks} + +%D A nice one too: + +% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]} +% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]} +% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]} +% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]} +% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]} + +\unexpanded\def\removetoks#1\from#2% + {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004% + {\def\m_syst_string_one{##3}% + \ifx\m_syst_string_one\empty#2{##1}\else#2{##1##2}\fi}% + \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004} + +%D Also: + +\unexpanded\def\appendetoks#1\to#2% + {\ifx\dodoglobal\relax + \expandafter\etoksapp + \else + \resetglobal + \expandafter\xtoksapp + \fi#2{#1}} + +\unexpanded\def\prependetoks#1\to#2% + {\ifx\dodoglobal\relax + \expandafter\etokspre + \else + \resetglobal + \expandafter\xtokspre + \fi#2{#1}} + +%D Hm. + +\unexpanded\def\flushtoks#1% nb: can reassign to #1 again, hence the indirectness + {\t_syst_helpers_scratch#1\relax + \dodoglobal#1\emptytoks + \the\t_syst_helpers_scratch\relax} + +\let\dotoks\the + +%D \macros +%D {beforesplitstring,aftersplitstring} +%D +%D These both commands split a string at a given point in two +%D parts, so \type{x.y} becomes \type{x} or \type{y}. +%D +%D \starttyping +%D \beforesplitstring test.tex\at.\to\filename +%D \aftersplitstring test.tex\at.\to\extension +%D \stoptyping +%D +%D The first routine looks (and is indeed) a bit simpler than the second one. The +%D alternative looking more or less like the first one did not always give the +%D results we needed. Both implementations show some insight in the manipulation of +%D arguments. + +\let\syst_helpers_split_string\relax + +\unexpanded\def\beforesplitstring#1\at#2\to#3% + {\def\syst_helpers_split_string##1#2##2#2##3\\% + {\def#3{##1}}% + \expandafter\syst_helpers_split_string#1#2#2\\} + +\unexpanded\def\aftersplitstring#1\at#2\to#3% + {\def\syst_helpers_split_string##1#2##2@@@##3\\% + {\def#3{##2}}% + \expandafter\syst_helpers_split_string#1@@@#2@@@\\} + +%D \macros +%D {splitstring,greedysplitstring} +%D +%D A bonus macro. + +\unexpanded\def\splitstring#1\at#2\to#3\and#4% + {\def\syst_helpers_split_string##1#2##2\empty\empty\empty##3\\% + {\def#3{##1}% + \def\syst_helpers_split_string{##3}% + \ifx\syst_helpers_split_string\empty + \let#4\empty + \else + \def#4{##2}% + \fi}% + \expandafter\syst_helpers_split_string#1\empty\empty\empty#2\empty\empty\empty\\} + +\unexpanded\def\greedysplitstring#1\at#2\to#3\and#4% + {\edef\asciib{#1}% + \let\asciic\asciib + \let#3\empty + \let#4\empty + \doloop + {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib + \ifx\asciib\empty + \exitloop + \else + % not \edef#3{\ifx#3\empty\else#3#2\fi\asciia} else + % /root/path fails because then #3==empty + \edef#3{\ifcase\recurselevel\or\else#3#2\fi\asciia}% + \let#4\asciib + \fi}% + \ifx#3\empty\let#3\asciic\fi} + +%D \macros +%D {beforetestandsplitstring, +%D aftertestandsplitstring, +%D testandsplitstring} + +\unexpanded\def\beforetestandsplitstring#1\at#2\to#3% + {\def\syst_helpers_split_string##1#2##2#2##3##4\\% + {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}% + \expandafter\syst_helpers_split_string#1#2#2\empty\\} + +\unexpanded\def\aftertestandsplitstring#1\at#2\to#3% + {\def\syst_helpers_split_string ##1#2##2@@@##3##4\\% + {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}% + \expandafter\syst_helpers_split_string #1@@@#2@@@\empty\\} + +\def\testandsplitstring#1\at#2\to#3\and#4% + {\def\syst_helpers_split_string##1#2##2#2##3##4\\% + {\ifx##3\empty\let#3\empty\let#4\empty\else\def#3{##1}\def#4{##2}\fi}% + \expandafter\syst_helpers_split_string#1#2#2\empty\\} + +%D \macros +%D {splitatperiod, +%D {splitatcomma, +%D splitatasterisk, +%D splitatcolon, +%D splitatcolons} + +\unexpanded\def\splitatperiod #1{\normalexpanded{\syst_helpers_splitatperiod #1}..\relax} +\unexpanded\def\splitatcomma #1{\normalexpanded{\syst_helpers_splitatcomma #1},,\relax} % not at ", " +\unexpanded\def\splitatasterisk#1{\normalexpanded{\syst_helpers_splitatasterisk#1}**\relax} +\unexpanded\def\splitatcolon #1{\normalexpanded{\syst_helpers_splitatcolon #1}::\relax} +\unexpanded\def\splitatcolons #1{\normalexpanded{\syst_helpers_splitatcolons #1}::::\relax} + +\unexpanded\def\syst_helpers_splitatperiod #1.#2.#3\relax#4#5{\def#4{#1}\def#5{#2}} +\unexpanded\def\syst_helpers_splitatcomma #1,#2,#3\relax#4#5{\def#4{#1}\def#5{#2}} +\unexpanded\def\syst_helpers_splitatasterisk #1*#2*#3\relax#4#5{\def#4{#1}\def#5{#2}} +\unexpanded\def\syst_helpers_splitatcolon #1:#2:#3\relax#4#5{\def#4{#1}\def#5{#2}} +\unexpanded\def\syst_helpers_splitatcolons #1::#2::#3\relax#4#5{\edef#4{#1}\edef#5{#2}} + +%D \macros +%D {removesubstring} +%D +%D A first application of the two routines defined above is: +%D +%D \starttyping +%D \removesubstring-\from first-last\to\nothyphenated +%D \stoptyping +%D +%D Which in terms of \TEX\ looks like: + +\unexpanded\def\removesubstring#1\from#2\to#3% + {\splitstring#2\to\m_syst_string_one\and\m_syst_string_two + \dodoglobal#3{\m_syst_string_one\m_syst_string_two}} + +%D \macros +%D {appendtocommalist,prependtocommalist, +%D addtocommalist,removefromcommalist} +%D +%D When working with comma separated lists, one sooner or later want the tools to +%D append or remove items from such a list. When we add an item, we first check if +%D it's already there. This means that every item in the list is unique. +%D +%D \starttyping +%D \addtocommalist {alfa} \name +%D \addtocommalist {beta} \name +%D \addtocommalist {gamma} \name +%D \removefromcommalist {beta} \name +%D \stoptyping +%D +%D These commands can be prefixed with \type {\doglobal}. The implementation of the +%D second command is more complecated, because we have to take leading spaces into +%D account. Keep in mind that users may provide lists with spaces after the commas. +%D When one item is left, we also have to get rid of trailing spaces. +%D +%D \starttyping +%D \def\words{alfa, beta, gamma, delta} +%D \def\words{alfa,beta,gamma,delta} +%D \stoptyping +%D +%D Removing an item takes more time than adding one. A fast appending alternative, +%D without any testing, is also provided: +%D +%D \starttyping +%D \appendtocommalist {something} \name +%D \prependtocommalist {something} \name +%D \stoptyping +%D +%D This can be implemented as follows: +%D +%D \starttyping +%D \def\appendtocommalist#1#2% +%D {\ifx#2\empty +%D \dodoglobal\edef#2{#1}% +%D \else % no test on empty +%D \dodoglobal\edef#2{#2,#1}% +%D \fi} +%D +%D \def\prependtocommalist#1#2% +%D {\ifx#2\empty +%D \dodoglobal\edef#2{#1}% +%D \else % no test on empty +%D \dodoglobal\edef#2{#1,#2}% +%D \fi} +%D \stoptyping +%D +%D The faster alternatives are: + +\unexpanded\def\appendtocommalist#1#2% + {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}} + +\unexpanded\def\prependtocommalist#1#2% + {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}} + +\unexpanded\def\addtocommalist#1#2% {item} \cs + {\rawdoifelseinset{#1}#2\resetglobal + {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} + +\unexpanded\def\pretocommalist#1#2% {item} \cs + {\rawdoifelseinset{#1}#2\resetglobal + {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} + +\unexpanded\def\robustdoifelseinset#1#2% + {\edef\m_syst_string_one{\detokenize\expandafter{\normalexpanded{#1}}}% + \edef\m_syst_string_two{\detokenize\expandafter{\normalexpanded{#2}}}% + \rawdoifelseinset\m_syst_string_one\m_syst_string_two} + +\let\robustdoifinsetelse\robustdoifelseinset + +\unexpanded\def\robustaddtocommalist#1#2% {item} \cs + {\robustdoifelseinset{#1}#2\resetglobal + {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}} + +\unexpanded\def\robustpretocommalist#1#2% {item} \cs + {\robustdoifelseinset{#1}#2\resetglobal + {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}} + +\unexpanded\def\xsplitstring#1#2% \cs {str} + {\def\syst_helpers_split_string##1,#2,##2,#2,##3\\% + {\edef\m_syst_string_one{\bcleanedupcommalist##1\empty\empty\relax}% + \edef\m_syst_string_two{\acleanedupcommalist##2,,\relax}}% + \expandafter\syst_helpers_split_string\expandafter,#1,,#2,,#2,\\} + +\def\bcleanedupcommalist#1#2#3\relax{\if#1,\else#1\fi\if#2,\else#2\fi#3} +\def\bcleanedupcommalist#1#2\relax{\if#1,\else#1\fi#2} +\def\acleanedupcommalist#1,,#2\relax{#1} + +\unexpanded\def\removefromcommalist#1#2% to be sped up + {\rawdoifelseinset{#1}#2% + {\normalexpanded{\xsplitstring\noexpand#2{#1}}% + \dodoglobal\edef#2% + {\ifx\m_syst_string_one\empty + \m_syst_string_two + \else + \m_syst_string_one\ifx\m_syst_string_two\empty\else,\m_syst_string_two\fi + \fi}} + \resetglobal} + +%D \macros +%D {substituteincommalist} +%D +%D Slow but seldom used, so for the moment we stick to this implementation. +%D +%D \starttyping +%D \substituteincommalist{old}{new}{list} +%D \stoptyping + +\def\syst_helpers_substitute_in_comma_list_step#1% + {\edef\m_syst_string_three{#1}% + \ifx\m_syst_string_one\m_syst_string_three + \ifx\m_syst_string_two\empty \else + \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi\m_syst_string_two}% + \fi + \else + \edef\m_syst_string_four{\ifx\m_syst_string_four\empty\else\m_syst_string_four,\fi#1}% + \fi} + +\unexpanded\def\substituteincommalist#1#2#3% old, new, list (slooow) + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#2}% + \let\m_syst_string_four\empty + \normalexpanded{\rawprocesscommacommand[#3]}\syst_helpers_substitute_in_comma_list_step + \let#3\m_syst_string_four} + +%D \macros +%D {replaceincommalist} +%D +%D The next macro can be used to replace an indexed element in a commalist: +%D +%D \starttyping +%D \replaceincommalist\MyList{2} +%D \stoptyping +%D +%D Element~2 will be replaced by the current meaning of the macro \type +%D {\newcommalistelement}. The old meaning is saved in \type {\commalistelement}. +%D The replacement honors grouped items, like in: +%D +%D \starttyping +%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} +%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3} +%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3} +%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3} +%D \stoptyping +%D +%D This macro was used in the bibtex code (and is probably no longer needed). + +\newcount\c_syst_helpers_comma_list_index +\let \m_syst_helpers_comma_list_target\empty + +\let\newcommalistelement\empty + +\def\syst_helpers_replace_in_comma_list_step#1% + {\ifnum\commalistcounter=\c_syst_helpers_comma_list_index\relax + \ifx\newcommalistelement\empty\else + \ifx\m_syst_helpers_comma_list_target\empty + \let\m_syst_helpers_comma_list_target\newcommalistelement + \else + \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter + \m_syst_helpers_comma_list_target\expandafter\expandafter\expandafter + {\expandafter\m_syst_helpers_comma_list_target\expandafter,\newcommalistelement}% + \fi + \fi + \def\commalistelement{#1}% + \else + \ifx\m_syst_helpers_comma_list_target\empty + \ifx\nexttoken\bgroup % is known -) + \def\m_syst_helpers_comma_list_target{{#1}}% + \else + \def\m_syst_helpers_comma_list_target{#1}% + \fi + \else + \ifx\nexttoken\bgroup % is known -) + \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,{#1}}% + \else + \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,#1}% + \fi + \fi + \fi + \advance\commalistcounter\plusone} + +\unexpanded\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1 + {\c_syst_helpers_comma_list_index#2\relax + \let\m_syst_helpers_comma_list_target\empty + \let\commalistelement\empty + \commalistcounter\plusone + \expandafter\processcommalist\expandafter[#1]\syst_helpers_replace_in_comma_list_step + \dodoglobal\let#1\m_syst_helpers_comma_list_target} + +%D \macros +%D {globalprocesscommalist} +%D +%D The commalist processing commands are characterized by the fact that the way they +%D handle expansion as well as the fact that they can be nested. This makes them +%D kind of useless for handling comma lists in alignments. In these situations the +%D next macro can be of use. + +\let\m_syst_helpers_comma_list_command_global\empty + +\def\syst_helpers_comma_list_command_global_step#1,% + {\if]#1\else + \m_syst_helpers_comma_list_command_global{#1}% + \expandafter\syst_helpers_comma_list_command_global_step + \fi} + +\unexpanded\def\globalprocesscommalist[#1]#2% + {\glet\m_syst_helpers_comma_list_command_global#2% + \expandafter\syst_helpers_comma_list_command_global_step#1,],} + +%D \macros +%D {withoutpt,PtToCm, +%D numberofpoints,dimensiontocount} +%D +%D We can convert point into centimeters with: +%D +%D \starttyping +%D \PtToCm{dimension} +%D \stoptyping + +{\catcode`\.=\othercatcode + \catcode`\p=\othercatcode + \catcode`\t=\othercatcode + \gdef\WITHOUTPT#1pt{#1}} + +\def\withoutpt#1% + {\expandafter\WITHOUTPT#1} + +%D The capitals are needed because \type {p} and \type {t} have catcode~12, while +%D macronames only permit tokens with the catcode~11. As a result we cannot use the +%D \type {.group} primitives. Those who want to know more about this kind of +%D manipulations, we advice to study the \TEX book in detail. Because this macro +%D does not do any assignment, we can use it in the following way too. + +\def\PtToCm#1% + {\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm} + +%D We also support: +%D +%D \starttyping +%D \numberofpoints {dimension} +%D \dimensiontocount {dimension} {\count} +%D \stoptyping +%D +%D Both macros return a rounded number. + +% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt} +% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt} + +\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax} +\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax} + +%D \macros +%D {swapdimens,swapcounts,swapmacros, +%D globalswapdimens,globalswapcounts,globalswapmacros} +%D +%D Simple but effective are the next two macros. There name exactly states their +%D purpose. + +\newdimen\d_syst_helpers_swapped +\newcount\c_syst_helpers_swapped +\let \m_syst_helpers_swapped\relax + +\unexpanded\def\swapdimens#1#2{\d_syst_helpers_swapped #1\relax#1#2\relax#2\d_syst_helpers_swapped} +\unexpanded\def\swapcounts#1#2{\c_syst_helpers_swapped #1\relax#1#2\relax#2\c_syst_helpers_swapped} +\unexpanded\def\swapmacros#1#2{\let\m_syst_helpers_swapped#1\let #1#2\let #2\m_syst_helpers_swapped} + +\unexpanded\def\globalswapdimens#1#2{\d_syst_helpers_swapped #1\global#1#2\global#2\d_syst_helpers_swapped} +\unexpanded\def\globalswapcounts#1#2{\c_syst_helpers_swapped #1\global#1#2\global#2\c_syst_helpers_swapped} +\unexpanded\def\globalswapmacros#1#2{\let\m_syst_helpers_swapped#1\glet #1#2\glet #2\m_syst_helpers_swapped} + +%D \macros +%D {pushmacro,popmacro} +%D +%D Premature and a bit of beta, we offer: +%D +%D \starttyping +%D \pushmacro\macro +%D \popmacro\macro +%D \stoptyping +%D +%D Beware: global! + +\installsystemnamespace{localpushedmacro} +\installsystemnamespace{globalpushedmacro} + +\let\m_syst_helpers_push_macro\empty + +\newcount\c_syst_helpers_pop_count + +\def\syst_helpers_push_macro_new_global + {\expandafter\newcount\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname\plusone} + +\def\syst_helpers_push_macro_new_local + {\expandafter\newcount\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname\plusone} + +\unexpanded\def\globalpushmacro#1% + {\xdef\m_syst_helpers_push_macro{\csstring#1}% + \ifcsname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\lastnamedcs\plusone + \else + \syst_helpers_push_macro_new_global + \fi + \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1} + +\unexpanded\def\localpushmacro#1% this one can be used to push a value over an \egroup + {\xdef\m_syst_helpers_push_macro{\csstring#1}% + \ifcsname\??localpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\lastnamedcs\plusone + \else + \syst_helpers_push_macro_new_local + \fi + \expandafter\glet\csname\the\lastnamedcs\m_syst_helpers_push_macro\endcsname#1} + +\unexpanded\def\globalpopmacro#1% + {\xdef\m_syst_helpers_push_macro{\csstring#1}% + \c_syst_helpers_pop_count\csname\??globalpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\lastnamedcs \minusone + \expandafter\glet\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname} + +\unexpanded\def\localpopmacro#1% + {\xdef\m_syst_helpers_push_macro{\csstring#1}% + \c_syst_helpers_pop_count\csname\??localpushedmacro\m_syst_helpers_push_macro\endcsname + \global\advance\lastnamedcs \minusone + \expandafter\let\expandafter#1\csname\the\c_syst_helpers_pop_count\m_syst_helpers_push_macro\endcsname} + +\let\pushmacro\localpushmacro +\let\popmacro \localpopmacro + +%D \macros +%D {setlocalhsize,distributedhsize} +%D +%D Sometimes we need to work with the \type{ \hsize} that is corrected for +%D indentation and left and right skips. The corrected value is available in \type +%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D +%D +%D \starttyping +%D \setlocalhsize \hbox to \localhsize{...} +%D \setlocalhsize[-1em] \hbox to \localhsize{...} +%D \setlocalhsize[.5ex] \hbox to \localhsize{...} +%D \stoptyping +%D +%D These examples show us that an optional can be used. The value provided is added +%D to \type {\localhsize}. + +\newdimen\localhsize + +\unexpanded\def\setlocalhsize % don't change ! + {\doifelsenextoptional + \syst_helpers_set_local_hsize_yes + \syst_helpers_set_local_hsize_nop} + +\def\syst_helpers_set_local_hsize_nop + {\localhsize\availablehsize} + +\def\syst_helpers_set_local_hsize_yes[#1]% + {\syst_helpers_set_local_hsize_nop + \advance\localhsize#1\relax} + +\def\availablehsize + {\dimexpr + \hsize-\leftskip-\rightskip + \ifnum\hangafter<\zerocount + \ifdim\hangindent>\zeropoint-\else+\fi\hangindent + \fi + \relax} + +\def\distributedhsize#1#2#3% + {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax} + +\def\hsizefraction#1#2% + {\dimexpr#1/#2\relax} + +%D \macros +%D {doifvalue,doifnotvalue,doifelsevalue, +%D doifnothing,doifsomething,doifelsenothing, +%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing} +%D +%D These \type {\if} commands can be used to access macros (or variables) that are +%D normally accessed by using \type {\getvalue}. Using these alternatives safes us +%D three tokens per call. Anyone familiar with the not||values ones, can derive +%D their meaning from the definitions. + +\unexpanded\def\doifvalue#1#2% + {\iftok{\csname#1\endcsname}{#2}% + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifnotvalue#1#2% + {\iftok{\csname#1\endcsname}{#2}% + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\doifelsevalue#1#2% + {\iftok{\csname#1\endcsname}{#2}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\doifnothing#1% + {\iftok{#1}\emptytoks + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifsomething#1% + {\iftok{#1}\emptytoks + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\doifelsenothing#1% + {\iftok{#1}\emptytoks + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\doifelsesomething#1% + {\iftok{#1}\emptytoks + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\unexpanded\def\doifvaluenothing#1% + {\iftok{\csname#1\endcsname}\emptytoks + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\doifvaluesomething#1% + {\iftok{\csname#1\endcsname}\emptytoks + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\doifelsevaluenothing#1% + {\iftok{\csname#1\endcsname}\emptytoks + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifvalueelse \doifelsevalue +\let\doifnothingelse \doifelsenothing +\let\doifsomethingelse \doifelsesomething +\let\doifvaluenothingelse\doifelsevaluenothing + +%D \macros +%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue} +%D +%D Also handy: + +\def\doifelseemptyvalue#1% + {\expandafter\ifx\csname#1\endcsname\empty + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifemptyvalueelse\doifelseemptyvalue + +\def\doifemptyvalue#1% + {\expandafter\ifx\csname#1\endcsname\empty + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\def\doifnotemptyvalue#1% + {\expandafter\ifx\csname#1\endcsname\empty + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +%D \macros +%D {doifallcommonelse} +%D +%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where +%D the first two arguments are sets. + +\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow + {\def\syst_helpers_do_common_check_all##1% + {\doifnotinset{##1}{#4}\donefalse + \ifdone\else\expandafter\quitcommalist\fi}% + \donetrue + \processcommalist[#3]\syst_helpers_do_common_check_all + \ifdone\expandafter#1\else\expandafter#2\fi} + +\unexpanded\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments} +\unexpanded\def\doifallcommon {\syst_helpers_do_if_all_common_else\firstofonearguments\gobbleoneargument } +\unexpanded\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument \firstofonearguments } + +\let\doifallcommonelse\doifelseallcommon + +%D \macros +%D {DOIF,DOIFELSE,DOIFNOT} +%D +%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less +%D desirable, for instance when we compare filenames. The next three alternatives +%D upcase their arguments before comparing them. +%D +%D \starttyping +%D \DOIF {string1} {string2} {...} +%D \DOIFNOT {string1} {string2} {...} +%D \DOIFELSE {string1} {string2} {then ...}{else ...} +%D \stoptyping +%D +%D We have to use a two||step implementation, because the +%D expansion has to take place outside \type{\uppercase}. +%D +%D These might end up as \LUA based helpers (i.e. consider these +%D obsolete: + +\unexpanded\def\syst_helpers_do_IF#1#2% + {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\unexpanded\def\syst_helpers_do_IF_NOT#1#2% + {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\syst_helpers_do_IF_ELSE#1#2% + {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\syst_helpers_do_IF_INSTRING_ELSE#1#2% + {\uppercase{\syst_helpers_do_if_in_string_else{$#1$}{$#2$}}% + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\unexpanded\def\DOIF #1#2{\normalexpanded{\syst_helpers_do_IF {#1}{#2}}}% will become obsolete +\unexpanded\def\DOIFNOT #1#2{\normalexpanded{\syst_helpers_do_IF_NOT {#1}{#2}}}% will become obsolete +\unexpanded\def\DOIFELSE #1#2{\normalexpanded{\syst_helpers_do_IF_ELSE {#1}{#2}}}% will become obsolete +\unexpanded\def\DOIFINSTRINGELSE #1#2{\normalexpanded{\syst_helpers_do_IF_INSTRING_ELSE{#1}{#2}}}% will become obsolete + +%D \macros +%D {dosingleargumentwithset, +%D dodoubleargumentwithset,dodoubleemptywithset, +%D dotripleargumentwithset,dotripleemptywithset} +%D +%D These maybe too mysterious macros enable us to handle more than one setup at once. +%D +%D \starttyping +%D \dosingleargumentwithset \command[#1] +%D \dodoubleargumentwithset \command[#1][#2] +%D \dotripleargumentwithset \command[#1][#2][#3] +%D \dodoubleemptywithset \command[#1][#2] +%D \dotripleemptywithset \command[#1][#2][#3] +%D \stoptyping +%D +%D The first macro calls \type {\command[##1]} for each string in the set~\type +%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one +%D may guess. These commands support constructions like: +%D +%D \starttyping +%D \def\dodefinesomething[#1][#2]% +%D {\getparameters[\??xx#1][#2]} +%D +%D \unexpanded\def\definesomething% +%D {\dodoubleargumentwithset\dodefinesomething} +%D \stoptyping +%D +%D Which accepts calls like: +%D +%D \starttyping +%D \definesomething[alfa,beta,...][variable=...,...] +%D \stoptyping + +\let\m_syst_helpers_with_set_command\empty +\let\syst_helpers_with_set_step \relax + +\def\syst_helpers_with_set_double[#1][#2]% + {\doifsomething{#1}% + {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2]}% + \processcommalist[#1]\syst_helpers_with_set_step}} + +\def\syst_helpers_with_set_triple[#1][#2][#3]% + {\doifsomething{#1}% + {\def\syst_helpers_with_set_step##1{\m_syst_helpers_with_set_command[##1][#2][#3]}% + \processcommalist[#1]\syst_helpers_with_set_step}} + +\def\dodoubleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dodoubleempty \syst_helpers_with_set_double} % \command +\def\dodoubleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dodoubleargument\syst_helpers_with_set_double} % \command + +\def\dotripleemptywithset #1{\let\m_syst_helpers_with_set_command#1\dotripleempty \syst_helpers_with_set_triple} % \command +\def\dotripleargumentwithset#1{\let\m_syst_helpers_with_set_command#1\dotripleargument\syst_helpers_with_set_triple} % \command + +%D \macros +%D {stripcharacters,stripspaces} +%D +%D The next command was needed first when we implemented the \CONTEXT\ interactivity +%D macros. When we use labeled destinations, we often cannot use all the characters +%D we want. We therefore strip some of the troublemakers, like spaces, from the +%D labels before we write them to the \DVI||file, which passes them to for instance +%D a \POSTSCRIPT\ file. +%D +%D \starttyping +%D \stripspaces\from\one\to\two +%D \stoptyping +%D +%D Both the old string \type{\one} and the new one \type{\two} +%D are expanded. This command is a special case of: +%D +%D \starttyping +%D \stripcharacter\char\from\one\to\two +%D \stoptyping +%D +%D As we can see below, spaces following a control sequence are to enclosed in \type +%D {{}}. + +\let\m_syst_helpers_strip_character\empty + +\unexpanded\def\stripcharacter#1\from#2\to#3% + {\def\syst_helpers_strip_character##1#1##2\end + {\edef\m_syst_helpers_strip_character{\m_syst_helpers_strip_character##1}% + \doifnotempty{##2}{\syst_helpers_strip_character##2\end}}% + \let\m_syst_helpers_strip_character\empty + \edef\m_syst_string_one{#2}% + \expandafter\syst_helpers_strip_character\m_syst_string_one#1\end + \dodoglobal\let#3\m_syst_helpers_strip_character} + +\unexpanded\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2 + {\stripcharacter{ }\from#1\to#2} + +%D \macros +%D {unspacestring} +%D +%D The next macro does the same but is more compatible with other macros, like \type +%D {\convert...}. + +\unexpanded\def\unspacestring#1\to#2% + {\stripcharacter{ }\from#1\to#2} + +%D \macros +%D {executeifdefined} +%D +%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents, +%D references, two||pass optimizations, sorted lists etc. This file is loaded as +%D many times as needed. During such a pass we skip the commands thate are of no use +%D at that moment. Because we don't want to come into trouble with undefined +%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The +%D next macro take care of such executions and when not defined, gobbles the +%D unwanted arguments. +%D +%D \starttyping +%D \executeifdefined{name}\gobbleoneargument +%D \stoptyping +%D +%D We can of course gobble more arguments using the appropriate gobbling command. + +\def\executeifdefined#1% #2 / never change this one again + {\ifcsname#1\endcsname + % \csname#1\expandafter\expandafter\expandafter\endcsname\expandafter\gobbleoneargument + \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +%D This one also has the advantage that it is fully expandable and that it can be +%D used after an assignment. + +%D \macros +%D {doifsomespaceelse} +%D +%D The next command checks a string on the presence of a space and executed a +%D command accordingly. +%D +%D \starttyping +%D \doifsomespaceelse {tekst} {then ...} {else ...} +%D \stoptyping +%D +%D We use this command in \CONTEXT\ for determing if an argument must be broken into +%D words when made interactive. Watch the use of \type {\noexpand}. + +%D Is this one still needed? + +\def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@} + +\def\doifelsesomespace#1% % #2#3% + {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi} + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\let\doifsomespaceelse\doifelsesomespace + +%D \macros +%D {processseparatedlist} +%D +%D Maybe a bit late, but here is a more general version of the \type +%D {\processcommalist} command. This time we don't handle nesting but accept +%D arbitrary seperators. +%D +%D \starttyping +%D \processseparatedlist[list][separator]\command +%D \stoptyping +%D +%D One can think of things like: +%D +%D \starttyping +%D \processseparatedlist[alfa+beta+gamma][+]\message +%D \stoptyping +%D +%D We want to handle all situations, like: +%D +%D \startbuffer +%D \processseparatedlist[{aap noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} +%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} +%D \processseparatedlist[aap {noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} +%D \processseparatedlist[aap noot] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii} +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove +%D afterwards. + +\let\syst_helpers_process_separated_list_step\relax + +\def\syst_helpers_process_separated_list#1]#2[#3]#4% + {\def\syst_helpers_process_separated_list_step##1##2#3% + {\def\m_syst_string_one{##2}% suggested by VZ + \if]##1% + \let\syst_helpers_process_separated_list_step\relax + \orelse\ifx\blankspace\m_syst_string_one + #4{##1}% + \orelse\if]##2% + \let\syst_helpers_process_separated_list_step\relax + \else + #4{##1##2}% + \fi + \syst_helpers_process_separated_list_step}% + \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#3]#3} + +\unexpanded\def\processseparatedlist[% + {\syst_helpers_process_separated_list\relax} + +%D \macros +%D {processlist} +%D +%D An even more general list processing macro is the following one: +%D +%D \starttyping +%D \processlist{beginsym}{endsym}{separator}\docommand list +%D \stoptyping +%D +%D This one supports arbitrary open and close symbols as well as user defined +%D separators. +%D +%D \starttyping +%D \processlist(){=>}\docommand(a=>b=>c=>d) +%D \stoptyping + +\let\syst_helpers_process_any_list \relax +\let\syst_helpers_process_any_list_indeed\relax +\let\syst_helpers_process_any_list_step \relax + +\unexpanded\def\processlist#1#2#3#4% no blank skipping ! + {\def\syst_helpers_process_any_list_indeed##1#2% + {\def\syst_helpers_process_any_list_step####1####2#3% + {\ifx#2####1% + \let\syst_helpers_process_any_list_step\relax + \orelse\ifx#2####2% + \let\syst_helpers_process_any_list_step\relax + \else + #4{####1####2}% + \fi + \syst_helpers_process_any_list_step}% + \expandafter\syst_helpers_process_any_list_step\gobbleoneargument##1#3#2#3}% + \def\syst_helpers_process_any_list#1% + {\syst_helpers_process_any_list_indeed\relax}% + \syst_helpers_process_any_list} + +%D \macros +%D {processassignlist} +%D +%D Is possible to combine an assignment list with one containing keywords. +%D Assignments are treated accordingly, keywords are treated by \type {\command}. +%D +%D \starttyping +%D \processassignlist[...=...,...=...,...]\commando +%D \stoptyping +%D +%D This command can be integrated in \type {\getparameters}, but we decided best not +%D to do so. + +\unexpanded\def\processassignlist#1[#2]#3% + {\def\syst_helpers_process_assign_list_assign[##1=##2=##3]% + {\doif{##3}\relax{#3{##1}}}% + \def\syst_helpers_process_assign_list_step##1% + {\syst_helpers_process_assign_list_assign[##1==\relax]}% + \processcommalist[#2]\syst_helpers_process_assign_list_step} + +%D \macros +%D {untextargument +%D untexcommand} +%D +%D When manipulating data(bases) and for instance generating index entries, the next +%D three macros can be of help: +%D +%D \starttyping +%D \untextargument{...}\to\name +%D \untexcommand {...}\to\name +%D \stoptyping +%D +%D They remove braces and backslashes and give us something to sort. + +\let\m_syst_helpers_untexed\empty + +\unexpanded\def\untexsomething + {\begingroup + \catcode\leftbraceasciicode \ignorecatcode + \catcode\rightbraceasciicode\ignorecatcode + \escapechar\minusone + \syst_helpers_untex_something} + +\def\syst_helpers_untex_something#1#2\to#3% + {\doglobal#1#2\to\m_syst_helpers_untexed + \endgroup + \let#3\m_syst_helpers_untexed} + +\unexpanded\def\untexargument{\untexsomething\convertargument} +\unexpanded\def\untexcommand {\untexsomething\convertcommand} + +%D \macros +%D {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints} +%D +%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both used big points (\TEX's +%D bp). The next macros convert points and scaled points into big points. The magic +%D factor $72/72.27$ can be found in most \TEX\ related books. +%D +%D \starttyping +%D \ScaledPointsToBigPoints {number} \target +%D \ScaledPointsToWholeBigPoints {number} \target +%D \stoptyping + +\let\tobigpoints \clf_tobigpoints +\let\towholebigpoints\clf_towholebigpoints + +\unexpanded\def\PointsToBigPoints #1#2{\edef#2{\tobigpoints #1}} % can be avoided +\unexpanded\def\PointsToWholeBigPoints #1#2{\edef#2{\towholebigpoints#1}} % can be avoided +\unexpanded\def\ScaledPointsToBigPoints #1#2{\edef#2{\tobigpoints #1\scaledpoint}} % obsolete +\unexpanded\def\ScaledPointsToWholeBigPoints#1#2{\edef#2{\towholebigpoints#1\scaledpoint}} % obsolete + +%D \macros +%D {PointsToReal} +%D +%D Points can be stripped from their suffix by using \type {\withoutpt}. The next +%D macro enveloppes this macro. +%D +%D \starttyping +%D \PointsToReal {dimension} \target +%D \stoptyping + +\unexpanded\def\PointsToReal#1#2% + {\edef#2{\withoutpt\the\dimexpr#1}} + +%D \macros +%D {dontleavehmode} +%D +%D Sometimes when we enter a paragraph with some command, the first token gets the +%D whole first line. We can prevent this by saying: +%D +%D \starttyping +%D \dontleavehmode +%D \stoptyping +%D +%D This command is used in for instance the language module \type {lang-ini}. The +%D first version was: +%D +%D \starttyping +%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi} +%D \stoptyping +%D +%D Next, Taco came with a better alternative (using mathsurround): +%D +%D \starttyping +%D \def\dontleavehmode +%D {\ifhmode\else \ifmmode\else +%D {\mathsurround\zeropoint\everymath\emptytoks$ $}% +%D \fi \fi} +%D \stoptyping +%D +%D And finaly we got the following alternative, one that avoids interfering grouping +%D at the cost of a box. +%D +%D \starttyping +%D \newbox\b_syst_helpers_dlh +%D +%D \unexpanded\def\dontleavehmode +%D {\ifhmode\else \ifmmode\else +%D \setbox\b_syst_helpers_dlh\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\b_syst_helpers_dlh +%D \fi \fi} +%D \stoptyping +%D +%D But, as we run a recent version of \TEX, we can use the new primitive: + +\ifdefined\normalquitvmode \let\dontleavehmode\normalquitvmode \fi + +%D \macros +%D {utfupper, utflower, uppercasestring, lowercasestring} +%D +%D The names tell what they do: +%D +%D \starttyping +%D \uppercasestring somestring\to\somestring +%D \lowercasestring somestring\to\somestring +%D \stoptyping +%D +%D The first argument may be a \type{\macro}. +%D +%D These macros are sort of obsolete as we never use uppercase this way. But +%D nevertheless we provide them: + +\def\utfupper#1{\clf_upper{#1}} % expandable +\def\utflower#1{\clf_lower{#1}} % expandable + +\unexpanded\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}} +\unexpanded\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}} + +%D \macros +%D {handletokens} +%D +%D With the next macro we enter a critical area of macro expansion. What we want is +%D a macro that looks like: +%D +%D \starttyping +%D \handletokens some tokens\with \somemacro +%D \stoptyping +%D +%D A bonus example: +%D +%D \starttyping +%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox} +%D +%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi} +%D +%D \hbox{\handletokens tekst en meer tekst\with\weetikveel} +%D \stoptyping + +%D \macros +%D {counttoken,counttokens} +%D +%D For the few occasions that we want to know the number of specific tokens in a +%D string, we can use: +%D +%D \starttyping +%D \counttoken token\in string\to \somecount +%D \counttokens string\to \somecount +%D \stoptyping +%D +%D This macro, that for instance is used in \type {cont-tab}, takes a real counter. +%D The macro can be preceded by \type {\doglobal}. + +\def\syst_helpers_count_token#1% obeys {} + {\def\m_syst_string_three{#1}% + \ifx\m_syst_string_two\m_syst_string_three \else + \ifx\m_syst_string_one\m_syst_string_three + \advance\privatescratchcounter\plusone + \fi + \expandafter\syst_helpers_count_token + \fi} + +\unexpanded\def\counttoken#1\in#2\to#3% + {\privatescratchcounter\zerocount + \def\m_syst_string_one{#1}% + \def\m_syst_string_two{\end}% + \syst_helpers_count_token#2\end + \dodoglobal#3\privatescratchcounter} + +\unexpanded\def\counttokens#1\to#2% + {\privatescratchcounter\zerocount + \def\syst_helpers_count_token##1{\advance\privatescratchcounter\plusone}% + \handletokens#1\with\syst_helpers_count_token + \dodoglobal#2\privatescratchcounter} + +%D \macros +%D {splitofftokens} +%D +%D Running this one not always gives the expected results. Consider for instance the +%D macro for which I originally wrote this token handler. + +\unexpanded\def\splitofftokens#1\from#2\to#3% slow but hardly used + {\ifnum#1>\zerocount + \privatescratchcounter#1\relax + \def\syst_helpers_split_off_tokens##1% + {\ifnum\privatescratchcounter>\zerocount + \advance\privatescratchcounter \minusone + \edef#3{#3##1}% + \fi}% + % \let#3\empty % #3 can be #2, so: + \expandafter\let\expandafter#3\expandafter\empty + \expandafter\handletokens#2\with\syst_helpers_split_off_tokens + \else + \edef#3{#2}% + \fi} + +%D This macro can be called like: +%D +%D \startbuffer[example] +%D \splitofftokens10\from01234567 890123456789\to\test [\test] +%D \stopbuffer +%D +%D up there. The reason for this is not that logical but follows from \TEX's +%D However, the characters that we expect to find in \type {\test} just don't show +%D sometimes mysterious way of expanding. Look at this: +%D +%D \startbuffer[next] +%D \def\next{a} \edef\test{\next} [\test] +%D \let\next=b \edef\test{\test\next} [\test] +%D \let\next=c \edef\test{\next} [\test] +%D \let\next=d \edef\test{\test\next} [\test] +%D \let\next=e \expandafter\edef\expandafter\test\expandafter{\test\next} [\test] +%D \stopbuffer +%D +%D \typebuffer[next] +%D +%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let} +%D are not expanded! +%D +%D \unprotect\getbuffer[next]\protect +%D +%D That's why we finally end up with a macro that looks ahead by using an +%D assignment, this time by using \type {\futurelet}, and grabbing an argument as +%D well. That way we can handle the sentinal, a blank space and grouped tokens. + +\unexpanded\def\syst_helpers_handle_tokens % \nexthandledtoken is part of interface + {\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed} + +\def\handletokens#1\with#2% + {\gdef\syst_helpers_handle_tokens_command{#2}% permits more complex #2's + \syst_helpers_handle_tokens#1\end} + +\def\syst_helpers_handle_tokens_indeed + {\ifx\nexthandledtoken\blankspace + \expandafter\syst_helpers_handle_tokens_indeed_one + \orelse\ifx\nexthandledtoken\end + \expandafter\gobbletwoarguments % also gobble the \end + \else + \expandafter\syst_helpers_handle_tokens_indeed_two + \fi *} + +\def\syst_helpers_handle_tokens_indeed_one * % + {\syst_helpers_handle_tokens_command{ }\syst_helpers_handle_tokens} + +\def\syst_helpers_handle_tokens_indeed_two *#1% + {\syst_helpers_handle_tokens_command{#1}\syst_helpers_handle_tokens} + +%D This macro is tested on: +%D +%D \def\xxx#1{[#1]} +%D +%D \startlines +%D \handletokens abc\with\xxx +%D \handletokens a b c\with\xxx +%D \handletokens a b c\with\xxx +%D \handletokens a{bc}d\with\xxx +%D \handletokens a\space bc \with\xxx +%D \stoplines +%D +%D And our previous example shows up as: +%D +%D \getbuffer[example] + +%D \macros +%D {iftrialtypesetting, ifvisible} +%D +%D The next boolean is at first sight a strange one. Sometimes one does a trial +%D typesetting run, for instance to determine dimensions. Some mechanisms, like +%D object inclusion, can fail on such trials. Temporary setting the next boolean to +%D true, helps a lot. The second boolena can be used to inhibit processing +%D completely. + +\newif\ifvisible \visibletrue + +\newtoks\everysettrialtypesetting +\newtoks\everyresettrialtypesetting + +\unexpanded\def\settrialtypesetting {\the\everysettrialtypesetting } % obeys grouping so +\unexpanded\def\resettrialtypesetting{\the\everyresettrialtypesetting} % this one is seldom needed + +\let\iftrialtypesetting\iffalse % so we have no \trialtypesettingtrue|false in mkiv ! + +\appendtoks \let\iftrialtypesetting\iftrue \to \everysettrialtypesetting +\appendtoks \let\iftrialtypesetting\iffalse \to \everyresettrialtypesetting + +%D \macros +%D {twodigitrounding} +%D +%D When using \type {\special}s or \type {\pdfliteral}s, it sometimes makes sense to +%D limit the precission. The next macro rounds a real number to two digits. It takes +%D one argument and only works in \ETEX. + +\def\integerrounding #1{\clf_rounded\zerocount\numexpr#1\relax} +\def\onedigitrounding #1{\clf_rounded\plusone \numexpr#1\relax} +\def\twodigitrounding #1{\clf_rounded\plustwo \numexpr#1\relax} +\def\threedigitrounding#1{\clf_rounded\plusthree\numexpr#1\relax} + +%D \macros +%D {processcontent} +%D +%D This macro is first used in the tabulation macros. +%D +%D \starttyping +%D \unexpanded\def\starthans% +%D {\processcontent{stophans}\test{\message{\test}\wait}} +%D \stoptyping + +\unexpanded\def\processcontent#1% + {\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname} + +\unexpanded\def\syst_helpers_process_content#1#2#3% + {\unexpanded\def\syst_helpers_process_content##1#1% + {\endgroup\def#2{##1}#3}% + \syst_helpers_process_content} + +%D \macros +%D {dogobblesingleempty, dogobbledoubleempty} +%D +%D These two macros savely grab and dispose two arguments. + +\def\dogobblesingleempty{\dosingleempty\syst_helpers_gobble_single_empty} +\def\dogobbledoubleempty{\dodoubleempty\syst_helpers_gobble_double_empty} + +\def\syst_helpers_gobble_single_empty [#1]{} +\def\syst_helpers_gobble_double_empty[#1][#2]{} + +\let\gobblesingleempty\dogobblesingleempty % also used +\let\gobbledoubleempty\dogobbledoubleempty % also used + +%D \macros +%D {setdimensionwithunit, freezedimensionwithunit} +%D +%D The next assignments are all valid: +%D +%D \starttyping +%D \setdimensionwithunit\scratchdimen{10} {cm} +%D \setdimensionwithunit\scratchdimen{10cm}{cm} +%D \setdimensionwithunit\scratchdimen{10cm}{} +%D \freezedimensionwithunit\SomeWidth{\textwidth} +%D \freezedimensionwithunit\SomeDepth{\dp\strutbox} +%D \stoptyping +%D +%D As an alternative for the next macro we can use a global assignment inside a box. +%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s. + +\unexpanded\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick + {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty} + +\unexpanded\def\freezedimensionwithunit#1#2% + {\setdimensionwithunit\privatescratchdimen#1{#2}\edef#1{\the\privatescratchdimen}} + +%D \macros +%D {doifsometokselse, doifsometoks} +%D +%D Not that fast I guess, but here's a way to test for token registers being empty. + +\unexpanded\def\doifelsesometoks#1% + {\iftok#1\emptytoks + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +\unexpanded\def\doifsometoks#1% + {\iftok#1\emptytoks + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\doifemptytoks#1% + {\iftok#1\emptytoks + \expandafter\firstofoneargument + \else + \expandafter\gobbleoneargument + \fi} + +\let\doifsometokselse\doifelsesometoks + +%D \macros +%D {startstrictinspectnextcharacter} +%D +%D This one is for the bibliography module (still?): + +\let\syst_helpers_strict_inspect_next_character[ + +\def\syst_helpers_strict_inspect_next_character% no user macro ! + {\ifx\nexttoken[% + \expandafter\m_syst_action_yes + \else + \expandafter\m_syst_action_nop + \fi} + +\unexpanded\def\strictdoifelsenextoptional#1#2% + {\def\m_syst_action_yes{#1}% + \def\m_syst_action_nop{#2}% + \futurelet\nexttoken\syst_helpers_strict_inspect_next_character} + +\let\strictdoifnextoptionalelse\strictdoifelsenextoptional + +%D \macros +%D {gobblespacetokens} +%D +%D This macro needs a speed-up! + +%\def\gobblespacetokens +% {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do ! + +\def\gobblespacetokens + {\afterassignment\nexttoken\let\nexttoken=} + +%D \macros +%D {verbatimargument} +%D +%D As the name says, this macro converts its argument to a (rather safe) string. + +\let\verbatimstring\detokenize + +%D These are needed in ordinal number conversions: + +\def\lastdigit#1% + {\expandafter\thelastdigit\number#1\relax} + +\def\thelastdigit#1#2% + {\ifx#2\relax#1\else\expandafter\thelastdigit\expandafter#2\fi} + +\def\lasttwodigits#1% + {\expandafter\thelasttwodigits\expandafter0\number#1\relax} + +\def\thelasttwodigits#1#2#3% 0 dig ... \relax + {\ifx#3\relax#1#2\else\expandafter\thelasttwodigits\expandafter#2\expandafter#3\fi} + +%D \macros +%D {serializecommalist} +%D +%D Concatenate commalists: + +\let\syst_helpers_serialize_comma_list_step\relax + +\def\syst_helpers_serialize_comma_list_step#1% + {\edef\serializedcommalist{\serializedcommalist#1}} + +\unexpanded\def\serializecommalist[#1]% + {\let\serializedcommalist\empty + \processcommacommand[#1]\syst_helpers_serialize_comma_list_step} + +%D \macros +%D {purenumber} +%D +%D Sometimes we need control over when \TEX\ stops reading a number, especially in +%D full expandable macros where using \type {\relax} would lead to disasters. +%D +%D \starttyping +%D \ifodd\purenumber{...}\space ... \else ... \fi +%D \stoptyping +%D +%D Here we use a space as number delimiter in combination with a space- and +%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type +%D {\number} as well as \ETEX's \type {\numexpr}. + +\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}} + +%D \macros +%D {filterfromvalue} +%D +%D \starttyping +%D \setvalue{xx}{{A}{B}{C}} +%D +%D \filterfromvalue{xx}{3}{3} +%D \filterfromvalue{xx}{3}{2} +%D \filterfromvalue{xx}{3}{1} +%D \stoptyping +%D +%D An alternative is to store 'max' in the list, say: +%D +%D \starttyping +%D \setvalue{xx}{3{A}{B}{C}} +%D +%D \filterfromvalues{3}{xx}{3} +%D \filterfromvalues{3}{xx}{2} +%D \filterfromvalues{3}{xx}{1} +%D \stoptyping +%D +%D I'll implement this when I'm in \quotation {writing dirty macros mood}. + +\def\dofilterfromstr#1#2% max n % no need to be fast + {\expandafter \expandafter \expandafter \csstring + \ifcase#1\or \ifcase#2\or + \firstofoneargument \else + \gobbleoneargument \fi + \or \ifcase#2\or + \firstoftwoarguments \or + \secondoftwoarguments \else + \gobbletwoarguments \fi + \or \ifcase#2\or + \firstofthreearguments \or + \secondofthreearguments \or + \thirdofthreearguments \else + \gobblethreearguments \fi + \or \ifcase#2\or + \firstoffourarguments \or + \secondoffourarguments \or + \thirdoffourarguments \or + \fourthoffourarguments \else + \gobblefourarguments \fi + \or \ifcase#2\or + \firstoffivearguments \or + \secondoffivearguments \or + \thirdoffivearguments \or + \fourthoffivearguments \or + \fifthoffivearguments \else + \gobblefivearguments \fi + \fi} + +\def\filterfromvalue#1#2#3% value max n + {\expandafter\doubleexpandafter\csname % we use the fact that an + \expandafter\ifx\csname#1\endcsname\relax % undefined cs has become \relax + \csstring\gobbleoneargument % which we then gobble here + \else + \dofilterfromstr{#2}{#3}% + \fi + \endcsname\csname#1\endcsname} + +\def\filterfromnext#1#2% max n {..}{..}{..}{..} + {\csname\dofilterfromstr{#1}{#2}\endcsname} + +%D \macros +%D {definemeasure} +%D +%D \starttyping +%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)] +%D +%D ... \measure{mywidth} ... +%D \stoptyping + +\installsystemnamespace{measure} + +\unexpanded\def\definemeasure + {\dodoubleargument\syst_helpers_define_measure} + +\def\syst_helpers_define_measure[#1][#2]% + {\expandafter\def\csname\??measure#1\endcsname{#2}} + +\unexpanded\def\freezemeasure + {\dodoubleargument\syst_helpers_freeze_measure} + +\def\syst_helpers_freeze_measure[#1][#2]% + {\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}} + +\unexpanded\def\setmeasure #1#2{\expandafter\def \csname\??measure#1\endcsname{#2}} % quick way +\unexpanded\def\setgmeasure#1#2{\expandafter\gdef\csname\??measure#1\endcsname{#2}} % quick way +\unexpanded\def\setemeasure#1#2{\expandafter\edef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way +\unexpanded\def\setxmeasure#1#2{\expandafter\xdef\csname\??measure#1\endcsname{\the\dimexpr#2}} % quick way + +\def\measure + {\the\measured} + +\def\measured#1% + %{\dimexpr\ifcsname\??measure#1\endcsname\csname\??measure#1\endcsname\else\zeropoint\fi\relax} + {\dimexpr\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi\relax} + +% #2 could be omitted, but we want to support spaces +% +% \setmeasure {x} {1cm} +% \setmeasure {xx} {1cm} +% \setmeasure {xxx}{1cm} + +%D \macros +%D {dividedsize} +%D +%D This one can be used inside a measure (used in m4all): +%D +%D \starttyping +%D \definemeasure[columnwidth][\dividedsize\textwidth{1em}{3}] +%D \stoptyping + +\def\dividedsize#1#2#3% size gap n + {\dimexpr + \ifnum\dimexpr#1\relax>\plusone + (\dimexpr#1\relax-\numexpr#3-\plusone\relax\dimexpr#2\relax)/#3\else#1% + \fi + \relax} + +%D \macros +%D {doifdimensionelse} +%D +%D This is a dirty one: we simply append a unit and discard it when needed. + +\def\doifelsedimension#1% + {\ifchkdim#1\or + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifdimensionelse\doifelsedimension + +%D Ok, here's another one, slower but seldom used. This one scans the text. +%D +%D \starttabulate[|Tc|Tc|] +%D \NC pt \NC \doifdimenstringelse {pt}{yes}{no} \NC \NR +%D \NC 12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR +%D \NC 1pt \NC \doifdimenstringelse {1pt}{yes}{no} \NC \NR +%D \NC 12pt \NC \doifdimenstringelse {12pt}{yes}{no} \NC \NR +%D \NC 12.0pt \NC \doifdimenstringelse {12.0pt}{yes}{no} \NC \NR +%D \NC -.12pt \NC \doifdimenstringelse {-.12pt}{yes}{no} \NC \NR +%D \NC .12pt \NC \doifdimenstringelse {.12pt}{yes}{no} \NC \NR +%D \NC -12pt \NC \doifdimenstringelse {-12pt}{yes}{no} \NC \NR +%D \NC -12.0pt \NC \doifdimenstringelse{-12.0pt}{yes}{no} \NC \NR +%D \NC big \NC \doifdimenstringelse {big}{yes}{no} \NC \NR +%D \NC 10 \NC \doifdimenstringelse {10}{yes}{no} \NC \NR +%D \NC 1 \NC \doifdimenstringelse {1}{yes}{no} \NC \NR +%D \stoptabulate + +\let\doifelsedimenstring\doifelsedimension +\let\doifdimenstringelse\doifelsedimenstring + +%D \macros +%D {comparedimension,comparedimensioneps} +%D +%D This is a dirty one: we simply append a unit and discard it when needed. + +\newdimen \roundingeps \roundingeps=10sp +\newconstant\compresult + +\def\comparedimension#1#2% + {\compresult + \ifdim#1<#2% + \zerocount + \orelse\ifdim#1<#2% + \plusone + \else + \plustwo + \fi} + +\def\comparedimensioneps#1#2% todo: use eps feature + {\compresult + \ifdim\dimexpr#1-#2\relax<\roudingeps + \zerocount + \orelse\ifdim\dimexpr#2-#1\relax<\roudingeps + \zerocount + \orelse\ifdim#1<#2% + \plusone + \else + \plustwo + \fi} + +% pretty ugly but fast + +% \copycsname xxx\endcsname\csname ..\endcsname + +\unexpanded\def\copycsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname} + +% \letcscsname \crap \csname ..\endcsname +% \letcsnamecs \csname ..\endcsname\crap +% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname + +\unexpanded\def\letcscsname {\expandafter\let\expandafter} +\unexpanded\def\letcsnamecs {\expandafter\let} +\unexpanded\def\letcsnamecsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter} + +% another one, add an item to a commalist + +\unexpanded\def\addvalue#1#2% cs item + {\ifcsname#1\endcsname\else\expandafter\let\csname#1\endcsname\empty\fi + \normalexpanded{\noexpand\addtocommalist{#2}\expandafter\noexpand\csname#1\endcsname}} + +\def\unspaced#1% + {\syst_helpers_unspaced#1\end} + +\def\syst_helpers_unspaced#1% + {\ifx#1\end + \expandafter\gobbleoneargument + \orelse\ifx#1\blankspace + % go on + \else + #1% + \fi + \syst_helpers_unspaced} + +\unexpanded\def\unspaceargument#1\to#2% + {\privatescratchcounter\catcode\spaceasciicode + \catcode\spaceasciicode\ignorecatcode + \scantextokens{\edef#2{#1}}% + \catcode\spaceasciicode\privatescratchcounter} + +\unexpanded\def\unspaceafter#1#2% + {\unspaceargument#2\to\ascii + \expandafter#1\expandafter{\ascii}} + +% sometimes handy: + +\unexpanded\def\doifelsehasspace#1% + {\edef\m_syst_string_one{#1}% + \normalexpanded{\syst_helpers_if_has_space_else#1\space}\empty\relax} + +\let\doifhasspaceelse\doifelsehasspace + +\unexpanded\def\syst_helpers_if_has_space_else#1 #2#3\relax % \space\empty\relax + {\ifx\m_syst_string_one\space + \expandafter\firstoftwoarguments + \orelse\ifx#2\empty + \expandafter\secondoftwoarguments + \else + \expandafter\firstoftwoarguments + \fi} + +% this will replace loadfile once and alike !!! todo + +\installsystemnamespace{flag} + +\unexpanded\def\setflag #1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\zerocount} +\unexpanded\def\resetflag#1{\expandafter\dodoglobal\expandafter\let\csname\??flag#1\endcsname\plusone} + +\def\flag#1{\csname\??flag#1\endcsname} + +\def\doifelseflagged#1% + {\expandafter\ifx\csname\??flag#1\endcsname\relax + \expandafter\secondoftwoarguments + \orelse\ifcase\csname\??flag#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments + \fi} + +\let\doifflaggedelse\doifelseflagged + +\def\doifnotflagged#1% + {\expandafter\ifx\csname\??flag#1\endcsname\relax + \expandafter\firstofoneargument + \orelse\ifcase\csname\??flag#1\endcsname + \expandafter\gobbleoneargument + \else + \expandafter\firstofoneargument + \fi} + +\unexpanded\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey + {\expandafter\def\csname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}} + +\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4% + {\ifx#1\relax + \ifcase\privatescratchcounter + \endgroup + \doubleexpandafter\secondoftwoarguments + \else + \endgroup + \doubleexpandafter\firstoftwoarguments + \fi + \else + \endgroup + \expandafter\secondoftwoarguments + \fi} + +% used ? + +\def\doifelsenonzeropositive#1% + {\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end} + +\let\doifnonzeropositiveelse\doifelsenonzeropositive + +% here ? + +\unexpanded\def\dosetrawvalue #1#2#3{\expandafter \def\csname#1#2\endcsname{#3}} +\unexpanded\def\dosetrawevalue#1#2#3{\expandafter\edef\csname#1#2\endcsname{#3}} +\unexpanded\def\dosetrawgvalue#1#2#3{\expandafter\gdef\csname#1#2\endcsname{#3}} +\unexpanded\def\dosetrawxvalue#1#2#3{\expandafter\xdef\csname#1#2\endcsname{#3}} + +\unexpanded\def\getrawparameters {\dogetparameters\dosetrawvalue } +\unexpanded\def\getraweparameters {\dogetparameters\dosetrawevalue} +\unexpanded\def\getrawgparameters {\dogetparameters\dosetrawgvalue} +\unexpanded\def\getrawxparameters {\dogetparameters\dosetrawxvalue} + +\unexpanded\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete + +%D Sort of obsolete: + +\newcount\c_syst_helpers_mod + +\unexpanded\def\dosetmodulo#1#2#3% + {\c_syst_helpers_mod#1\divide\c_syst_helpers_mod#2\multiply\c_syst_helpers_mod#2% + #3#1\advance#3-\c_syst_helpers_mod} + +\unexpanded\def\dosetdivision#1#2#3% + {#3#1\divide#3 #2\relax} + +\unexpanded\def\DoMod#1by#2to#3{\dosetmodulo {#1}{#2}{#3}} +\unexpanded\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}} + +\def\syst_helpers_unprotected#1\par + {#1\protect} + +\unexpanded\def\unprotected + {\unprotect + \syst_helpers_unprotected} + +\let\resettimer \clf_resettimer +\let\elapsedtime \clf_elapsedtime +\let\elapsedseconds \elapsedtime + +\newcount\c_syst_helpers_test_feature_n +\newcount\c_syst_helpers_test_feature_m + +\def\currentfeaturetest{\number\c_syst_helpers_test_feature_n} + +\unexpanded\def\testfeature#1#2% + {\c_syst_helpers_test_feature_m#1\relax + \def\syst_helpers_test_feature_yes + {\advance\c_syst_helpers_test_feature_n\plusone + \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else + #2\expandafter\syst_helpers_test_feature_yes + \fi}% + \def\syst_helpers_test_feature_nop + {\advance\c_syst_helpers_test_feature_n\plusone + \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else + \expandafter\syst_helpers_test_feature_nop + \fi}% + \retestfeature} + +\unexpanded\def\retestfeature % timer support is new per 10/5/2005 + {\bgroup + \ifcase\interactionmode\let\wait\relax\fi + \clf_resettimer + \c_syst_helpers_test_feature_n\zerocount + \syst_helpers_test_feature_nop + \clf_benchmarktimer + \writestatus\m!system{starting feature test (n=\number\c_syst_helpers_test_feature_m)}\wait + \c_syst_helpers_test_feature_n\zerocount + \syst_helpers_test_feature_yes + \writestatus\m!system{\number\c_syst_helpers_test_feature_m\space feature tests done (\elapsedseconds s)}% + \wait + \egroup} + +\unexpanded\def\showtimer#1% + {\writestatus{runtime}{\elapsedseconds\space s / #1}} + +\unexpanded\def\testfeatureonce#1#2% + {\begingroup + \let\wait\relax + \testfeature{#1}{#2}% + \endgroup} + +%D \macros +%D {freezedimenmacro} +%D +%D This macro is use as: +%D +%D \starttyping +%D \freezedimenmacro\leftmargindistance +%D \stoptyping + +\unexpanded\def\freezedimenmacro#1% + {\edef#1{\the\dimexpr#1}} + +%D The next macro negates a macro (dimension or number, or actually, whatever. It's +%D a typical example of \type {\if} usage: +%D +%D \starttyping +%D \if-\whatever \else-\whatever\fi => else => -whatever +%D \if--\whatever\else-\whatever\fi => then => whatever +%D \stoptyping + +\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text + +\def\gobbleassigndimen#1\\{} + +\def\assigndimen#1#2% + {\afterassignment\gobbleassigndimen#1=#2\zeropoint\\} + +\unexpanded\def\appended#1#2#3{\expandafter#1\expandafter#2\expandafter{#2#3}} +\unexpanded\def\appendvalue #1{\expandafter\appended\expandafter \def\csname#1\endcsname} +\unexpanded\def\appendgvalue#1{\expandafter\appended\expandafter\gdef\csname#1\endcsname} + +\unexpanded\def\prepended#1#2#3% + {\t_syst_helpers_scratch{#3}% + \expandafter\expandafter\expandafter#1\expandafter\expandafter\expandafter#2\expandafter\expandafter\expandafter + {\expandafter\the\expandafter\t_syst_helpers_scratch#2}} + +\unexpanded\def\prependvalue #1{\expandafter\prepended\expandafter \def\csname#1\endcsname} +\unexpanded\def\prependgvalue#1{\expandafter\prepended\expandafter\gdef\csname#1\endcsname} + +%D \macros +%D {dowithrange} +%D +%D This one is for Mojca Miklavec, who made me aware of the fact that \type +%D {page-imp.tex} was not the best place to hide it. +%D +%D \startbuffer +%D \def\DoSomething#1{ [item #1] } +%D +%D \processranges[1,4:5]\DoSomething \par +%D \dowithrange {1,4:5}\DoSomething \par +%D \stopbuffer +%D +%D \typebuffer \blank \getbuffer \blank + +\def\syst_helpers_with_range#1% + {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to + \ifx\m_syst_helpers_range_to\empty\let\m_syst_helpers_range_to\m_syst_helpers_range_from\fi + \dostepwiserecurse\m_syst_helpers_range_from\m_syst_helpers_range_to\plusone{\m_helpers_range_action{##1}}}% + +\unexpanded\def\processranges[#1]#2% #1= n:m,p,q:r + {\def\m_helpers_range_action{#2}% + \processcommacommand[#1]\syst_helpers_with_range} + +\unexpanded\def\dowithrange#1#2% + {\def\m_helpers_range_action{#2}% + \processcommacommand[#1]\syst_helpers_with_range} + +% \def\DoSomething#1{ [item #1] } +% \dowithrange[1,4:5]\DoSomething + +%D \macros +%D {ignoreimplicitspaces} +%D +%D \startbuffer +%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces} +%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b} +%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces} +%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b} +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\unexpanded\def\ignoreimplicitspaces + {\doifelsenextchar\relax\relax\relax} + +%D \macros +%D {processwords} +%D +%D Not that sophisticated but sometimes users (like in metafun). + +\def\syst_helpers_process_word#1 #2\_e_o_w_ + {\doifsomething{#1}{\processword{#1} \syst_helpers_process_word#2 \_e_o_w_}} + +\def\processwords#1% + {\syst_helpers_process_word#1 \_e_o_w_}% no \unskip + +\let\processword\relax + +%D \macros +%D {startnointerference} +%D +%D \starttyping +%D \startnointerference +%D all kind of code +%D \stopnointerference +%D \stoptyping + +\newbox\b_syst_helpers_no_interference + +\unexpanded\def\startnointerference % not even grouped ! + {\setbox\b_syst_helpers_no_interference\vbox + \bgroup} + +\unexpanded\def\stopnointerference + {\egroup + \setbox\b_syst_helpers_no_interference\emptybox} + +%D A variant for \type {\executeifdefined}: + +\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter so let's expand it once + {\normalexpanded{\noexpand\syst_helpers_expand_checked_csname{#1}{#2}}} + +\def\syst_helpers_expand_checked_csname#1#2#3% + {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname} + +%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not +%D set in the font! (This will be overloaded) + +\unexpanded\def\signalcharacter{\char\zerocount} % \zwj + +%D A few secial variants of commands defined here. Some more will be moved here (e.g. +%D from table modules. + +\def\dodirectdoubleempty#1#2% used in math (lookahead issues) + {\ifx#2[% + \expandafter\syst_helpers_direct_double_empty_one_yes + \else + \expandafter\syst_helpers_direct_double_empty_one_nop + \fi#1#2} + +\def\syst_helpers_direct_double_empty_one_yes#1[#2]#3% + {\ifx#3[\else\expandafter\syst_helpers_direct_double_empty_two_nop\fi#1[#2]#3} + +\def\syst_helpers_direct_double_empty_one_nop#1{#1[][]} +\def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]} + +%D Used in math definitions (in an \type {\edef}): + +%D \startbuffer +%D [\docheckedpair{}] +%D [\docheckedpair{a}] +%D [\docheckedpair{a,b}] +%D [\docheckedpair{a,b,c}] +%D \stopbuffer +%D +%D \typebuffer \startlines \getbuffer \stoplines + +\def\docheckedpair#1% + {\syst_helpers_checked_pair#1,,\_o_e_p_} + +\def\syst_helpers_checked_pair#1,#2,#3\_o_e_p_ + {#1,#2} + +%D Here are some nasty helpers. They can be used to fill often expanded token +%D lists efficiently (see tabulate for an example). + +\def\constantnumber#1% + {\ifcase#1\zerocount + \or \plusone + \or \plustwo + \or \plusthree + \or \plusfour + \or \plusfive + \or \plussix + \or \plusseven + \or \pluseight + \or \plusnine + \or \plusten + \else \number#1\relax\fi} + +\def\constantnumberargument#1% + {\ifcase#1\zerocount + \or \plusone + \or \plustwo + \or \plusthree + \or \plusfour + \or \plusfive + \or \plussix + \or \plusseven + \or \pluseight + \or \plusnine + \or \plusten + \else {\number#1}\fi} + +\def\constantdimen#1% + {\ifdim#1=\zeropoint + \zeropoint + \else + \the#1\relax + \fi} + +\def\constantdimenargument#1% + {\ifdim#1=\zeropoint + \zeropoint + \else + {\the#1}% + \fi} + +\def\constantemptyargument#1% + {\ifx#1\empty + \noexpand\empty + \else + {#1}% + \fi} + +%D \macros +%D {getsubstring} +%D \startbuffer +%D +%D \getsubstring{4}{}{Who Wants This} +%D \getsubstring{4}{9}{Who Wants This} +%D \getsubstring{9}{-2}{Who Wants This} +%D \getsubstring{1}{5}{Who Wants This} +%D \stopbuffer +%D +%D \typebuffer +%D +%D \startlines +%D \getbuffer +%D \stoplines + +% expandable: + +\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}} + +%D Other dimensions than pt (used in mb-mp) + +\def\converteddimen#1#2{\clf_converteddimen\dimexpr#1\relax{#2}} + +%D Maybe (looks ugly): +%D +%D \starttyping +%D \doifcase {foo} +%D {bar} {BAR} +%D {foo} {FOO} +%D {default} {DEFAULT} +%D +%D \doifcase {foo} +%D {bar} {BAR} +%D {foo} {\doifcase {bar} +%D {bar} {BAR} +%D {foo} {FOO} +%D {default} {DEFAULT} +%D } +%D {default} {DEFAULT} +%D \stoptyping + +% \doifcase {\btxfoundname{author}} +% {author} {\btxflush{author}} +% {editor} {\texdefinition{btx:apa:editor-or-editors}} +% {title} {\texdefinition{btx:apa:title-subtitle-type}} +% {default} {\btxflush{author}} + +% \unexpanded\def\doifcase#1% +% {\edef\m_case_asked{#1}% +% \syst_aux_case} +% +% \def\syst_aux_case#1% +% {\edef\m_case_temp{#1}% +% \ifx\m_case_temp\m_case_asked +% \expandafter\syst_aux_case_yes +% \orelse\ifx\m_case_temp\s!default +% \expandafter\firstofoneargument +% \else +% \expandafter\syst_aux_case_nop +% \fi} +% +% \def\syst_aux_skip#1#2% +% {\edef\m_case_temp{#1}% +% \ifx\m_case_temp\s!default +% \expandafter\syst_aux_done +% \else +% \expandafter\syst_aux_skip +% \fi} +% +% \def\syst_aux_case_yes#1% +% {\def\syst_aux_done{#1}% +% \syst_aux_skip} +% +% \def\syst_aux_case_nop#1% +% {\syst_aux_case} + +%D \macros +%D {ntimes} +%D +%D some repetition: +%D +%D \startbuffer +%D \ntimes{*}{20} +%D \stopbuffer +%D +%D \typebuffer \blank gives: \getbuffer \blank +%D +%D This is not real fast but quite okay: + +%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72 +\def\ntimes#1#2{\clf_ntimes{#1}\numexpr#2\relax} % 0.33 + +%D Experiment (sometimes looks nicer in code): + +\unexpanded\def\sameargumentscondition#1#2% + {\edef\m_syst_string_one{#1}% + \edef\m_syst_string_two{#2}% + \ifx\m_syst_string_one\m_syst_string_two} + +\unexpanded\def\emptyargumentcondition#1% + {\edef\m_syst_string_one{#1}% + \ifx\m_syst_string_one\empty} + +\protect \endinput diff --git a/tex/context/base/mkiv/syst-ini.mkiv b/tex/context/base/mkiv/syst-ini.mkiv index 4be622d48..013f1106f 100644 --- a/tex/context/base/mkiv/syst-ini.mkiv +++ b/tex/context/base/mkiv/syst-ini.mkiv @@ -570,9 +570,7 @@ \newif\ifdone \newif\iffound -%D Potential primitive in \LUATEX: - -\ifdefined\htdp \else \def\htdp#1{\dimexpr\ht#1+\dp#1\relax} \fi +\def\htdp#1{\dimexpr\ht#1+\dp#1\relax} %D A few shortcuts: diff --git a/tex/context/base/mkiv/syst-ini.mkxl b/tex/context/base/mkiv/syst-ini.mkxl new file mode 100644 index 000000000..8f89d9221 --- /dev/null +++ b/tex/context/base/mkiv/syst-ini.mkxl @@ -0,0 +1,1075 @@ +%D \module +%D [ file=syst-ini, +%D version=2008.11.04, % 2001.11.16, % 1999.03.17, % an oldie: 1995.10.10 +%D title=\CONTEXT\ System Macros, +%D subtitle=Bootstrapping \TEX, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D We used to load plain \TEX\ in a special way, but redefining a couple of +%D primitives so that for instance font loading was ignored. For those interested, +%D this loader is found in \type {syst-tex.tex}. Some of the comment's are Don +%D Knuths and more of it can be found in the plain \TEX\ format. +%D +%D Characters can have special states, that can be triggered by setting their +%D category coded. Some are preset, others are to be set as soon as possible, +%D otherwise we cannot define any useful macros. +%D +%D First we define a bunch of constants. Normally we would \type {\setconstant} +%D but we're prestine and have no macros defined yet. Abstraction also makes it +%D possible to avoid the \type {^^} in the input. + +\chardef\escapecatcode 0 +\chardef\begingroupcatcode 1 +\chardef\endgroupcatcode 2 +\chardef\mathshiftcatcode 3 +\chardef\alignmentcatcode 4 +\chardef\endoflinecatcode 5 +\chardef\parametercatcode 6 +\chardef\superscriptcatcode 7 +\chardef\subscriptcatcode 8 +\chardef\ignorecatcode 9 +\chardef\spacecatcode 10 +\chardef\lettercatcode 11 +\chardef\othercatcode 12 % finally obsolete: \let\other \othercatcode +\chardef\activecatcode 13 % finally obsolete: \let\active\activecatcode +\chardef\commentcatcode 14 +\chardef\invalidcatcode 15 + +%chardef\zeroasciicode 0 +\chardef\tabasciicode 9 +\chardef\newlineasciicode 10 % don't confuse this one with \endoflineasciicode +\chardef\formfeedasciicode 12 +\chardef\endoflineasciicode 13 % somewhat messy but this can be the active \par +\chardef\endoffileasciicode 26 +\chardef\spaceasciicode 32 +\chardef\exclamationmarkasciicode 33 % ! used in namespace protection +\chardef\doublequoteasciicode 34 % " +\chardef\hashasciicode 35 +\chardef\dollarasciicode 36 +\chardef\commentasciicode 37 +\chardef\ampersandasciicode 38 +\chardef\singlequoteasciicode 39 % ' +\chardef\primeasciicode 39 % ' +\chardef\leftparentasciicode 40 +\chardef\rightparentasciicode 41 +\chardef\hyphenasciicode 45 +\chardef\forwardslashasciicode 47 % / +\chardef\colonasciicode 58 +\chardef\lessthanasciicode 60 % < used as alternative verbatim { +\chardef\morethanasciicode 62 % > used as alternative verbatim } +\chardef\questionmarkasciicode 63 % ? used in namespace protection +\chardef\atsignasciicode 64 % @ used in namespace protection +\chardef\backslashasciicode 92 % `\\ +\chardef\circumflexasciicode 94 +\chardef\underscoreasciicode 95 +\chardef\leftbraceasciicode 123 % `\{ +\chardef\barasciicode 124 % `\| +\chardef\rightbraceasciicode 125 % `\} +\chardef\tildeasciicode 126 % `\~ +\chardef\delasciicode 127 + +%catcode\zeroasciicode \ignorecatcode % `\^^@ ascii null is ignored +\catcode\tabasciicode \spacecatcode % `\^^I ascii tab is a blank space +\catcode\formfeedasciicode \activecatcode % `\^^L ascii form-feed (active, set later) +%catcode\endoflineasciicode \endoflinecatcode % `\^^M ascii return is end-line +\catcode\endoffileasciicode \ignorecatcode % `\^^Z endoffile (ignored in ConTeXt) +%catcode\spaceasciicode \spacecatcode % `\ ascii space is blank space +\catcode\hashasciicode \parametercatcode % `\# hash mark is macro parameter character +\catcode\dollarasciicode \mathshiftcatcode % `\$ dollar sign is math shift +%catcode\commentasciicode \commentcatcode % `\% percent sign is comment character +\catcode\ampersandasciicode \alignmentcatcode % `\& ampersand is alignment tab +%catcode\backslashasciicode \escapecatcode % `\\ backslash is TeX escape character +\catcode\circumflexasciicode \superscriptcatcode % `\^ circumflex and uparrow are for superscripts +\catcode\underscoreasciicode \subscriptcatcode % `\_ underline and downarrow are for subscripts +\catcode\leftbraceasciicode \begingroupcatcode % `\{ left brace is begin-group character +\catcode\rightbraceasciicode \endgroupcatcode % `\} right brace is end-group character +\catcode\tildeasciicode \activecatcode % `\~ tilde is active +%catcode\delasciicode \invalidcatcode % `\^^? ascii delete is invalid + +\chardef\statuswrite 128 + +%D Initialization of primitives. + +\directlua { + local baseprimitives = tex.extraprimitives("core","tex") + local moreprimitives = tex.extraprimitives("etex","luatex") + + tex.enableprimitives("",moreprimitives) + + tex.enableprimitives("normal",baseprimitives) + tex.enableprimitives("normal",moreprimitives) + + function tex.enableprimitives() end +} + +\def\space{ } +\def\empty{} + +\letcharcode \formfeedasciicode \par % \def ^^L{\par} formfeed +\letcharcode \tildeasciicode \ % tilde +\letcharcode \spaceasciicode \space % space + +\expandafter\def\csname\Uchar\tabasciicode \endcsname {\ } % \def\^^I{\ } tab +\expandafter\def\csname\Uchar\formfeedasciicode \endcsname {\par} % \def\^^L{\par} formfeed +\expandafter\def\csname\Uchar\endoflineasciicode\endcsname {\ } % \def\^^M{\ } return + +%D For now: + +\def\gobbleoneargument#1{} % will be defined later on anyway + +%D First we define a simplified version of the \CONTEXT\ protection mechanism. +%D Later we will implement a better variant. + +\def\unprotect + {\edef\protect + {\catcode\atsignasciicode \the\catcode\atsignasciicode \relax + \catcode\exclamationmarkasciicode\the\catcode\exclamationmarkasciicode\relax + \catcode\questionmarkasciicode \the\catcode\questionmarkasciicode \relax + \catcode\underscoreasciicode \the\catcode\underscoreasciicode \relax + \let\protect\relax}% + \catcode\atsignasciicode \lettercatcode + \catcode\exclamationmarkasciicode\lettercatcode + \catcode\questionmarkasciicode \lettercatcode + \catcode\underscoreasciicode \lettercatcode} + +\let\protect\relax + +\unprotect + +%D Some pretty important definitions: + +\let\bgroup={ +\let\egroup=} + +%D \macros +%D {normalbgroup,normalgroup} +%D +%D No comment. + +%D Allocation of registers is done slightly different than in plain \TEX. First of +%D all we use different reserved counters. We also don't implement a family handler +%D because users are not supposed to implement their own math. We reserve the lowest +%D 31 registers for scratch purposes. Keep in mind that in the core engine some +%D registers are reserved: counters 0 upto 9, and counter 255. +%D +%D As with plain \TEX\ we recommend that macro designers always use \type {\global} +%D assignments with respect to registers numbered 1, 3, 5 \unknown\ 31, and always +%D non||\type {\global} assignments with respect to registers 0, 2, 4, \unknown\ 30. +%D This will prevent \quote {save stack buildup} that might otherwise occur. +%D +%D We reserve some registers for special (management) purposes: + +% 0 - 20 : scratch +% 21 - 127 : internal +% 128 - 254 : inserts +% 255 : page +% 256 - : user + +\countdef \c_syst_min_allocated_register = 52 \c_syst_min_allocated_register = 256 % can change +\countdef \c_syst_max_allocated_register = 53 \c_syst_max_allocated_register = 32767 +\countdef \c_syst_min_allocated_read = 54 \c_syst_min_allocated_read = -1 +\countdef \c_syst_max_allocated_read = 55 \c_syst_max_allocated_read = 16 +\countdef \c_syst_min_allocated_language = 56 \c_syst_min_allocated_language = 0 +\countdef \c_syst_max_allocated_language = 57 \c_syst_max_allocated_language = 255 +\countdef \c_syst_min_allocated_insert = 58 \c_syst_min_allocated_insert = 128 +\countdef \c_syst_max_allocated_insert = 59 \c_syst_max_allocated_insert = 254 +\countdef \c_syst_min_allocated_family = 60 \c_syst_min_allocated_family = 128 +\countdef \c_syst_max_allocated_family = 61 \c_syst_max_allocated_family = 255 +\countdef \c_syst_min_allocated_attribute = 62 \c_syst_min_allocated_attribute = 1024 % 0-1023 : private +\countdef \c_syst_min_allocated_write = 63 \c_syst_min_allocated_write = 0 +\countdef \c_syst_max_allocated_write = 64 \c_syst_max_allocated_write = 127 + +\countdef \c_syst_last_allocated_count = 32 \c_syst_last_allocated_count = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_dimen = 33 \c_syst_last_allocated_dimen = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_skip = 34 \c_syst_last_allocated_skip = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_muskip = 35 \c_syst_last_allocated_muskip = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_box = 36 \c_syst_last_allocated_box = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_toks = 37 \c_syst_last_allocated_toks = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_read = 38 \c_syst_last_allocated_read = \c_syst_min_allocated_read +\countdef \c_syst_last_allocated_write = 39 \c_syst_last_allocated_write = \c_syst_min_allocated_write +\countdef \c_syst_last_allocated_marks = 40 \c_syst_last_allocated_marks = \c_syst_min_allocated_register +\countdef \c_syst_last_allocated_language = 41 \c_syst_last_allocated_language = \c_syst_min_allocated_language % not used in context +\countdef \c_syst_last_allocated_insertion = 42 \c_syst_last_allocated_insertion = \c_syst_min_allocated_insert +\countdef \c_syst_last_allocated_family = 43 \c_syst_last_allocated_family = \c_syst_min_allocated_family % not used in context +\countdef \c_syst_last_allocated_attribute = 44 \c_syst_last_allocated_attribute = \c_syst_min_allocated_attribute % not used in context + +\countdef \c_syst_min_counter_value = 125 \c_syst_min_counter_value = -"7FFFFFFF % beware, we use index 125 at the lua end +\countdef \c_syst_max_counter_value = 126 \c_syst_max_counter_value = "7FFFFFFF % beware, we use index 126 at the lua end + +\countdef \zerocount = 120 \zerocount = 0 +\countdef \plusone = 121 \plusone = 1 +\countdef \minusone = 122 \minusone = -1 + +\countdef \normalpagebox = 127 \normalpagebox = 255 % hardcoded in pdftex/xetex + +% Only to be used by developers in very special cases! + +% \def\lastallocatedcount {\the\c_syst_last_allocated_count} +% \def\lastallocateddimen {\the\c_syst_last_allocated_dimen} +% \def\lastallocatedskip {\the\c_syst_last_allocated_skip} +% \def\lastallocatedmuskip {\the\c_syst_last_allocated_muskip} +% \def\lastallocatedbox {\the\c_syst_last_allocated_dimen} +% \def\lastallocatedtoks {\the\c_syst_last_allocated_toks} +% \def\lastallocatedattribute{\the\c_syst_last_allocated_attribute} + +% A few traditional allocations (these might go): + +\countdef \count@ 255 % hm, used in \newif .. todo: replace it there +\dimendef \dimen@ 0 +\dimendef \dimen@i 1 % global only +\dimendef \dimen@ii 2 + +%D So, effectively we start allocating from 256 and upwards. The inserts sit in the +%D range 128 upto 254. Page numbers use the counters 0 upto 9 and the pagebox is +%D 255. Users can use the scratch registers upto 31 without problem but all others +%D are reserved. + +\let\wlog\gobbleoneargument % Let's get rid of this one. + +%D The allocators share a common helper macro. + +\normalprotected\def\newcount {\syst_basics_allocate\c_syst_last_allocated_count \count \countdef \c_syst_max_allocated_register} +\normalprotected\def\newdimen {\syst_basics_allocate\c_syst_last_allocated_dimen \dimen \dimendef \c_syst_max_allocated_register} +\normalprotected\def\newskip {\syst_basics_allocate\c_syst_last_allocated_skip \skip \skipdef \c_syst_max_allocated_register} +\normalprotected\def\newmuskip {\syst_basics_allocate\c_syst_last_allocated_muskip \muskip \muskipdef \c_syst_max_allocated_register} +\normalprotected\def\newbox {\syst_basics_allocate\c_syst_last_allocated_box \box \mathchardef\c_syst_max_allocated_register} +\normalprotected\def\newtoks {\syst_basics_allocate\c_syst_last_allocated_toks \toks \toksdef \c_syst_max_allocated_register} +\normalprotected\def\newread {\syst_basics_allocate\c_syst_last_allocated_read \read \chardef \c_syst_max_allocated_read} +\normalprotected\def\newwrite {\syst_basics_allocate\c_syst_last_allocated_write \write \chardef \c_syst_max_allocated_write} +\normalprotected\def\newmarks {\syst_basics_allocate\c_syst_last_allocated_marks \marks \mathchardef\c_syst_max_allocated_register} +\normalprotected\def\newinsert {\syst_basics_allocate\c_syst_last_allocated_insertion\insert \chardef \c_syst_max_allocated_insert} + +%D We don't need these in \CONTEXT: + +\normalprotected\def\newlanguage{\syst_basics_allocate\c_syst_last_allocated_language \language\chardef \c_syst_max_allocated_language} +\normalprotected\def\newfamily {\syst_basics_allocate\c_syst_last_allocated_family \fam \chardef \c_syst_max_allocated_family} + +\let\newfam\newfamily + +\firstvalidlanguage\plusone + +% Watch out, for the moment we disable the check for already being defined +% later we will revert this but first all chardefs must be replaced. + +\normalprotected\def\newconstant #1{\ifdefined#1\let#1\undefined\fi\newcount#1} +\normalprotected\def\setnewconstant #1{\ifdefined#1\let#1\undefined\fi\newcount#1#1} % just a number +\normalprotected\def\setconstant {} % dummy, no checking, so it warns +\normalprotected\def\setconstantvalue#1#2{\csname#1\endcsname\numexpr#2\relax} + +% maybe setconstant with check + +% %D The next definitions are really needed (in \CONTEXT): + +\newlinechar\newlineasciicode \edef\outputnewlinechar{\Uchar\newlineasciicode} % {^^J} + +%D One reason to start high with allocation is that it permits us to allocate +%D consecutive ranges more easily, for instance if for \MPLIB\ we want to allocate a +%D continuous range of boxes. It also permits us to do a proper upward allocation +%D for inserts. The current code evolved from code that dealt with older engines but +%D as all engines now provide many registers we removed all traces. + +\ifdefined\writestatus \else + %\normalprotected\def\writestatus#1#2{\immediate\write\statuswrite{#1: #2}} + \normalprotected\def\writestatus#1#2{\message{#1: #2}} +\fi + +\def\syst_basics_allocate_yes#1#2#3#4#5% last class method max name + {\ifnum#1<#4\relax + \global\advance#1\plusone + \global#3#5=#1\relax + \else + \writestatus{warning}{no room for \string#2\space \string#5\space (max: \number#4)}% + \fi} + +\def\syst_basics_allocate_nop#1#2#3#4#5% last class method max name + {\writestatus{warning}{\string#2 \string#5 is already defined (\string\relax\space it first)}} + +\def\syst_basics_allocate#1#2#3#4#5% last class method max name + {\ifx#5\undefined + \expandafter\syst_basics_allocate_yes + \else\ifx#5\relax + \expandafter\expandafter\expandafter\syst_basics_allocate_yes + \else + \expandafter\expandafter\expandafter\syst_basics_allocate_nop + \fi\fi + #1#2#3#4#5} + +%D Since the number of chars exceed 256 now, we can use \type {\chardef} instead of +%D the more limited \type {\mathchardef}. + +\normalprotected\def\newbox {\syst_basics_allocate\c_syst_last_allocated_box \box \chardef\c_syst_max_allocated_register} +\normalprotected\def\newmarks{\syst_basics_allocate\c_syst_last_allocated_marks\marks\chardef\c_syst_max_allocated_register} + +%D Attributes are something very \LUATEX. In \CONTEXT\ you are not supposed to use +%D the attributes directly but always allocate then first. For instance attribute~0 +%D is reserved for special purposes (this might change). Attributes in the range +%D 128-1023 are private and should not be touched. + +\let\attributeunsetvalue\c_syst_min_counter_value % used to be \minusone + +\normalprotected\def\newattribute{\syst_basics_allocate\c_syst_last_allocated_attribute\attribute\attributedef\c_syst_max_allocated_register} + +%D Not used by \CONTEXT\ but for instance \PICTEX\ needs it. It's a trick to force +%D strings instead of tokens that take more memory. It's a trick to trick to force +%D strings. This macro is never used in \CONTEXT. + +%normalprotected\def\newhelp#1#2{\newtoks#1#1\expandafter{\csname#2\endcsname}} +\normalprotected\def\newhelp#1#2{\newtoks#1#1\expandafter{\detokenize{#2}}} + +%D \macros +%D {scratchcounter, +%D scratchdimen,scratchskip,scratchmuskip, +%D scratchbox, +%D scratchtoks} +%D +%D We now define a few scratch registers, so that successive loads at least have +%D some available. The private ones are used in cases where we don't want to +%D intrude on normal scratch ones. + +\newcount \scratchcounter \newcount \globalscratchcounter \newcount \privatescratchcounter +\newdimen \scratchdimen \newdimen \globalscratchdimen \newdimen \privatescratchdimen +\newskip \scratchskip \newskip \globalscratchskip \newskip \privatescratchskip +\newmuskip\scratchmuskip \newmuskip\globalscratchmuskip \newmuskip\privatescratchmuskip +\newtoks \scratchtoks \newtoks \globalscratchtoks \newtoks \privatescratchtoks +\newbox \scratchbox \newbox \globalscratchbox \newbox \privatescratchbox + +\newcount\scratchcounterone \newcount\scratchcountertwo \newcount\scratchcounterthree +\newdimen \scratchdimenone \newdimen \scratchdimentwo \newdimen \scratchdimenthree +\newskip \scratchskipone \newskip \scratchskiptwo \newskip \scratchskipthree +\newmuskip\scratchmuskipone \newmuskip\scratchmuskiptwo \newmuskip\scratchmuskipthree +\newtoks \scratchtoksone \newtoks \scratchtokstwo \newtoks \scratchtoksthree +\newbox \scratchboxone \newbox \scratchboxtwo \newbox \scratchboxthree + +\newcount\scratchcounterfour \newcount\scratchcounterfive \newcount\scratchcountersix +\newdimen \scratchdimenfour \newdimen \scratchdimenfive \newdimen \scratchdimensix +\newskip \scratchskipfour \newskip \scratchskipfive \newskip \scratchskipsix +\newmuskip\scratchmuskipfour \newmuskip\scratchmuskipfive \newmuskip\scratchmuskipsix +\newtoks \scratchtoksfour \newtoks \scratchtoksfive \newtoks \scratchtokssix +\newbox \scratchboxfour \newbox \scratchboxfive \newbox \scratchboxsix + +\newcount\globalscratchcounterone +\newcount\globalscratchcountertwo +\newcount\globalscratchcounterthree + +%D \macros +%D {tempstring} + +\let\tempstring\empty + +%D \macros +%D {scratchwidth, scratchheight, scratchdepth, scratchoffset, scratchdistance} +%D +%D A few more scratch dimensions: + +\newdimen\scratchwidth +\newdimen\scratchheight +\newdimen\scratchdepth + +\newdimen\scratchoffset +\newdimen\scratchleftoffset +\newdimen\scratchrightoffset +\newdimen\scratchtopoffset +\newdimen\scratchbottomoffset + +\newdimen\scratchdistance + +\newdimen\scratchhsize +\newdimen\scratchvsize + +\newdimen\scratchxoffset +\newdimen\scratchyoffset +\newdimen\scratchhoffset +\newdimen\scratchvoffset + +\newdimen\scratchxposition +\newdimen\scratchyposition + +\newcount\scratchnx +\newcount\scratchny + +\newcount\scratchmx +\newcount\scratchmy + +\newcount\scratchmin +\newcount\scratchmax + +\newcount\scratchunicode + +\newdimen\scratchleftskip +\newdimen\scratchrightskip +\newdimen\scratchtopskip +\newdimen\scratchbottomskip + +%D More allocations: + +\newskip \zeroskip \zeroskip 0pt plus 0pt minus 0pt +\newdimen \zeropoint \zeropoint 0pt +\newdimen \onepoint \onepoint 1pt +\newdimen \halfapoint \halfapoint 0.5pt +\newdimen \maxdimen \maxdimen 16383.99999pt % 1073741823sp +\newcount \maxcount \maxcount 2147483647 +\newdimen \onebasepoint \onebasepoint 1bp +\newdimen \scaledpoint \scaledpoint 1sp +\newdimen \thousandpoint \thousandpoint 1000pt +\newmuskip\zeromuskip \zeromuskip 0mu +\newmuskip\onemuskip \onemuskip 1mu + +\newmuskip\muquad \muquad 18mu + +\let\points \onepoint +\let\halfpoint\halfapoint + +\newtoks \emptytoks + +%D And even more: (todo: countdefs 60+) + +%newcount\minusone \minusone -1 +\newcount\minustwo \minustwo -2 +%chardef \zerocount 0 +%chardef \plusone 1 +\chardef \plustwo 2 +\chardef \plusthree 3 +\chardef \plusfour 4 +\chardef \plusfive 5 +\chardef \plussix 6 +\chardef \plusseven 7 +\chardef \pluseight 8 +\chardef \plusnine 9 +\chardef \plusten 10 +\chardef \plussixteen 16 +\chardef \plusfifty 50 +\chardef \plushundred 100 +\chardef \plusonehundred 100 +\chardef \plustwohundred 200 +\chardef \plusfivehundred 500 +\chardef \pluscxxvii 127 +\chardef \pluscxxviii 128 +\chardef \pluscclv 255 +\chardef \pluscclvi 256 +\chardef \plusthousand 1000 +\chardef \plustenthousand 10000 +\chardef \plustwentythousand 20000 +\chardef \medcard 32768 +\chardef \maxcard 65536 % pdftex has less mathchars +\chardef \maxcardminusone 65535 + +%D \macros +%D {doubleexpandafter,tripleexpandafter,expanded,startexpanded} +%D +%D A few handy shortcuts + +\let\singleexpandafter \expandafter +\def\doubleexpandafter{\expandafter\expandafter\expandafter} +\def\tripleexpandafter{\expandafter\doubleexpandafter\expandafter} + +%D We prefer the more readable variant than in plain \TEX. User should only +%D use \type {\emptybox}: + +\newbox\voidbox % public + +\let\normalhbox\hbox +\let\normalvbox\vbox + +\def\unvoidbox{\unhbox\voidbox} +\def\emptybox {\box \voidbox} % used in initializations so no attributes +\def\emptyvbox{\normalvpack{}} % no copy as we need to set attributes +\def\emptyhbox{\normalhpack{}} % no copy as we need to set attributes + +\let\leavevmode\unvoidbox % we prefer to use \dontleavehmode + +%D \macros +%D {dontcomplain} +%D +%D We need this one soon: + +\normalprotected\def\dontcomplain + {\hbadness\plustenthousand + \vbadness\plustenthousand + \hfuzz \maxdimen + \vfuzz \maxdimen} + +%D Some expected plain variants follow. We don't reuse registers because we +%D don't want clashes. + +\let \p@ \onepoint +\let \m@ne \minusone +\let \z@ \zeropoint +\let \@ne \plusone +\let \tw@ \plustwo +\let \thr@@ \plusthree +\let \sixt@@n \plussixteen +\let \@cclv \pluscclv +\let \@cclvi \pluscclvi +\let \voidb@x \voidbox +\newtoks \toks@ % \scratchtoks + +%D We define \type {\newif} a la plain \TEX, but will redefine it later. As +%D Knuth says: +%D +%D \startnarrower +%D And here's a different sort of allocation: for example, +%D +%D \starttyping +%D \newif\iffoo +%D \stoptyping +%D +%D creates \type {\footrue}, \type {\foofalse} to go with \type {\iffoo}. +%D \stopnarrower + +% \normalprotected\def\newif#1% +% {\count@\escapechar +% \escapechar\minusone +% \expandafter\expandafter\expandafter\def\new_if #1{true}{\let#1\iftrue }% +% \expandafter\expandafter\expandafter\def\new_if#1{false}{\let#1\iffalse}% +% \new_if#1{false}% the condition starts out false +% \escapechar\count@} +% +% \def\new_if#1#2% +% {\csname\expandafter\if@\string#1#2\endcsname} +% +% \bgroup % `if' is required +% \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}} +% \egroup + +% We use \csstring so there is no need to push/pop escapechar. +% We use different names so that we get a better error message. +% +% \normalprotected\def\newif#1% +% {\let\new_if_saved\newif +% \let\newif\new_if_check +% \expandafter\expandafter\expandafter\def\new_if_cs #1{true}{\let#1\iftrue }% +% \expandafter\expandafter\expandafter\def\new_if_cs#1{false}{\let#1\iffalse}% +% \new_if_cs#1{false}% +% \let\newif\new_if_saved} +% +% \normalprotected\def\new_if_cs#1#2% +% {\csname\expandafter\newif\csstring#1#2\endcsname} +% +% We wrap all into one macro: + +\normalprotected\def\newif#1% + {\let\new_if_saved\newif + \let\newif\new_if_check + \expandafter\def\csname\expandafter\newif\csstring#1true\endcsname {\let#1\iftrue }% + \expandafter\def\csname\expandafter\newif\csstring#1false\endcsname{\let#1\iffalse}% + \csname\expandafter\newif\csstring#1false\endcsname + \let\newif\new_if_saved} + +\bgroup + \normalexpanded{\gdef\noexpand\new_if_check\string i\string f{}} +\egroup + +%D Let's test this one: + +\newif\ifdone +\newif\iffound + +\let\htdp\boxtotal + +%D A few shortcuts: + +\normalprotected\def\udef {\normalprotected\def } +\normalprotected\def\ugdef{\normalprotected\gdef} +\normalprotected\def\uedef{\normalprotected\edef} +\normalprotected\def\uxdef{\normalprotected\xdef} + +%D For a while we keep the following, as systems like tikz need it. Best +%D not use that one \CONTEXT. + +\let\active\activecatcode + +%D Constants to be used with \type {\currentgrouptype}. + +\chardef\bottomlevelgroupcode = 0 +\chardef\simplegroupcode = 1 +\chardef\hboxgroupcode = 2 +\chardef\adjustedhboxgroupcode = 3 +\chardef\vboxgroupcode = 4 +\chardef\vtopgroupcode = 5 +\chardef\aligngroupcode = 6 +\chardef\noaligngroupcode = 7 +\chardef\outputgroupcode = 8 +\chardef\mathgroupcode = 9 +\chardef\discretionarygroupcode = 10 +\chardef\insertgroupcode = 11 +\chardef\vcentergroupcode = 12 +\chardef\mathchoicegroupcode = 13 +\chardef\semisimplegroupcode = 14 +\chardef\mathshiftgroupcode = 15 +\chardef\mathleftgroupcode = 16 +\chardef\vadjustgroupcode = \insertgroupcode + +%D Constants to be used with \type {\interactionmode}. + +\chardef\batchmodecode \zerocount +\chardef\nonstopmodecode \plusone +\chardef\scrollmodecode \plustwo +\chardef\errorstopmodecode \plusthree + +%D Constants to be used with \type {\lastnodetype}. The \type {\lastnodetype} +%D primitive is \ETEX\ compliant. The valid range is still -1 .. 15 and glyph nodes +%D have number 0 (used to be char node) and ligature nodes are mapped to 7. That way +%D macro packages can use the same symbolic names as in traditional \ETEX. Keep in +%D mind that the internal node numbers are different and that there are more node +%D types that 15. The mode parameter forces \LUAMETATEX\ to use the real node +%D numbers. + +\internalcodesmode\plusone + +%D Constants to be used with \type {\currentiftype}. I wonder if we will ever +%D use these in \CONTEXT. We have a few more anyway and in \LUAMETATEX\ we +%D have different numbers. So for now let's just not define them. The +%D previously mentioned mode parameters enables the real numbers (we have +%D some more and they are therefore ordered differently). + +% \chardef\charifcode = 1 +% \chardef\catifcode = 2 +% \chardef\numifcode = 3 +% \chardef\dimifcode = 4 +% \chardef\oddifcode = 5 +% \chardef\vmodeifcode = 6 +% \chardef\hmodeifcode = 7 +% \chardef\mmodeifcode = 8 +% \chardef\innerifcode = 9 +% \chardef\voidifcode = 10 +% \chardef\hboxifcode = 11 +% \chardef\vboxifcode = 12 +% \chardef\xifcode = 13 +% \chardef\eofifcode = 14 +% \chardef\trueifcode = 15 +% \chardef\falseifcode = 16 +% \chardef\caseifcode = 17 +% \chardef\definedifcode = 18 +% \chardef\csnameifcode = 19 +% \chardef\fontcharifcode = 20 + +%D Of course we want even bigger log files, so we copied this from the \ETEX\ +%D source files. +%D +%D When watching such logs, beware of nasty side effects of \type {\scantokens}, +%D as in: +%D +%D \starttyping +%D \bgroup +%D \lccode`a=12\lowercase{\xdef\whatever{a}}\egroup +%D \def\whatever{test \whatever test} +%D \scantokens\expandafter{\whatever} +%D \egroup +%D \stoptyping +%D +%D In \LUATEX\ we have ways around this. + +% no longer \errorstopmode cf. plain tex 3.141592653 + +\normalprotected\def\tracingall + {\tracingonline \plusone + \tracingcommands \plusthree + \tracingstats \plustwo + \tracingpages \plusone + \tracingoutput \plusone + \tracinglostchars \plustwo + \tracingmacros \plustwo + \tracingparagraphs\plusone + \tracingrestores \plusone + \showboxbreadth \maxdimen + \showboxdepth \maxdimen + \tracinggroups \plusone + \tracingifs \plusone + \tracingscantokens\plusone + \tracingnesting \plusone + \tracingassigns \plustwo} + +\normalprotected\def\loggingall + {\tracingall + \tracingonline \zerocount} + +\normalprotected\def\tracingnone + {\tracingassigns \zerocount + \tracingnesting \zerocount + \tracingscantokens\zerocount + \tracingifs \zerocount + \tracinggroups \zerocount + \showboxdepth \plusthree + \showboxbreadth \plusfive + \tracingrestores \zerocount + \tracingparagraphs\zerocount + \tracingmacros \zerocount + \tracinglostchars \plusone + \tracingoutput \zerocount + \tracingpages \zerocount + \tracingstats \zerocount + \tracingcommands \zerocount + \tracingonline \zerocount} + +%D When we want to see a box we can as well show all of it. + +\showboxdepth \maxdimen +\showboxbreadth\maxdimen + +%D Just for tracing purposes we set: + +\tracingstats\plusone + +%D Here we also save \type {\input}, more will be saved later. + +\ifdefined\normalinput \else \let\normalinput\input \fi + +%D We don't like outer commands, and we always want access to the original +%D \type {\input} primitive. + +\let\normalouter\outer \def\outer{} % no longer \relax + +%D To circumvent dependencies, we can postpone certain initializations to +%D dumping time, by appending them to the \type {\everydump} token register. + +\ifdefined\normaldump \else \let\normaldump\dump \fi + +\newtoks\everydump + +\def\dump{\the\everydump\normaldump} + +%D The same applies for the startup actions. + +\ifdefined\normaleveryjob \else \let\normaleveryjob\everyjob \fi + +\let\everyjob\relax \newtoks\everyjob + +\normaleveryjob{\the\everyjob} + +%D \macros +%D {newconditional, +%D settrue, setfalse, +%D ifconditional,then} +%D +%D \TEX's lacks boolean variables, although the \PLAIN\ format implements \type +%D {\newif}. The main disadvantage of this scheme is that it takes three hash table +%D entries. A more memory saving alternative is presented here. A conditional is +%D defined by: +%D +%D \starttyping +%D \newconditional\doublesided +%D \setfalse +%D \stoptyping +%D Setting a conditional is done by \type{\settrue} and +%D \type{\setfalse}: +%D +%D \starttyping +%D \settrue\doublesided +%D \setfalse +%D \stoptyping +%D while testing is accomplished by: +%D +%D \starttyping +%D \ifconditional\doublesided ... \else ... \fi +%D \setfalse +%D \stoptyping +%D We cannot use the simple scheme: +%D +%D \starttyping +%D \def\settrue #1{\let#1=\iftrue} +%D \def\setfalse#1{\let#1=\iffalse} +%D \stoptyping +%D +%D Such an implementation gives problems with nested conditionals. The next +%D implementation is about as fast and just as straightforward: + +\let\conditionalfalse\plusone % maybe we will have a dedicated count/chardef +\let\conditionaltrue \zerocount % maybe we will have a dedicated count/chardef + +\normalprotected\def\settrue #1{\let#1\conditionaltrue } +\normalprotected\def\setfalse#1{\let#1\conditionalfalse} + +\normalprotected\def\settruevalue #1{\expandafter\let\csname#1\endcsname\conditionaltrue } +\normalprotected\def\setfalsevalue#1{\expandafter\let\csname#1\endcsname\conditionalfalse} + +\let\newconditional\setfalse +\let\ifconditional \ifcase + +\let\then\relax % so that we can say: \ifnum1>2\then -) + +% This one has to be unprotected otherwise we get a files-ends-to-soon but it's ok +% as conditions expand anyway. + +\def\quitcondition{\orelse\iffalse} + +%D \macros +%D {newmacro,setnewmacro,newfraction} +%D +%D Let's be complete and also introduce some definers. These are not mandate +%D but handy for grepping. + +\normalprotected\def\newmacro #1{\let#1\empty} +\normalprotected\def\setnewmacro#1{\let#1} + +\def\!!zerocount{0} +\def\!!plusone {1} + +\normalprotected\def\newfraction#1{\let#1\!!plusone} + +%D It would be handy to have a primitive \type {\unless\ifcase} because then we +%D could use nicer values. Anyhow, this conditional code used to be in the \type +%D {syst-aux} module but is now promoted to here. + +%D \macros +%D {ifzeropt} +%D +%D The next macro is both cosmetic and byte saving. It is pretty \type +%D {\if}||safe too. It can be used in cases like: +%D +%D \starttyping +%D \ifzeropt \somedimen ... \else ... \fi +%D \stoptyping + +\let\ifzeropt\ifcase + +% these token list helpers might move to syst-aux.mkiv +% +% we assume a \cs. not toks0 or so +% +% \normalprotected\def\appendtotoks #1#{\def\temp{#1}\afterassignment\doappendtotoks \scratchtoks=} +% \normalprotected\def\prependtotoks#1#{\def\temp{#1}\afterassignment\doprependtotoks\scratchtoks=} + +\newtoks\t_syst_toks_temp \let\m_syst_toks_temp\t_syst_toks_temp + +\normalprotected\def\appendtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_append_l \t_syst_toks_temp=} +\normalprotected\def\prependtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_prepend_l\t_syst_toks_temp=} + +% \def\syst_toks_append {\m_syst_toks_temp\expandafter\expandafter\expandafter{\expandafter\the\expandafter\m_syst_toks_temp\the\t_syst_toks_temp}}} +% \def\syst_toks_prepend{\m_syst_toks_temp\expandafter\expandafter\expandafter{\expandafter\the\expandafter\t_syst_toks_temp\the\m_syst_toks_temp}}} + +\normalprotected\def\globalappendtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_append_g \t_syst_toks_temp=} +\normalprotected\def\globalprependtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_prepend_g\t_syst_toks_temp=} + +\def\syst_toks_append_l {\normalexpanded{\m_syst_toks_temp{\the\m_syst_toks_temp\the\t_syst_toks_temp}}} +\def\syst_toks_prepend_l{\normalexpanded{\m_syst_toks_temp{\the\t_syst_toks_temp\the\m_syst_toks_temp}}} + +\def\syst_toks_append_g {\global\syst_toks_append_l } +\def\syst_toks_prepend_g{\global\syst_toks_prepend_l} + +\normalprotected\def\addtotoks #1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_add_l\let\next} +\normalprotected\def\globaladdtotoks#1{\let\m_syst_toks_temp#1\afterassignment\syst_toks_add_g\let\next} + +\def\syst_toks_add_l{\m_syst_toks_temp\expandafter\bgroup\the\m_syst_toks_temp} +\def\syst_toks_add_g{\global\syst_toks_add_l} + +\normalprotected\def\addtotokscs #1#2{#1{\the#1#2}} % saves a few bytes +\normalprotected\def\globaladdtotokscs#1#2{\global#1{\the#1#2}} % saves a few bytes + +%D \macros +%D {begcsname} +%D +%D Handy for \ETEX-only usage (avoids making \type {\relax}'s: + +% \def\begcsname#1\endcsname{\ifcsname#1\endcsname\csname#1\endcsname\fi} + +\let\begcsname\begincsname + +%D Now come a few macros that might be needed in successive loading. We redefine the +%D \type {\par} primitive pretty soon so that we get the equivalents right. + +% too tricky: \par is use more often than a par starts so we have too much change +% that we get assymetrical behaviour +% +% \newtoks\everyendpar +% +% \normalprotected\def\endpar{\the\everyendpar\normalpar} +% \normalprotected\def\par {\endpar} +% +% \normalprotected\def\reseteverypar +% {\everypar \emptytoks +% \everyendpar\emptytoks} + +\normalprotected\def\reseteverypar + {\everypar\emptytoks} + +\let\endgraf\par +\let\endline\cr + +\normalprotected\def\null{\hpack{}} + +%D The following two might be overloaded later on but some modules need then +%D earlier. These functionality is reflected in the name and will not change. + +% \bgroup +% \catcode`\^^M=\activecatcode% +% \gdef\obeylines{\catcode`\^^M\activecatcode \let^^M\par}% +% \glet^^M\par% +% \egroup +% +% \bgroup +% \gdef\obeyspaces{\catcode`\ \activecatcode}% +% \obeyspaces\glet =\space% +% \egroup + +\def\obeylines {\catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par} +\def\obeyspaces{\catcode\spaceasciicode \activecatcode\letcharcode\spaceasciicode \space} + +% %D A constant: +% +% \let\endoflinetoken=^^M + +%D Also needed might be a simple loop structure and we borrow plain \TEX's one +%D as it is often expected to be present and it is about the fastest you can +%D get. Beware: this macro does not support nested loops. We use a namespace +%D prefix \type {@@pln}. + +\def\loop#1\repeat{\def\@@plnbody{#1}\@@plniterate} % might go + +%D The following makes \type {\loop} \unknown\ \type {\if} \unknown\ \type +%D {\repeat} skippable (clever trick): + +\let\repeat\fi % so both \loop and \repeat are reserved words! + +%D The original (no \type {@@pln} there): +%D +%D \starttyping +%D \def\@@plniterate{\@@plnbody\let\next\@@plniterate\else\let\next\relax\fi\next} +%D \stoptyping +%D +%D A more efficient alternative: +%D +%D \starttyping +%D \def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\expandafter\relax\fi} +%D \stoptyping +%D +%D An even more efficient one: + +\def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\fi} + +%D We don't define a real output routine yet but at least get rid of pages: + +\output{\shipout\box\normalpagebox} + +%D Although we don't add pagenumbers yet we alias the default register used +%D for counting pages: + +\countdef\pageno\zerocount \pageno\plusone % first page is number 1 + +%D Beside the raw counter \type {\pageno} the \type {\folio} macro provides +%D the value. + +\def\folio{\the\pageno} % kind of expected and therefore reserved + +%D The following registers are kind of standard and (for the moment) we define +%D them here. This might change. + +\newskip \bigskipamount \bigskipamount = 12pt plus 4pt minus 4pt +\newskip \medskipamount \medskipamount = 6pt plus 2pt minus 2pt +\newskip \smallskipamount \smallskipamount = 3pt plus 1pt minus 1pt + +\baselineskip = 12pt +\lineskip = 1pt +\lineskiplimit = 0pt + +%D Sometimes kerns make more sense than glue but we need to be in the +%D right mode: + +\normalprotected\def\vkern{\ifhmode\par \fi\kern} +\normalprotected\def\hkern{\ifvmode\dontleavehmode\fi\kern} + +%D Again a few kind-of-extensions the core. These come from plain \TEX\ but +%D are probably not used in \CONTEXT. + +\newskip \hideskip \hideskip = -1000pt plus 1fill +\newskip \centering \centering = 0pt plus 1000pt minus 1000pt + +\def\hidewidth % for alignment entries that can stick out + {\hskip\hideskip} + +\def\ialign % initialized \halign + {\everycr\emptytoks + \tabskip\zeroskip + \halign} + +\newcount \mscount + +\def\spanomit{\span\omit} % bypass error message + +\def\multispan#1% + {\omit + \mscount#1\relax + \loop + \ifnum\mscount>\plusone + \spanomit \advance\mscount\minusone + \repeat} + +\let\nopdfcompression \relax +\let\onlypdfobjectcompression\relax +\let\maximumpdfcompression \relax +\let\normalpdfcompression \relax + +%D Basic status stuff. + +\newif\ifproductionrun + +%D For those who expect this \unknown + +\ifx\fmtname \undefined \def\fmtname {ConTeXt Initial TeX} \fi +\ifx\fmtversion\undefined \def\fmtversion{3.1415926} \fi + +%D A few bonus macros: + +\def\modulonumber#1#2{\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax} +\def\dividenumber#1#2{\the\numexpr(#2-(#1/2))/#1\relax} + +%D These could be set at the \LUA\ end instead: + +\edef\texenginename {\directlua{tex.print(LUATEXENGINE)}} +\edef\texengineversion {\directlua{tex.print(LUATEXVERSION)}} +\edef\texenginefunctionality{\directlua{tex.print(LUATEXFUNCTIONALITY)}} + +%D We have no reason not to enable this: + +\savingvdiscards\plusone + +%D We only can set this one via directives (system.synctex) and we only support +%D the context variant. This will go away completely. + +\newcount\synctex \let\normalsynctex\synctex + +%D We get rid of the funny \TEX\ offset defaults of one inch by setting them to zero. + +\voffset\zeropoint \let\voffset\relax \newdimen\voffset \let\normalvoffset\voffset +\hoffset\zeropoint \let\hoffset\relax \newdimen\hoffset \let\normalhoffset\hoffset + +\matheqnogapstep\zerocount % for now + +%D Now we define a few helpers that we need in a very early stage. We have no +%D message system yet but redundant definitions are fatal anyway. + +\newcount\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes + +\def\v_interfaces_prefix_template_system{\number \c_syst_helpers_n_of_namespaces>>} +%def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet + +\normalprotected\def\installsystemnamespace#1% + {\ifcsname ??#1\endcsname + \immediate\write\statuswrite{fatal error: duplicate system namespace '#1'}% + \expandafter\normalend + \else + \global\advance\c_syst_helpers_n_of_namespaces\plusone + \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template_system}% + \fi} + +%D It makes more sense to have these here: + +\let\normalsuperscript \Usuperscript +\let\normalsubscript \Usubscript +\let\normalnosuperscript\Unosuperscript +\let\normalnosubscript \Unosubscript +\let\normalstartimath \Ustartmath +\let\normalstopimath \Ustopmath +\let\normalstartdmath \Ustartdisplaymath +\let\normalstopdmath \Ustopdisplaymath + +%D Also better here: + +\def\wildcardsymbol{*} + +\protect \endinput diff --git a/tex/context/base/mkiv/tabl-ntb.mkiv b/tex/context/base/mkiv/tabl-ntb.mkiv index 1cf5ad3dc..879cd33e3 100644 --- a/tex/context/base/mkiv/tabl-ntb.mkiv +++ b/tex/context/base/mkiv/tabl-ntb.mkiv @@ -11,13 +11,12 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -%D This module has a more modern variant in xtables but as we follow a bit -%D different approach with settings there, this mechanism will stay. In fact -%D each of them has its advantages. This module could be sped up a bit and made -%D more efficient by delegating some housekeeping to \LUA\ but it's not worth -%D the effort. The code could me made more readable but again, there is no -%D real purpose in it. If needed I can squeeze out a few more percentages -%D runtime. +%D This module has a more modern variant in xtables but as we follow a bit different +%D approach with settings there, this mechanism will stay. In fact each of them has +%D its advantages. This module could be sped up a bit and made more efficient by +%D delegating some housekeeping to \LUA\ but it's not worth the effort. The code +%D could me made more readable but again, there is no real purpose in it. If needed +%D I can squeeze out a few more percentages runtime. % columndistance 'optimized' ... needs checking % @@ -27,8 +26,8 @@ % sometimes this helps (with nc going wild): \setupTABLE[maxwidth=100cm] % -% bug: width 3cm is not honored and column becomes too wide -% as given width is added to distributed width +% bug: width 3cm is not honored and column becomes too wide as given width is added +% to distributed width % % \bTABLE % \bTR @@ -61,16 +60,14 @@ % \stopcelltable % \stoptext -%D As always, this is the n\high{th} version. Much time went in -%D trying to speed up the many cell calculations, some -%D optimizations were rejected in order not to complicate this -%D module too much (and in order to prevail extensibility). In the +%D As always, this is the n\high{th} version. Much time went in trying to speed up +%D the many cell calculations, some optimizations were rejected in order not to +%D complicate this module too much (and in order to prevail extensibility). In the %D meantime we've sacrified some speed for readability. \unprotect -%D The next alternative also takes care of preceding and following -%D white space. +%D The next alternative also takes care of preceding and following white space. %D %D \startbuffer %D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower] @@ -203,8 +200,8 @@ \newbox\b_tabl_ntb_final -%D We have already prepared the previous macros for nesting, -%D so we only have to pop in the right ones: +%D We have already prepared the previous macros for nesting, so we only have to pop +%D in the right ones: \newcount\c_tabl_level @@ -861,8 +858,8 @@ \def\tabl_ntb_tn[#1]#2\eTN {\tabl_ntb_td[#1]\digits#2\relax\eTD} -%D Vit Zyka needed the option to create a distance between columns, so I -%D added support for individual column distances. +%D Vit Zyka needed the option to create a distance between columns, so I added +%D support for individual column distances. %D %D \startbuffer %D % \setupTABLE[c][each][distance=2em] @@ -884,9 +881,8 @@ %D %D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection %D -%D and he provided patches for the global left and right margin distances -%D as well as the columndistance (although i changed the names -). Here -%D is his testcase: +%D and he provided patches for the global left and right margin distances as well as +%D the columndistance (although i changed the names -). Here is his testcase: %D %D \startbuffer %D \framed[offset=overlay]\bgroup @@ -1233,8 +1229,8 @@ \def\tabl_ntb_prelocate_okay {\expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks} -% We use aligments to handle the empty (skipped) columns, so -% that we don't have to (re|)|calculate these. +%D We use aligments to handle the empty (skipped) columns, so that we don't have to +%D (re|)|calculate these. \let\m_tabl_ntb_saved_row\!!zerocount \let\m_tabl_ntb_saved_col\!!zerocount @@ -1734,6 +1730,8 @@ \fi}% \ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths E#1\fi} +% todo: use scratchcounters, not !! ones + \def\tabl_ntb_check_heights_one_indeed {\!!countb\tabl_ntb_get_row\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\relax % check row span @@ -1815,19 +1813,6 @@ {\writestatus\m!TABLE{\space\space\recurselevel: \the\dimexpr\tabl_ntb_get_wid\recurselevel}}% \endgroup} -% \def\tabl_ntb_char_align -% {\doifelse{\naturaltablelocalparameter\c!aligncharacter}\v!yes -% \tabl_ntb_char_align_indeed\gobbletwoarguments} - -% \def\tabl_ntb_char_align_indeed#1#2#3% row column data -% {\edef\alignmentclass{#2}% -% \edef\alignmentcharacter{\naturaltablelocalparameter\c!alignmentcharacter}% -% \ifcase\c_tabl_tbl_pass\or -% \setfirstpasscharacteralign\checkalignment{#3}% {\strut#2\unskip}% -% \fi % force hsize, so always a second -% \setsecondpasscharacteralign \checkalignment{#3}% {\strut#2\unskip}% -% \ignorespaces} - \def\tabl_ntb_char_align % called often {\edef\p_characteralign{\naturaltablelocalparameter\c!aligncharacter}% \ifx\p_characteralign\v!yes @@ -1857,25 +1842,12 @@ \unexpanded\def\tabl_ntb_cell_process_x#1#2[#3]#4% {} -% problem: when span doesn't break we can have a span that is the sum of -% cells but still to small .. chicken egg problem ... for that we should -% also have a smallest width run +% problem: when span doesn't break we can have a span that is the sum of cells but +% still to small .. chicken egg problem ... for that we should also have a smallest +% width run % % nilling the background makes a run upto 25% faster -% \def\tabl_ntb_cell_process_a_check_span_one -% {\ifautosqueezeTBLspan -% \edef\p_width{\naturaltablelocalparameter\c!width}% -% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname -% \else -% \donetrue -% \fi -% \ifdone % brr, 0 -% \ifnum\scratchcounter>\plusone -% \tabl_ntb_set_spn\c_tabl_ntb_col -% \fi -% \fi} - \def\tabl_ntb_cell_process_a_check_span_one {\ifautosqueezeTBLspan \edef\p_width{\naturaltablelocalparameter\c!width}% @@ -1889,47 +1861,6 @@ \fi \fi} -% \def\tabl_ntb_cell_process_a_check_span_two_yes -% {\iftightTBLcolspan -% \donefalse -% \else -% \ifnum\scratchcounter>\plusone -% \begingroup -% \edef\p_width{\naturaltablelocalparameter\c!width}% -% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname -% \ifdone -% \endgroup -% \edef\p_option{\naturaltablelocalparameter\c!option}% -% \ifx\p_option\v!tight\donefalse\else\donetrue\fi -% \else -% % a dimension -% \endgroup -% \donefalse -% \fi -% \else -% \edef\p_option{\naturaltablelocalparameter\c!option}% -% \ifx\p_option\v!tight\donefalse\else\donetrue\fi -% \fi -% \fi -% \ifdone -% \ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox -% \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}% -% \fi -% \fi} - -% \def\tabl_ntb_cell_process_a_check_span_two_nop -% {\ifnum\scratchcounter>\plusone -% \edef\p_width{\naturaltablelocalparameter\c!width}% -% \csname\??naturaltablesqueeze\ifcsname\??naturaltablesqueeze\p_width\endcsname\p_width\fi\endcsname -% \else -% \donetrue -% \fi -% \ifdone -% \ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox -% \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}% -% \fi -% \fi} - \let\tabl_ntb_cell_process_a_check_span_two_yes\relax \def\tabl_ntb_cell_process_a_check_span_two_nop @@ -1953,9 +1884,9 @@ \anch_backgrounds_text_level_start \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}% \anch_backgrounds_text_level_stop -\ifcase\c_anch_backgrounds_text_count\else - \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state -\fi + \ifcase\c_anch_backgrounds_text_count\else + \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state + \fi }% \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax \ifdim\wd\scratchbox>\scratchdimen @@ -2059,12 +1990,12 @@ \else \setnaturaltablelocalparameter\c!height{\d_tabl_ntb_height}% \fi -\ifcase\c_anch_backgrounds_text_count\else - \edef\p_region{\naturaltablelocalparameter\c!region}% - \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount - \letnaturaltablelocalparameter\c!region\v!yes - \fi\fi -\fi + \ifcase\c_anch_backgrounds_text_count\else + \edef\p_region{\naturaltablelocalparameter\c!region}% + \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount + \letnaturaltablelocalparameter\c!region\v!yes + \fi\fi + \fi \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}% \hskip\tabl_ntb_get_dis{#2}} @@ -2198,12 +2129,6 @@ \let\eTDs\relax \let\eTRs\relax -% \unexpanded\def\bTDs[#1]#2\eTDs -% {\normalexpanded{\bTD[\ifcsname\??naturaltablesetup#1\endcsname\csname\??naturaltablesetup#1\endcsname\fi]}#2\eTD} -% -% \unexpanded\def\bTRs[#1]#2\eTRs -% {\normalexpanded{\bTR[\ifcsname\??naturaltablesetup#1\endcsname\csname\??naturaltablesetup#1\endcsname\fi]}#2\eTR} - \unexpanded\def\bTDs[#1]#2\eTDs {\normalexpanded{\bTD[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTD} diff --git a/tex/context/base/mkiv/tabl-ntb.mkxl b/tex/context/base/mkiv/tabl-ntb.mkxl new file mode 100644 index 000000000..e80ff06d6 --- /dev/null +++ b/tex/context/base/mkiv/tabl-ntb.mkxl @@ -0,0 +1,2138 @@ +%D \module +%D [ file=tabl-ntb, +%D version=2000.04.18, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Natural Tables, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D This module has a more modern variant in xtables but as we follow a bit different +%D approach with settings there, this mechanism will stay. In fact each of them has +%D its advantages. This module could be sped up a bit and made more efficient by +%D delegating some housekeeping to \LUA\ but it's not worth the effort. The code +%D could me made more readable but again, there is no real purpose in it. If needed +%D I can squeeze out a few more percentages runtime. + +% columndistance 'optimized' ... needs checking +% +% we don't need the alignment mechanism .. we can just pack the row in a box + +\writestatus{loading}{ConTeXt Table Macros / Natural Tables} + +% sometimes this helps (with nc going wild): \setupTABLE[maxwidth=100cm] +% +% bug: width 3cm is not honored and column becomes too wide as given width is added +% to distributed width +% +% \bTABLE +% \bTR +% \bTD test \eTD +% \bTD \framed[height=3cm]{test} \eTD +% \bTD[width=3cm] \dorecurse{30}{a } \eTD +% \bTD \input ward \eTD +% \eTR +% \bTR +% \bTD test \eTD +% \bTD \framed[height=3cm]{test} \eTD +% \bTD \dorecurse{30}{a } \eTD +% \bTD \input ward \eTD +% \eTR +% \eTABLE + +% \unexpanded\def\startrow {\bTR} +% \unexpanded\def\stoprow {\eTR} +% \unexpanded\def\startcell#1\stopcell{\bTD#1\eTD} +% \let\stopcell \relax +% \let\startcelltable \bTABLE +% \let\stopcelltable \eTABLE + +% \starttext +% \startcelltable +% \startrow \startcell a \stopcell \stoprow +% \startrow \startcell a \stopcell \stoprow +% \startrow \startcell a \stopcell \stoprow +% \startrow \startcell a \stopcell \stoprow +% \stopcelltable +% \stoptext + +%D As always, this is the n\high{th} version. Much time went in trying to speed up +%D the many cell calculations, some optimizations were rejected in order not to +%D complicate this module too much (and in order to prevail extensibility). In the +%D meantime we've sacrified some speed for readability. + +\unprotect + +%D The next alternative also takes care of preceding and following white space. +%D +%D \startbuffer +%D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower] +%D \bTR \bTD something \eTD \eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\ifdefined\dotagTABLEcell \else \let\dotagTABLEcell \relax \fi % todo: namespace +\ifdefined\dotagTABLEsignal \else \let\dotagTABLEsignal\relax \fi % todo: namespace + +\let\tabl_ntb_next_level\relax + +\newtoks\t_tabl_ntb_cell_start +\newtoks\t_tabl_ntb_cell_stop + +\appendtoks + \naturaltablelocalparameter\c!left + \delayedbegstrut +\to \t_tabl_ntb_cell_start + +\appendtoks + \delayedendstrut + \naturaltablelocalparameter\c!right +\to \t_tabl_ntb_cell_stop + +\appendtoks + \flushpostponednodedata + % maybe: \the\neverypar +\to \t_tabl_ntb_cell_start + +\unexpanded\def\tabl_ntb_cell_start + {% \inhibitblank + \dotagTABLEcell + %\tabl_ntb_next_level + \font_styles_math_reset + \usenaturaltablelocalstyleandcolor\c!style\c!color + \everypar\t_tabl_ntb_cell_start + \font_styles_math_start} + +\unexpanded\def\tabl_ntb_cell_stop + {\font_styles_math_stop + \ifhmode + \the\t_tabl_ntb_cell_stop + \par % added 13/4/2006 + \orelse\ifdim\prevdepth<\zeropoint % =-1000pt ? + % not sure yet:\naturaltablelocalparameter\c!right + \vskip-\strutdp + \else + \removebottomthings + \fi} + +% maybe: +% +% \unexpanded\def\tabl_ntb_cell_stop +% {\ifhmode +% \the\t_tabl_ntb_cell_stop +% \par % added 13/4/2006 +% \else +% % not sure yet:\naturaltablelocalparameter\c!right +% \par +% \ifhmode +% % \removeunwantedspaces +% \else\ifdim\prevdepth<\zeropoint % =-1000pt ? +% \vskip-\strutdp +% \else +% \removebottomthings +% \fi\fi +% \fi} + +\newcount\c_tabl_ntb_row +\newcount\c_tabl_ntb_col +\newcount\c_tabl_ntb_spn + +\newcount\c_tabl_ntb_nx +\newcount\c_tabl_ntb_ny + +\setnewconstant\c_tabl_ntb_cell \plusone +\setnewconstant\c_tabl_ntb_none \plustwo + +\newcount\c_tabl_ntb_current_row +\newcount\c_tabl_ntb_current_col +\newcount\c_tabl_ntb_current_row_one +\newcount\c_tabl_ntb_current_col_one +\newcount\c_tabl_ntb_current_row_two +\newcount\c_tabl_ntb_current_col_two +\newcount\c_tabl_ntb_current_row_three +\newcount\c_tabl_ntb_current_col_three +\newcount\c_tabl_ntb_current_row_four +\newcount\c_tabl_ntb_current_col_four + +\newcount\c_tabl_ntb_running_col +\newcount\c_tabl_ntb_maximum_row +\newcount\c_tabl_ntb_maximum_col +\newcount\c_tabl_ntb_maximum_row_span +\newcount\c_tabl_ntb_maximum_col_span + +\newcount\c_tabl_ntb_encountered_col +\newcount\c_tabl_ntb_encountered_max + +\newtoks\t_tabl_ntb +\newtoks\t_tabl_ntb_row + +\newconstant\c_tabl_tbl_pass + +\newtoks\t_tabl_ntb_head +\newtoks\t_tabl_ntb_next +\newtoks\t_tabl_ntb_body +\newtoks\t_tabl_ntb_foot + +\newcount\c_tabl_ntb_n_of_head_lines +\newcount\c_tabl_ntb_n_of_next_lines +\newcount\c_tabl_ntb_n_of_hdnx_lines + +\newdimen\d_tabl_ntb_height +\newdimen\d_tabl_ntb_width + +\newdimen\d_tabl_ntb_leftmargindistance +\newdimen\d_tabl_ntb_rightmargindistance +\newdimen\d_tabl_ntb_columndistance +\newdimen\d_tabl_ntb_maxwidth + +\newtoks\everyTABLEpass % public + +\newcount\tablecellrows % public (needs checking) +\newcount\tablecellcolumns % public (needs checking) + +\newbox\b_tabl_ntb_final + +%D We have already prepared the previous macros for nesting, so we only have to pop +%D in the right ones: + +\newcount\c_tabl_level + +\installglobalmacrostack\m_tabl_ntb_saved_row +\installglobalmacrostack\m_tabl_ntb_saved_col + +\unexpanded\def\tabl_ntb_table_push + {\ifnum\m_tabl_tbl_level>\plusone + \tabl_ntb_parameters_reset + % we need a proper count push/pop + \xdef\m_tabl_ntb_saved_row{\the\c_tabl_ntb_row}\push_macro_m_tabl_ntb_saved_row + \xdef\m_tabl_ntb_saved_col{\the\c_tabl_ntb_col}\push_macro_m_tabl_ntb_saved_col + \else + \global\intabletrue + \fi} + +\unexpanded\def\tabl_ntb_table_pop + {\ifnum\m_tabl_tbl_level>\plusone + \pop_macro_m_tabl_ntb_saved_row\global\c_tabl_ntb_row\m_tabl_ntb_saved_row + \pop_macro_m_tabl_ntb_saved_col\global\c_tabl_ntb_col\m_tabl_ntb_saved_col + \else + \global\intablefalse + \fi} + +\unexpanded\def\tabl_ntb_next_level + {\advance\c_tabl_level\plusone + \edef\m_tabl_tbl_level{\the\c_tabl_level}} + +\unexpanded\def\tabl_ntb_prev_level + {\advance\c_tabl_level\minusone + \edef\m_tabl_tbl_level{\the\c_tabl_level}} + +\tabl_ntb_next_level % go to level 1 + +\installcorenamespace{naturaltable} % was tbl +\installcorenamespace{naturaltablelocal} % was tbltbl + +\installdirectcommandhandler \??naturaltable {naturaltable} % \??naturaltable +\installsimpleframedcommandhandler \??naturaltablelocal {naturaltablelocal} \??naturaltablelocal + +\installcorenamespace{naturaltabletal} +\installcorenamespace{naturaltablegal} +\installcorenamespace{naturaltablenob} +\installcorenamespace{naturaltabletag} +\installcorenamespace{naturaltablecol} +\installcorenamespace{naturaltablerow} +\installcorenamespace{naturaltablewd} +\installcorenamespace{naturaltableht} +\installcorenamespace{naturaltabledp} +\installcorenamespace{naturaltablewid} +\installcorenamespace{naturaltablehei} +\installcorenamespace{naturaltabledis} +\installcorenamespace{naturaltableaut} +\installcorenamespace{naturaltablebck} +%installcorenamespace{naturaltablefwd} % forcedwidth +\installcorenamespace{naturaltabletxt} +\installcorenamespace{naturaltablespn} +\installcorenamespace{naturaltableref} +\installcorenamespace{naturaltableset} +\installcorenamespace{naturaltablecell} +\installcorenamespace{naturaltablesqueeze} +\installcorenamespace{naturaltabletok} + +\letvalue{\??naturaltablesqueeze }\donefalse +\letvalue{\??naturaltablesqueeze\v!fit }\donetrue +\letvalue{\??naturaltablesqueeze\v!fixed}\donetrue +\letvalue{\??naturaltablesqueeze\v!broad}\donetrue +\letvalue{\??naturaltablesqueeze\v!local}\donetrue + +\def\tabl_ntb_let_gal{\expandafter\glet\csname\??naturaltablegal\m_tabl_tbl_level\endcsname} +\def\tabl_ntb_get_gal{\csname\??naturaltablegal\m_tabl_tbl_level\endcsname} + +\def\tabl_ntb_let_tal#1{\expandafter\glet\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname} +\def\tabl_ntb_get_tal#1{\csname\??naturaltabletal\m_tabl_tbl_level:\number#1\endcsname} + +\def\tabl_ntb_set_nob#1{\expandafter\let\csname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone} +\def\tabl_ntb_get_nob#1{\ifcsname\??naturaltablenob\m_tabl_tbl_level:\number#1\endcsname\plusone\else\zerocount\fi} + +%def\tabl_ntb_set_tag#1#2{\expandafter\edef\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_set_col#1#2{\expandafter\edef\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_set_row#1#2{\expandafter\edef\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +\def\tabl_ntb_let_tag#1#2{\expandafter\let\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_let_col#1#2{\expandafter\let\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_let_row#1#2{\expandafter\let\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +%def\tabl_ntb_set_wd#1#2{\expandafter\xdef\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global ! +\def\tabl_ntb_set_ht#1#2{\expandafter\xdef\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global ! + +%def\tabl_ntb_let_wd#1#2{\expandafter\glet\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global ! +\def\tabl_ntb_let_ht#1#2{\expandafter\glet\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname} % global ! + +\def\tabl_ntb_get_tag#1#2{\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_get_col#1#2{\csname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_get_row#1#2{\csname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +%def\tabl_ntb_get_wd#1#2{\csname\??naturaltablewd\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_get_ht#1#2{\csname\??naturaltableht\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +\def\tabl_ntb_set_wid#1{\expandafter\xdef\csname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_set_hei#1{\expandafter\xdef\csname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_set_dis#1{\expandafter\xdef\csname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_set_aut#1{\expandafter\xdef\csname\??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! + +\def\tabl_ntb_let_wid#1{\expandafter\glet\csname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_let_hei#1{\expandafter\glet\csname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_let_dis#1{\expandafter\glet\csname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! +\def\tabl_ntb_let_aut#1{\expandafter\glet\csname\??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname} % {#2} global ! + +\def\tabl_ntb_get_wid#1{\ifcsname\??naturaltablewid\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi} +\def\tabl_ntb_get_hei#1{\ifcsname\??naturaltablehei\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi} +\def\tabl_ntb_get_dis#1{\ifcsname\??naturaltabledis\m_tabl_tbl_level:\number#1\endcsname\lastnamedcs\else\zeropoint\fi} +\def\tabl_ntb_get_aut#1{\csname \??naturaltableaut\m_tabl_tbl_level:\number#1\endcsname} + +\def\tabl_ntb_let_bck#1#2{\global\expandafter\chardef\csname\??naturaltablebck\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +\def\tabl_ntb_get_bck#1#2{\csname\??naturaltablebck\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +\def\tabl_ntb_tag_pattern#1#2{\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2} +\def\tabl_ntb_row_pattern#1#2{\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2} +\def\tabl_ntb_col_pattern#1#2{\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2} + +\def\tabl_ntb_tag_doif #1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi} +\def\tabl_ntb_tag_doifnot #1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\gobbleoneargument \else\expandafter\firstofoneargument \fi} +\def\tabl_ntb_tag_doifelse#1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi} +\def\tabl_ntb_row_doif #1#2{\ifcsname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi} +\def\tabl_ntb_col_doif #1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\firstofoneargument \else\expandafter\gobbleoneargument \fi} +\def\tabl_ntb_col_doifnot #1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\expandafter\gobbleoneargument \else\expandafter\firstofoneargument \fi} + +%D If we ever run into memory issues we can do: +% +% \def\tabl_ntb_let_tag#1#2#3% +% {\ifx#3\c_tabl_ntb_none\else +% \expandafter\let\csname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname#3% +% \fi} +% +% \def\tabl_ntb_get_tag#1#2% +% {\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname +% \lastnamedcs +% \else +% \c_tabl_ntb_none +% \fi} + +% not used +% +% \def\tabl_ntb_tag_state#1#2{\ifcsname\??naturaltabletag\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi} +% \def\tabl_ntb_row_state#1#2{\ifcsname\??naturaltablerow\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi} +% \def\tabl_ntb_col_state#1#2{\ifcsname\??naturaltablecol\m_tabl_tbl_level:\number#1:\number#2\endcsname\zerocount\else\plusone\fi} + +%def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone} +%def\tabl_ntb_spn_doifelse#1{\doifelse {\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname}\!!plusone} + +%def\tabl_ntb_set_spn #1{\setvalue {\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}} +%def\tabl_ntb_spn_doifelse#1{\doifelsevalue{\??naturaltablespn\m_tabl_tbl_level:\number#1}{1}} + +\def\tabl_ntb_let_ref #1#2{\expandafter\glet\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname} +\def\tabl_ntb_set_ref #1#2{\expandafter\xdef\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname} +%def\tabl_ntb_get_ref #1#2{\ifcsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\csname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname\fi} +\def\tabl_ntb_get_ref #1#2{\begincsname\??naturaltableref\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +\def\tabl_ntb_set_spn #1{\expandafter\let\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname \!!plusone} +\def\tabl_ntb_spn_doifelse#1{\ifcase0\csname\??naturaltablespn\m_tabl_tbl_level:\number#1\endcsname\relax % could be inlined + \expandafter\secondoftwoarguments % unset + \else + \expandafter\firstoftwoarguments % a span + \fi} + +% keep for a while: +% +% \unexpanded\def\tabl_ntb_set_txt_process#1#2#3#4#5#6% nasty: we restore the level +% {\expandafter\def\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\expandafter\endcsname\expandafter +% {\expandafter\def\expandafter\m_tabl_tbl_level\expandafter{\m_tabl_tbl_level}\tabl_ntb_cell_process{#3}{#4}[#5]{#6}}} + +\unexpanded\def\tabl_ntb_set_txt_process#1#2#3#4#5#6% + {\expandafter\def\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\endcsname + {\tabl_ntb_cell_process{#3}{#4}[#5]{\tabl_ntb_next_level#6\tabl_ntb_prev_level}}} + +\def\tabl_ntb_get_txt#1#2% + {\csname\??naturaltabletxt\m_tabl_tbl_level:\number#1:\number#2\endcsname} + +% to be changed: + +\newif\ifsqueezeTBLspan \squeezeTBLspantrue % spans one column cell over multi column par cells +\newif\ifautosqueezeTBLspan \autosqueezeTBLspantrue % unless explicit widths are given +\newif\ifautoTBLspread \autoTBLspreadfalse +\newif\ifautoTBLhsize \autoTBLhsizetrue +\newif\ifautoTBLrowspan \autoTBLrowspantrue +\newif\ifautoTBLemptycell \autoTBLemptycelltrue +\newif\ifautoTBLcheckwidth \autoTBLcheckwidthtrue +\newif\ifappendTBLsetups \appendTBLsetupstrue +\newif\ifenableTBLbreak \enableTBLbreakfalse +\newif\ifmultipleTBLheads \multipleTBLheadsfalse +\newif\iftightTBLrowspan \tightTBLrowspantrue +\newif\iftightTBLcolspan \tightTBLcolspanfalse + +\newconditional \c_tabl_ntb_trace_widths + +\installtextracker + {tables.natural.widths} + {\settrue \c_tabl_ntb_trace_widths} + {\setfalse\c_tabl_ntb_trace_widths} + +% so far + +\unexpanded\def\tabl_ntb_cell_process#1#2[#3]{} + +\unexpanded\def\bTC#1\eTC{\bTD#1\eTD} \let\eTC\relax +\unexpanded\def\bTX#1\eTX{\bTD#1\eTD} \let\eTX\relax +\unexpanded\def\bTY#1\eTY{\bTR#1\eTR} \let\eTY\relax + +\unexpanded\def\setupTABLE + {\dotripleempty\tabl_ntb_setup} + +\let\tabl_ntb_parameters_get\setupcurrentnaturaltablelocal + +\def\tabl_ntb_setup + {\ifthirdargument + \expandafter\tabl_ntb_setup_three + \orelse\ifsecondargument + \doubleexpandafter\tabl_ntb_setup_two + \else + \doubleexpandafter\tabl_ntb_setup_one + \fi} + +\def\tabl_ntb_setup_one[#1][#2][#3]% + {\setupcurrentnaturaltablelocal[#1]} + +\def\tabl_ntb_setup_xy[#1][#2][#3]% + {\def\tabl_ntb_setup_step##1{\tabl_ntb_parameters_set[#1##1][#3]}% + \processcommalist[#2]\tabl_ntb_setup_step} + +\def\tabl_ntb_setup_un[#1][#2][#3]% + {\def\tabl_ntb_setup_step##1% + {\def\tabl_ntb_setup_step_step####1{\tabl_ntb_parameters_set[\c!x##1\c!y####1][#3]}% + \processcommalist[#2]\tabl_ntb_setup_step_step}% + \processcommalist[#1]\tabl_ntb_setup_step} + +\def\tabl_ntb_setup_each[#1][#2][#3]% ignores #3 + {\tabl_ntb_parameters_set[#1\v!each][#2]} + +\def\tabl_ntb_setup_ux[#1][#2][#3]% ignores #3 + {\def\tabl_ntb_setup_step##1{\tabl_ntb_parameters_set[\c!x##1][#2]}% + \processcommalist[#1]\tabl_ntb_setup_step} + +\installcorenamespace{naturaltablesetupthree} +\installcorenamespace{naturaltablesetuptwo} + +%def\tabl_ntb_setup_three[#1]{\csname\??naturaltablesetupthree\ifcsname\??naturaltablesetupthree#1\endcsname#1\else\s!unknown\fi\endcsname[#1]} +%def\tabl_ntb_setup_two [#1]{\csname\??naturaltablesetuptwo \ifcsname\??naturaltablesetuptwo #1\endcsname#1\else\s!unknown\fi\endcsname[#1]} + +\def\tabl_ntb_setup_three[#1]{\ifcsname\??naturaltablesetupthree#1\endcsname\expandafter\lastnamedcs\else\expandafter\tabl_ntb_setup_un\fi[#1]} +\def\tabl_ntb_setup_two [#1]{\ifcsname\??naturaltablesetuptwo #1\endcsname\expandafter\lastnamedcs\else\expandafter\tabl_ntb_setup_ux\fi[#1]} + +\setvalue{\??naturaltablesetupthree \v!row}[#1]{\tabl_ntb_setup_xy [\c!y]} +\setvalue{\??naturaltablesetupthree \v!column}[#1]{\tabl_ntb_setup_xy [\c!x]} +\setvalue{\??naturaltablesetupthree \v!start}[#1]{\tabl_ntb_setup_xy [\v!start]} +\setvalue{\??naturaltablesetupthree \v!header}[#1]{\tabl_ntb_setup_xy [\v!header]} + +\setvalue{\??naturaltablesetuptwo \v!row}[#1]{\tabl_ntb_setup_each[\c!y]} +\setvalue{\??naturaltablesetuptwo \v!column}[#1]{\tabl_ntb_setup_each[\c!x]} +\setvalue{\??naturaltablesetuptwo \v!start}[#1]{\tabl_ntb_setup_each[\v!start]} +\setvalue{\??naturaltablesetuptwo \v!header}[#1]{\tabl_ntb_setup_each[\v!header]} + +\letvalue{\??naturaltablesetupthree\s!unknown}\tabl_ntb_setup_un +\letvalue{\??naturaltablesetuptwo \s!unknown}\tabl_ntb_setup_ux + +\letcsnamecsname\csname\??naturaltablesetupthree r\endcsname\csname\??naturaltablesetupthree \v!row\endcsname +\letcsnamecsname\csname\??naturaltablesetupthree c\endcsname\csname\??naturaltablesetupthree\v!column\endcsname +\letcsnamecsname\csname\??naturaltablesetupthree y\endcsname\csname\??naturaltablesetupthree \v!row\endcsname +\letcsnamecsname\csname\??naturaltablesetupthree x\endcsname\csname\??naturaltablesetupthree\v!column\endcsname + +\letcsnamecsname\csname\??naturaltablesetuptwo r\endcsname\csname\??naturaltablesetuptwo \v!row\endcsname +\letcsnamecsname\csname\??naturaltablesetuptwo c\endcsname\csname\??naturaltablesetuptwo \v!column\endcsname +\letcsnamecsname\csname\??naturaltablesetuptwo y\endcsname\csname\??naturaltablesetuptwo \v!row\endcsname +\letcsnamecsname\csname\??naturaltablesetuptwo x\endcsname\csname\??naturaltablesetuptwo \v!column\endcsname + +\def\tabl_ntb_parameters_set[#1][#2]% + {\ifappendTBLsetups + \ifcsname\??naturaltableset\m_tabl_tbl_level:#1\endcsname + \def\tabl_ntb_parameters_get[##1]% + {\setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[##1,#2]}}% + \csname\??naturaltableset\m_tabl_tbl_level:#1\endcsname + \let\tabl_ntb_parameters_get\setupcurrentnaturaltablelocal + \else + \setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[#2]}% + \fi + \else + \setvalue{\??naturaltableset\m_tabl_tbl_level:#1}{\tabl_ntb_parameters_get[#2]}% + \fi} + +% % \setupTABLE [y] [first][background=color,backgroundcolor=blue,frame=off,bottomframe=on,topframe=on,framecolor=white] +% \setupTABLE [first][first][backgroundcorner=2,corner=10,frame=on] +% \setupTABLE [last] [first][backgroundcorner=4,corner=12,frame=on] +% +% \setupTABLE [row] [each] [background=color,backgroundcolor=blue,frame=on,framecolor=white] +% \setupTABLE [first][2] [corner=8] +% \setupTABLE [last] [2] [corner=5] +% \setupTABLE [first][last] [corner=7] +% \setupTABLE [last] [last] [corner=6] +% +% \startTEXpage +% \bTABLE[frame=off,align=middle] +% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR +% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR +% \bTR \bTD alpha \eTD \bTD beta \eTD \bTD gamma \eTD \eTR +% \eTABLE +% \stopTEXpage +% +% \setupTABLE [first] [two][corner=2] % special case +% \setupTABLE [last] [two][corner=4] % special case +% +% % % \setupTABLE [one] [first] ... special case of span +% +% \startTEXpage +% \bTABLE[frame=off,align=middle] +% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR +% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR +% \eTABLE +% \stopTEXpage + +%D By default rowspans are tight but you can change that: +%D +%D \startbuffer +%D \bTABLE +%D \bTR[height=20pt] \bTH 1. col \eTH \bTH 2. col \eTH \eTR +%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \bTD[nr=2] 2 rows in 2. col \eTD \eTR +%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 1. col\eTD \eTR +%D \bTR[height=20pt] \bTD[nr=3] 3 rows in 2. col \eTD \eTR +%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR +%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR +%D \eTABLE +%D +%D \bTABLE +%D \bTR[height=20pt] \bTH 2. col \eTH \bTH 1. col \eTH \eTR +%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 2. col \eTD \bTD 1 row in 1. col \eTD \eTR +%D \bTR[height=20pt] \bTD[nr=2] 2 rows in 1. col\eTD \eTR +%D \bTR[height=20pt] \bTD[nr=3] 3 rows in 2. col \eTD \eTR +%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR +%D \bTR[height=20pt] \bTD 1 row in 1. col \eTD \eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer +%D +%D \getbuffer +%D +%D With \type {\tightTBLrowspanfalse} we get: +%D +%D \start \tightTBLrowspanfalse \getbuffer \stop + +\let\tabl_ntb_setup_section\relax + +\unexpanded\def\tabl_ntb_setup_cell#1#2% cell over col over row + {\tabl_ntb_setup_section % already forgotten + \edef\m_tabl_ntb_positive_row{\number#1}% + \edef\m_tabl_ntb_positive_col{\number#2}% + \edef\m_tabl_ntb_negative_row{\the\numexpr-\c_tabl_ntb_maximum_row+#1+\minusone\relax}% + \edef\m_tabl_ntb_negative_col{\the\numexpr-\c_tabl_ntb_maximum_col+#2+\minusone\relax}% + % saves tokens (no speed gain) + \edef\m_tabl_ntb_prefix{\??naturaltableset\m_tabl_tbl_level:}% + % each each + \begincsname\m_tabl_ntb_prefix\c!x\v!each\c!y\v!each\endcsname + \begincsname\m_tabl_ntb_prefix\c!y\v!each\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\v!each\endcsname + % odd even + \begincsname\m_tabl_ntb_prefix\c!y\v!oddeven\m_tabl_ntb_positive_row\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\v!oddeven\m_tabl_ntb_positive_col\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\v!oddeven\m_tabl_ntb_positive_col\c!y\v!oddeven\m_tabl_ntb_positive_row\endcsname + % row/col number combinations + \begincsname\m_tabl_ntb_prefix\c!y\m_tabl_ntb_positive_row\endcsname + \begincsname\m_tabl_ntb_prefix\c!y\m_tabl_ntb_negative_row\endcsname + \naturaltablelocalparameter\c!extras + \letnaturaltablelocalparameter\c!extras\relax % new, see x-fo + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_negative_col\endcsname + \naturaltablelocalparameter\c!extras + \letnaturaltablelocalparameter\c!extras\relax % new, see x-fo + % first/last combinations + \ifnum\m_tabl_ntb_positive_row=\plusone + \begincsname\m_tabl_ntb_prefix\c!y\v!first\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\v!first\endcsname + \fi + \ifnum\m_tabl_ntb_positive_col=\plusone + \begincsname\m_tabl_ntb_prefix\c!x\v!first\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\m_tabl_ntb_positive_row\endcsname + \fi + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax + \begincsname\m_tabl_ntb_prefix\c!y\v!last\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\v!last\endcsname + \fi + \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax + \begincsname\m_tabl_ntb_prefix\c!x\v!last\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\m_tabl_ntb_positive_row\endcsname + \fi + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax + \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!last\endcsname + \fi\fi + \ifnum\m_tabl_ntb_positive_row=\plusone \ifnum\m_tabl_ntb_positive_col=\plusone + \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!first\endcsname + \fi\fi + \ifnum\m_tabl_ntb_positive_row=\plusone \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax + \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!first\endcsname + \fi\fi + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\plusone + \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!last\endcsname + \fi\fi + % special case: two rows and last row : two&first and two&last (round corners) + \ifnum\c_tabl_ntb_maximum_row=\plustwo\relax + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\plusone + \begincsname\m_tabl_ntb_prefix\c!x\v!first\c!y\v!two\endcsname + \fi\fi + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax \ifnum\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax + \begincsname\m_tabl_ntb_prefix\c!x\v!last\c!y\v!two\endcsname + \fi\fi + \fi + \ifnum\tabl_ntb_get_col\m_tabl_ntb_positive_row\m_tabl_ntb_positive_col=\c_tabl_ntb_maximum_col\relax % top span over whole width + \ifnum\m_tabl_ntb_positive_row=\plusone + \begincsname\m_tabl_ntb_prefix\c!x\v!one\c!y\v!first\endcsname + \fi + \ifnum\m_tabl_ntb_positive_row=\c_tabl_ntb_maximum_row\relax + \begincsname\m_tabl_ntb_prefix\c!x\v!one\c!y\v!last\endcsname + \fi + \fi + % header things + \ifnum#1>\c_tabl_ntb_n_of_hdnx_lines\else + \begincsname\m_tabl_ntb_prefix\v!header\v!each\endcsname + \begincsname\m_tabl_ntb_prefix\v!header\m_tabl_ntb_positive_col\endcsname + \fi + % explicit cells + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_positive_col\c!y\m_tabl_ntb_positive_row\endcsname + \begincsname\m_tabl_ntb_prefix\c!x\m_tabl_ntb_negative_col\c!y\m_tabl_ntb_negative_row\endcsname + % local + \begincsname\m_tabl_ntb_prefix\c!y++\m_tabl_ntb_positive_row\endcsname + % done + \relax} + +% we cannot use +n (checking on number/last/first would slow down too much) +% +% \setupTABLE[r] [2][color=red] +% \setupTABLE[r] [-2][color=red] +% \setupTABLE[c] [2][color=green] +% \setupTABLE[c] [-2][color=green] +% \setupTABLE[4] [4][color=blue] +% \setupTABLE[-4][-4][color=blue] +% +% \bTABLE +% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR} +% \eTABLE + +\let\m_tabl_ntb_before_split\empty +\let\m_tabl_ntb_after_split \empty +\let\m_tabl_ntb_same_page \empty + +% split + page: +% +% \bTABLE[split=yes] +% \bTR \bTD left \eTD\bTD right \eTD\eTR +% \bTR[after=\page] \bTD left \eTD\bTD right \eTD\eTR +% \bTR \bTD left \eTD\bTD right \eTD\eTR +% \eTABLE + +\unexpanded\def\tabl_ntb_tr + {\c_tabl_ntb_running_col\zerocount + \c_tabl_ntb_encountered_col\zerocount + \advance\c_tabl_ntb_maximum_row\plusone + \iffirstargument + \expandafter\tabl_ntb_tr_yes + \else + \expandafter\gobbleoneoptional + \fi} + +\def\tabl_ntb_tr_yes[#1]% + {\setvalue{\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_maximum_row}{\setupcurrentnaturaltablelocal[#1]}} + +\def\m_tabl_ntb_default_nr{\naturaltableparameter\c!nr} +\def\m_tabl_ntb_default_nc{\naturaltableparameter\c!nc} + +\unexpanded\def\tabl_ntb_td + {\advance\c_tabl_ntb_encountered_col\plusone + \iffirstargument + \expandafter\tabl_ntb_td_yes + \else + \expandafter\tabl_ntb_td_nop + \fi} + +\def\tabl_ntb_td_yes[#1]#2\eTD + {\letnaturaltableparameter\c!ny \m_tabl_ntb_default_nr + \letnaturaltableparameter\c!nx \m_tabl_ntb_default_nc + \letnaturaltableparameter\c!nc \plusone + \letnaturaltableparameter\c!nr \plusone + \letnaturaltableparameter\c!n \c_tabl_ntb_running_col + \letnaturaltableparameter\c!m \empty + \letnaturaltableparameter\c!action\empty % not that important + \setupcurrentnaturaltable[#1]% + % + \c_tabl_ntb_nx\naturaltableparameter\c!nx\relax + \c_tabl_ntb_ny\naturaltableparameter\c!ny\relax + % goto first cell n/m=cellnumber + \edef\m_tabl_ntb_n{\naturaltableparameter\c!n}% + \edef\m_tabl_ntb_m{\naturaltableparameter\c!m}% + % + \ifx\m_tabl_ntb_n\empty + \global\advance\c_tabl_ntb_spn\c_tabl_ntb_nx\relax + \orelse\ifnum\m_tabl_ntb_n=\c_tabl_ntb_running_col\else + \tabl_ntb_td_pass_n{#1}% + \fi + \ifx\m_tabl_ntb_m\empty \else + \ifnum\m_tabl_ntb_m=\c_tabl_ntb_running_col\else + \tabl_ntb_td_pass_m{#1}% + \fi + \fi + \doloop % skip over columns that result from earlier span + {\advance\c_tabl_ntb_running_col\plusone + \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\endcsname \else + \exitloop + \fi}% + % fill r*c cells and set span + \c_tabl_ntb_nx\naturaltableparameter\c!nx\relax + \c_tabl_ntb_ny\naturaltableparameter\c!ny\relax + \ifnum\c_tabl_ntb_nx=\plusone + \ifnum\c_tabl_ntb_ny=\plusone + \ifnum\c_tabl_ntb_running_col>\c_tabl_ntb_maximum_col\relax + \c_tabl_ntb_maximum_col\c_tabl_ntb_running_col + \fi + \else + \tabl_ntb_cell_preset + \fi + \else + \tabl_ntb_cell_preset + \fi + % set values + \tabl_ntb_let_tag\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\c_tabl_ntb_cell + \tabl_ntb_set_col\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_nx}% + \tabl_ntb_set_row\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_ny}% + % the action key will change! + \tabl_ntb_set_ref\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\naturaltableparameter\c!action}% + % save text + \normalexpanded + {\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}% + {#1}{#2}% + \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max + \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col + \fi} + +\def\tabl_ntb_td_nop[#1]#2\eTD + {\global\advance\c_tabl_ntb_spn\plusone\relax + \doloop + {\advance\c_tabl_ntb_running_col\plusone + \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\endcsname \else + \exitloop + \fi}% + \c_tabl_ntb_nx\plusone + \c_tabl_ntb_ny\plusone + \ifnum\c_tabl_ntb_running_col>\c_tabl_ntb_maximum_col\relax + \c_tabl_ntb_maximum_col\c_tabl_ntb_running_col + \fi + \tabl_ntb_let_tag\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\c_tabl_ntb_cell + \tabl_ntb_set_col\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_nx}% + \tabl_ntb_set_row\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_ny}% + \tabl_ntb_let_ref\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col\empty + \normalexpanded + {\tabl_ntb_set_txt_process\c_tabl_ntb_maximum_row\c_tabl_ntb_running_col{\the\c_tabl_ntb_maximum_row}{\the\c_tabl_ntb_running_col}}% + {#1}{#2}% + \ifnum\c_tabl_ntb_encountered_col>\c_tabl_ntb_encountered_max + \c_tabl_ntb_encountered_max\c_tabl_ntb_encountered_col + \fi} + +\def\tabl_ntb_td_pass_n#1% + {\scratchcounter\numexpr\m_tabl_ntb_n-\c_tabl_ntb_running_col+\minusone-\c_tabl_ntb_spn\relax + \ifnum\scratchcounter>\zerocount + \normalexpanded{\tabl_ntb_td[\c!nx=\the\scratchcounter,\c!n=,\c!m=,*sq=\v!no]}\eTD + \fi + \letnaturaltableparameter\c!ny\m_tabl_ntb_default_nr + \letnaturaltableparameter\c!nx\m_tabl_ntb_default_nc + \letnaturaltableparameter\c!nc\plusone + \letnaturaltableparameter\c!nr\plusone + \setupcurrentnaturaltable[#1]% + \letnaturaltableparameter\c!n \empty + \letnaturaltableparameter\c!m \empty} + +\def\tabl_ntb_td_pass_m#1% + {\scratchcounter\numexpr\m_tabl_ntb_m-\c_tabl_ntb_running_col+\minusone-\c_tabl_ntb_spn\relax + \dorecurse\scratchcounter{\normalexpanded{\tabl_ntb_td[\c!n=,\c!m=]}\eTD}% + % can be sped up + \letnaturaltableparameter\c!ny\m_tabl_ntb_default_nr + \letnaturaltableparameter\c!nx\m_tabl_ntb_default_nc + \letnaturaltableparameter\c!nc\plusone + \letnaturaltableparameter\c!nr\plusone + \setupcurrentnaturaltable[#1]% + \letnaturaltableparameter\c!n \empty + \letnaturaltableparameter\c!m \empty} + +\def\tabl_ntb_cell_preset + {\c_tabl_ntb_current_row\c_tabl_ntb_maximum_row + \c_tabl_ntb_current_col\c_tabl_ntb_running_col + \dorecurse\c_tabl_ntb_ny\tabl_ntb_cell_preset_rows + % check max column + \advance\c_tabl_ntb_current_col\minusone + \ifnum\c_tabl_ntb_current_col>\c_tabl_ntb_maximum_col\relax + \c_tabl_ntb_maximum_col\c_tabl_ntb_current_col + \fi} + +\def\tabl_ntb_cell_preset_rows + {\c_tabl_ntb_current_col\c_tabl_ntb_running_col + \tabl_ntb_set_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_nx}% + \ifnum\c_tabl_ntb_nx>\c_tabl_ntb_maximum_row_span\relax + \c_tabl_ntb_maximum_row_span\c_tabl_ntb_nx + \fi + \dorecurse\c_tabl_ntb_nx\tabl_ntb_cell_preset_cells + \advance\c_tabl_ntb_current_row\plusone} + +\def\tabl_ntb_cell_preset_cells + {\tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_none + \advance\c_tabl_ntb_current_col\plusone} + +%D The usage of n and m: +%D +%D \startbuffer +%D \bTABLE[width=3em] +%D \bTR\bTD d1 \eTD\bTD[n=2] d2 \eTD\bTD[n=5] d5 \eTD\bTD[n=7] d7 \eTD\eTR +%D \bTR\bTD f1 \eTD\bTD[n=4] f4 \eTD\bTD[n=5] f5 \eTD\bTD[n=7] f7 \eTD\eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D \startbuffer +%D \bTABLE[width=3em] +%D \bTR\bTD d1 \eTD\bTD[m=2] d2 \eTD\bTD[m=5] d5 \eTD\bTD[m=7] d7 \eTD\eTR +%D \bTR\bTD f1 \eTD\bTD[m=4] f4 \eTD\bTD[m=5] f5 \eTD\bTD[m=7] f7 \eTD\eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \getbuffer +%D +%D \startbuffer +%D \bTABLE[frame=on] +%D \bTR \bTH[nc=3] One \eTH \bTH[m=4] Four \eTH\eTR +%D \bTR \bTD a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR +%D \eTABLE +%D +%D \bTABLE[frame=on] +%D \bTR \bTH[nr=2] One \eTH \bTH[m=3] Three \eTH\eTR +%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR +%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\def\tabl_ntb_th[#1]#2\eTH + {\tabl_ntb_td[#1,\c!color=\naturaltablelocalparameter\c!headcolor,\c!style=\naturaltablelocalparameter\c!headstyle,\c!aligncharacter=\v!no]#2\eTD} + +\def\tabl_ntb_tn[#1]#2\eTN + {\tabl_ntb_td[#1]\digits#2\relax\eTD} + +%D Vit Zyka needed the option to create a distance between columns, so I added +%D support for individual column distances. +%D +%D \startbuffer +%D % \setupTABLE[c][each][distance=2em] +%D \setupTABLE[c][1][distance=2em] +%D \setupTABLE[c][2][distance=3em] +%D +%D \bTABLE +%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR +%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR +%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR +%D \eTABLE +%D +%D \bTABLE[option=stretch] +%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR +%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR +%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR +%D \eTABLE +%D \stopbuffer +%D +%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection +%D +%D and he provided patches for the global left and right margin distances as well as +%D the columndistance (although i changed the names -). Here is his testcase: +%D +%D \startbuffer +%D \framed[offset=overlay]\bgroup +%D \setupTABLE[column][2][align=left]% +%D \setupTABLE[column][3][align=right]% +%D \bTABLE[columndistance=2cm,leftmargindistance=.3cm,rightmargindistance=.5cm] +%D \bTR \bTH[nc=3] Table head\eTH \eTR +%D \bTR \bTD[nc=2] AB\eTD \bTD C\eTD \eTR +%D \bTR \bTD[nc=2,align=left] AB\eTD \bTD C\eTD \eTR +%D \bTR \bTD[nc=2,align=middle] AB\eTD \bTD C\eTD \eTR +%D \bTR \bTD A\eTD \bTD B\eTD \bTD C\eTD \eTR +%D \bTR \bTD Aa\eTD \bTD Bb\eTD \bTD Cccc\eTD \eTR +%D \bTR \bTD[nc=3,align=middle] ABC\eTD \eTR +%D \eTABLE +%D \egroup +%D \stopbuffer +%D +%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection + +% to be done: head foot, dus state var + +\unexpanded\def\bTABLEhead{\dosingleempty\tabl_ntb_head} \let\eTABLEhead\relax +\unexpanded\def\bTABLEnext{\dosingleempty\tabl_ntb_next} \let\eTABLEnext\relax +\unexpanded\def\bTABLEbody{\dosingleempty\tabl_ntb_body} \let\eTABLEbody\relax +\unexpanded\def\bTABLEfoot{\dosingleempty\tabl_ntb_foot} \let\eTABLEfoot\relax + +\def\tabl_ntb_head[#1]#2\eTABLEhead{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_head} +\def\tabl_ntb_next[#1]#2\eTABLEnext{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_next} +\def\tabl_ntb_body[#1]#2\eTABLEbody{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_body} +\def\tabl_ntb_foot[#1]#2\eTABLEfoot{\appendtoks\tabl_ntb_section[#1]{#2}\to\t_tabl_ntb_foot} + +\def\tabl_ntb_section[#1]#2% also used in tabl-nte + {\unexpanded\def\tabl_ntb_setup_section{\setupcurrentnaturaltablelocal[#1]}% + #2% + \let\tabl_ntb_setup_section\relax} + +\def\tabl_ntb_preset_parameters% each odd|even level / can be sped up but only once per table + {\begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\v!each\endcsname + \begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\v!oddeven\m_tabl_tbl_level\endcsname + \begincsname\??naturaltableset\m_tabl_tbl_level:\v!start\m_tabl_tbl_level\endcsname} + +\unexpanded\def\bTABLE + {\dosingleempty\tabl_ntb_table} + +\def\tabl_ntb_table[#1]% + {\tabl_ntb_table_push + % box not here + \bgroup + \pushpostponednodedata + \t_tabl_ntb_head\emptytoks + \t_tabl_ntb_next\emptytoks + \t_tabl_ntb_body\emptytoks + \t_tabl_ntb_foot\emptytoks + \ifhmode\kern\zeropoint\fi % blocks \removeunwantedspaces: check this on icare handelingsschema + \resetcharacteralign % new + \setupcurrentnaturaltablelocal[\c!align={\v!right,\v!broad,\v!high},#1]% + % + \d_tabl_ntb_leftmargindistance \naturaltablelocalparameter\c!leftmargindistance\relax + \d_tabl_ntb_rightmargindistance\naturaltablelocalparameter\c!rightmargindistance\relax + \d_tabl_ntb_columndistance \naturaltablelocalparameter\c!columndistance\relax + \d_tabl_ntb_maxwidth \naturaltablelocalparameter\c!maxwidth\relax + % + \usesetupsparameter\naturaltablelocalparameter + \doifelse{\naturaltablelocalparameter\c!textwidth}\v!local + {\hsize\availablehsize} + {\hsize\naturaltablelocalparameter\c!textwidth}% + \enableTBLbreakfalse + \multipleTBLheadsfalse + \autoTBLspreadfalse + \tightTBLcolspanfalse + \processaction + [\naturaltablelocalparameter\c!split] + [ \v!yes=>\enableTBLbreaktrue, + \v!repeat=>\enableTBLbreaktrue\multipleTBLheadstrue, + \v!auto=>\ifinsidesplitfloat\enableTBLbreaktrue\fi] + \processaction + [\naturaltablelocalparameter\c!header] + [\v!repeat=>\multipleTBLheadstrue]% + \tabl_ntb_preset_parameters + \processallactionsinset + [\naturaltablelocalparameter\c!option] + [\v!stretch=>\autoTBLspreadtrue,% + \v!tight=>\tightTBLcolspantrue]% + \linewidth\naturaltablelocalparameter\c!rulethickness % needs to be frozen + \dontcomplain + \c_tabl_ntb_running_col \zerocount + \c_tabl_ntb_maximum_col \zerocount + \c_tabl_ntb_maximum_row \zerocount + \c_tabl_ntb_maximum_row_span\plusone + \let\currentTABLErow \tabl_ntb_current_row + \let\currentTABLEcolumn\tabl_ntb_current_column + \let\nofTABLErows \tabl_ntb_n_of_rows + \let\nofTABLEcolumns \tabl_ntb_n_of_columns + \let\bTR\dobTR + \let\bTD\dobTD + \let\bTH\dobTH + \let\bTN\dobTN} + +\def\tabl_ntb_current_row {\m_tabl_ntb_positive_row} +\def\tabl_ntb_current_column{\m_tabl_ntb_positive_col} +\def\tabl_ntb_n_of_rows {\number\c_tabl_ntb_maximum_row} +\def\tabl_ntb_n_of_columns {\number\c_tabl_ntb_maximum_col} + +\let\currentTABLErow \!!zerocount +\let\currentTABLEcolumn\!!zerocount +\let\nofTABLErows \!!zerocount +\let\nofTABLEcolumns \!!zerocount + +% there is no gain in a \doifelsenextoptionalcs variant + +\unexpanded\def\dobTR{\dosingleempty\tabl_ntb_tr} % also used in tabl-nte +\unexpanded\def\dobTD{\dosingleempty\tabl_ntb_td} % also used in tabl-nte +\unexpanded\def\dobTH{\dosingleempty\tabl_ntb_th} % also used in tabl-nte +\unexpanded\def\dobTN{\dosingleempty\tabl_ntb_tn} % also used in tabl-nte + +% permits \expanded{\bTD ... \eTD} + +\let\bTR\relax \unexpanded\def\eTR{\ignorespaces} % handy in case we use a macro to generate rows +\let\bTD\relax \unexpanded\def\eTD{\ignorespaces} +\let\bTH\relax \unexpanded\def\eTH{\ignorespaces} +\let\bTN\relax \unexpanded\def\eTN{\ignorespaces} + +\unexpanded\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode + {% tricky and dirty order -) + \doifelsesometoks\t_tabl_ntb_head % slow, better a flag + {\the\t_tabl_ntb_head + \c_tabl_ntb_n_of_head_lines\c_tabl_ntb_maximum_row\relax + \doifelsesometoks\t_tabl_ntb_next + {\the\t_tabl_ntb_next + \c_tabl_ntb_n_of_next_lines\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_n_of_head_lines\relax}% + {\c_tabl_ntb_n_of_next_lines\zerocount}% was 1 + \c_tabl_ntb_n_of_hdnx_lines\c_tabl_ntb_maximum_row} + {\c_tabl_ntb_n_of_head_lines\zerocount % was 1 + \c_tabl_ntb_n_of_next_lines\zerocount + \c_tabl_ntb_n_of_hdnx_lines\zerocount}% + \the\t_tabl_ntb_body + \the\t_tabl_ntb_foot + \removeunwantedspaces % only if hmode + % finish cells + \tabl_ntb_loop_one + % to be sure + \tabl_ntb_loop_two + % check and do + \ifcase\c_tabl_ntb_maximum_col\else + \startTBLprocessing + \tabl_ntb_table_start + \dorecurse\c_tabl_ntb_maximum_row + {\tabl_ntb_row_start + \c_tabl_ntb_current_row\recurselevel\relax + \dorecurse\c_tabl_ntb_maximum_col + {\c_tabl_ntb_current_col\recurselevel\relax + \normalexpanded{\tabl_ntb_cell{\the\c_tabl_ntb_current_row}{\the\c_tabl_ntb_current_col}}}% + \tabl_ntb_row_stop}% + \removeunwantedspaces % only if hmode + \tabl_ntb_table_stop + \stopTBLprocessing + % wrong ! ! ! better to have an auto-offset-overlay + % \ifnum\m_tabl_tbl_level>1 + % \vskip-\strutdp + % \fi + \fi + % tracing + % \iftrue + % \blank \tttf + % \dorecurse\c_tabl_ntb_maximum_row + % {\c_tabl_ntb_current_row\recurselevel\relax + % \dorecurse\c_tabl_ntb_maximum_col + % {\c_tabl_ntb_current_col\recurselevel\relax + % [r=\the\c_tabl_ntb_current_row,c=\the\c_tabl_ntb_current_col,h=\the\dimexpr\tabl_ntb_get_ht\c_tabl_ntb_current_row\c_tabl_ntb_current_col,w=\the\dimexpr\tabl_ntb_get_wd\c_tabl_ntb_current_row\c_tabl_ntb_current_col]}% + % \par}% + % \blank + % \fi + \poppostponednodedata + \egroup + \tabl_ntb_table_pop} + +\def\tabl_ntb_loop_one + {\dorecurse\c_tabl_ntb_maximum_row{\tabl_ntb_loop_one_rows}} + +\def\tabl_ntb_loop_one_rows + {\c_tabl_ntb_current_row\recurselevel\relax + \dorecurse\c_tabl_ntb_maximum_col\tabl_ntb_loop_one_cells} + +\def\tabl_ntb_loop_one_cells + {\c_tabl_ntb_current_col\recurselevel\relax + \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else + \tabl_ntb_loop_one_cells_indeed + \fi} + +\def\tabl_ntb_loop_one_cells_indeed + {\c_tabl_ntb_current_col_two\c_tabl_ntb_current_col + \c_tabl_ntb_current_row_two\c_tabl_ntb_current_row + \c_tabl_ntb_current_row_one\c_tabl_ntb_current_row + \doloop + {\c_tabl_ntb_current_col_one\c_tabl_ntb_current_col + \doloop + {\ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\endcsname + \exitloop + \else + \advance\c_tabl_ntb_current_col_one\plusone + \ifnum\c_tabl_ntb_current_col_one>\c_tabl_ntb_maximum_col\relax + \exitloop + \fi + \fi}% + \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\endcsname + \exitloop + \else + \c_tabl_ntb_current_row_two\c_tabl_ntb_current_row_one + \c_tabl_ntb_current_col_two\c_tabl_ntb_current_col_one + \advance\c_tabl_ntb_current_row_one\plusone + \ifnum\c_tabl_ntb_current_row_one>\c_tabl_ntb_maximum_row + \exitloop + \fi + \fi}% + \ifnum\c_tabl_ntb_current_row_two>\c_tabl_ntb_maximum_row\c_tabl_ntb_current_row_two\c_tabl_ntb_maximum_row\fi + \ifnum\c_tabl_ntb_current_col_two>\c_tabl_ntb_maximum_col\c_tabl_ntb_current_col_two\c_tabl_ntb_maximum_col\fi + \c_tabl_ntb_current_row_two\numexpr\c_tabl_ntb_current_row_two-\c_tabl_ntb_current_row+\plusone\relax + \c_tabl_ntb_current_col_two\numexpr\c_tabl_ntb_current_col_two-\c_tabl_ntb_current_col+\plusone\relax + \c_tabl_ntb_current_row_one\c_tabl_ntb_current_row + \dorecurse\c_tabl_ntb_current_row_two + {\c_tabl_ntb_current_col_one\c_tabl_ntb_current_col + \tabl_ntb_set_col\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one{\the\c_tabl_ntb_current_col_two}% + \dorecurse\c_tabl_ntb_current_col_two + {\tabl_ntb_let_tag\c_tabl_ntb_current_row_one\c_tabl_ntb_current_col_one\c_tabl_ntb_none + \advance\c_tabl_ntb_current_col_one\plusone}% + \advance\c_tabl_ntb_current_row_one\plusone}% + \tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_cell + \tabl_ntb_set_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_col_two}% + \tabl_ntb_set_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_row_two}% + \ifautoTBLemptycell + \normalexpanded + {\tabl_ntb_set_txt_process\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\c_tabl_ntb_current_row}{\the\c_tabl_ntb_current_col}}% + {\c!option=\v!tight}{\strut\kern\scaledpoint}% the kern forces the tight + \fi} + +\def\tabl_ntb_loop_two + {\dorecurse\c_tabl_ntb_maximum_row\tabl_ntb_loop_two_rows} + +\def\tabl_ntb_loop_two_rows + {\c_tabl_ntb_current_row\recurselevel\relax + \dorecurse\c_tabl_ntb_maximum_col\tabl_ntb_loop_two_cells} + +\def\tabl_ntb_loop_two_cells + {\c_tabl_ntb_current_col\recurselevel\relax + \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname + \scratchcounter\numexpr\c_tabl_ntb_maximum_row-\c_tabl_ntb_current_row+\plusone\relax + \ifnum\tabl_ntb_get_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col>\scratchcounter + \tabl_ntb_set_row\c_tabl_ntb_current_row\c_tabl_ntb_current_col{\the\scratchcounter}% + \fi + \fi + \tabl_ntb_let_ht\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zeropoint + %tabl_ntb_let_wd\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zeropoint + \ifcsname\tabl_ntb_col_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else + \tabl_ntb_let_col\c_tabl_ntb_current_row\c_tabl_ntb_current_col\zerocount + \fi + \ifcsname\tabl_ntb_tag_pattern\c_tabl_ntb_current_row\c_tabl_ntb_current_col\endcsname \else + \tabl_ntb_let_tag\c_tabl_ntb_current_row\c_tabl_ntb_current_col\c_tabl_ntb_none + \fi} + +\let\startTBLprocessing\relax % public +\let\stopTBLprocessing \relax % public + +\newcount\c_tabl_prelocated_rows % \prelocateTBLrows{1000} may speed up large tables + +% \def\tabl_ntb_row_start{\t_tabl_ntb_row\emptytoks} +% \def\tabl_ntb_row_stop {\normalexpanded{\t_tabl_ntb{\the\t_tabl_ntb\noexpand\tabl_ntb_row_align_start\the\t_tabl_ntb_row\tabl_ntb_row_align_stop}}} + +\def\tabl_ntb_row_start + {\t_tabl_ntb_row\emptytoks} + +\def\tabl_ntb_row_stop + {\ifenableTBLbreak + \tabl_ntb_row_stop_split + \else + \tabl_ntb_row_stop_boxed + \fi} + +\def\tabl_ntb_row_stop_boxed + {% \noindent % no, else double leftskip in narrower + \etoksapp\t_tabl_ntb + {% no need for init + \tabl_ntb_row_align_start + \the\t_tabl_ntb_row + \tabl_ntb_row_align_stop}} + +\def\tabl_ntb_row_stop_split + {\ifcsname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname + \tabl_ntb_row_stop_split_yes + \else + \tabl_ntb_row_stop_split_nop + \fi} + +\def\tabl_ntb_row_stop_split_nop + {\etoksapp\t_tabl_ntb + {\tabl_ntb_row_align_reset + \tabl_ntb_row_align_start + \the\t_tabl_ntb_row + \tabl_ntb_row_align_stop}} + +\def\tabl_ntb_row_stop_split_yes + {\begingroup + \csname\??naturaltableset\m_tabl_tbl_level:\c!y++\the\c_tabl_ntb_current_row\endcsname + \xdef\m_tabl_ntb_before_split{\naturaltablelocalparameter\c!before}% to be checked + \xdef\m_tabl_ntb_after_split {\naturaltablelocalparameter\c!after}% to be checked + \xdef\m_tabl_ntb_same_page {\naturaltablelocalparameter\c!samepage}% + \endgroup + \etoksapp\t_tabl_ntb + {\tabl_ntb_row_align_set{\m_tabl_ntb_before_split}{\m_tabl_ntb_after_split}{\m_tabl_ntb_same_page}% + \tabl_ntb_row_align_start + \the\t_tabl_ntb_row + \tabl_ntb_row_align_stop}} + +\unexpanded\def\tabl_ntb_row_align_set#1#2#3% + {\xdef\m_tabl_ntb_before_split{#1}% + \xdef\m_tabl_ntb_after_split {#2}% + \xdef\m_tabl_ntb_same_page {#3}} + +\unexpanded\def\tabl_ntb_row_align_reset + {\glet\m_tabl_ntb_before_split\empty + \glet\m_tabl_ntb_after_split \empty + \glet\m_tabl_ntb_same_page \empty} + +\def\tabl_ntb_prelocate_error + {\writestatus\m!TABLE{fatal error: use \string\prelocateTBLrows\space to increase table memory (now: \the\c_tabl_prelocated_rows)}} + +% \prelocateTBLrows{1000} % may speed up large tables + +\def\prelocateTBLrows#1% we start at zero so we have one to much, better play safe anyway + {\dostepwiserecurse\c_tabl_prelocated_rows{#1}\plusone + {\expandafter\newtoks\csname\??naturaltabletok\recurselevel\endcsname}% + \def\tabl_ntb_row_start + {\ifnum\c_tabl_ntb_row<\c_tabl_prelocated_rows\relax + \tabl_ntb_prelocate_okay + \else + \tabl_ntb_prelocate_error + \fi}% + \def\tabl_ntb_row_stop + {\etoksapp\t_tabl_ntb + {\tabl_ntb_row_align_start + \the\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname + \tabl_ntb_row_align_stop}}% + \global\c_tabl_prelocated_rows#1\relax} + +\def\tabl_ntb_prelocate_okay + {\expandafter\let\expandafter\t_tabl_ntb_row\csname\??naturaltabletok\the\c_tabl_ntb_row\endcsname\t_tabl_ntb_row\emptytoks} + +%D We use aligments to handle the empty (skipped) columns, so that we don't have to +%D (re|)|calculate these. + +\let\m_tabl_ntb_saved_row\!!zerocount +\let\m_tabl_ntb_saved_col\!!zerocount + +\unexpanded\def\tabl_ntb_row_align_start + {\global\advance\c_tabl_ntb_row\plusone + \global\c_tabl_ntb_col\plusone + \global\c_tabl_ntb_spn\zerocount + \tabl_ntb_row_align_start_inject + \dostarttagged\t!tablerow\empty + \hbox\bgroup + \kern\dimexpr\d_tabl_ntb_leftmargindistance\relax} + +\unexpanded\def\tabl_ntb_row_align_stop + {\kern\dimexpr\d_tabl_ntb_rightmargindistance-\d_tabl_ntb_columndistance\relax + \egroup + \dostoptagged + \tabl_ntb_row_align_stop_inject} + +\unexpanded\def\tabl_ntb_before_page + {\ifx\m_tabl_ntb_same_page\v!before + % \blank[\v!samepage,\v!strong]% + \unpenalty + \nobreak + \orelse\ifx\m_tabl_ntb_same_page\v!both + % \blank[\v!samepage,\v!strong]% + \unpenalty + \nobreak + \fi} + +\unexpanded\def\tabl_ntb_after_page + {\ifnum\c_tabl_ntb_row>\c_tabl_ntb_n_of_head_lines + \ifnum\tabl_ntb_get_nob\c_tabl_ntb_row=\zerocount + \unpenalty + \ifx\m_tabl_ntb_same_page\v!after + % \blank[\v!samepage,\v!strong]% + \nobreak + \orelse\ifx\m_tabl_ntb_same_page\v!both + % \blank[\v!samepage,\v!strong]% + \nobreak + \else + % \blank[\v!preference,\v!weak]% + \allowbreak + \fi + \fi + \else + % \blank[\v!preference,\v!weak]% + \allowbreak % else no proper head split off + \fi} + +\unexpanded\def\tabl_ntb_inbetween + {\scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax + \ifnum\scratchcounter>\c_tabl_ntb_n_of_hdnx_lines\relax + \ifnum\scratchcounter<\c_tabl_ntb_maximum_row\relax + \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}% + \ifx\p_spaceinbetween\empty\else + \blank[\p_spaceinbetween]% + \fi + \fi + \fi} + +\unexpanded\def\tabl_ntb_row_align_start_inject + {\bgroup % protect local vars + \m_tabl_ntb_before_split + \egroup + \ifenableTBLbreak + \tabl_ntb_before_page + \fi} + +\unexpanded\def\tabl_ntb_row_align_stop_inject + {\par + \nointerlineskip + \ifenableTBLbreak + \tabl_ntb_after_page + \fi + \bgroup % protect local vars + \m_tabl_ntb_after_split + \egroup + \bgroup % protect local vars + \tabl_ntb_inbetween + \egroup} + +\def\tabl_ntb_flush_content + {\the\everyTABLEpass + \global\c_tabl_ntb_spn\zerocount + \global\c_tabl_ntb_col\zerocount + \global\c_tabl_ntb_row\zerocount + \global\advance\c_tabl_ntb_row\minusone + \dostarttaggedchained\t!table\empty\??naturaltable + %\registerparoptions % (*) triggers max hsize + \the\t_tabl_ntb + \dostoptagged} + +\unexpanded\def\tabl_ntb_span#1% + {\hskip\tabl_ntb_get_dis\c_tabl_ntb_col + \dorecurse{#1} + {\hskip\tabl_ntb_get_wid\c_tabl_ntb_col\relax + \global\advance\c_tabl_ntb_col\plusone}} + +\unexpanded\def\tabl_ntb_skip#1% + {\global\advance\c_tabl_ntb_col#1\relax} + +\unexpanded\def\tabl_ntb_plus + {\global\advance\c_tabl_ntb_col\plusone + \kern\d_tabl_ntb_columndistance} + +\setvalue{\??naturaltablecell\the\c_tabl_ntb_none}#1#2% + {\scratchcounter\tabl_ntb_get_col{#1}{#2}\relax + \ifnum\scratchcounter>\zerocount + \etoksapp\t_tabl_ntb_row + {\tabl_ntb_span{\the\scratchcounter}}% + \fi} + +\setvalue{\??naturaltablecell\the\c_tabl_ntb_cell}#1#2% + {\toksapp\t_tabl_ntb_row{\tabl_ntb_pass #1 #2 }% space delimited -> less tokens + \scratchcounter\tabl_ntb_get_col{#1}{#2}\relax + \ifnum\scratchcounter>\zerocount + \etoksapp\t_tabl_ntb_row + {\ifnum\scratchcounter=\plusone + \tabl_ntb_plus + \else + \tabl_ntb_skip{\the\scratchcounter}% + \fi}% + \fi} + +\unexpanded\def\tabl_ntb_cell#1#2% + {\csname\??naturaltablecell\the\tabl_ntb_get_tag{#1}{#2}\endcsname{#1}{#2}} + +\unexpanded\def\tabl_ntb_table_start + {\global\c_tabl_ntb_spn\zerocount + \global\c_tabl_ntb_row\zerocount + \global\c_tabl_ntb_col\zerocount + \c_tabl_tbl_pass\zerocount + \t_tabl_ntb\emptytoks} + +\def\tabl_ntb_pass_one#1 #2 % + {\tabl_ntb_get_txt{#1}{#2}}% + +\def\tabl_ntb_pass_two#1 #2 % meer in cellD + {\d_tabl_ntb_width\zeropoint + \scratchcounter\c_tabl_ntb_col + \!!counta\tabl_ntb_get_col{#1}{#2}\relax + \ifcase\!!counta\or + \advance\d_tabl_ntb_width\dimexpr + \tabl_ntb_get_wid\scratchcounter + \relax + \advance\scratchcounter\plusone + \else + \dorecurse\!!counta + {\advance\d_tabl_ntb_width\dimexpr + \tabl_ntb_get_wid\scratchcounter + \ifnum\recurselevel<\!!counta + +\d_tabl_ntb_columndistance + +\tabl_ntb_get_dis\scratchcounter + \fi + \relax + \advance\scratchcounter\plusone}% + \fi + \setbox\scratchbox\hbox{\tabl_ntb_get_txt{#1}{#2}}% + \tabl_ntb_set_ht{#1}{#2}{\the\ht\scratchbox}% + %tabl_ntb_set_wd{#1}{#2}{\the\wd\scratchbox}% + \ifdim\ht\scratchbox>\tabl_ntb_get_hei{#1}\relax + \tabl_ntb_set_hei{#1}{\the\ht\scratchbox}% + \fi}% + +\def\tabl_ntb_pass_three#1 #2 % + {% height + \dostarttagged\t!tablecell\empty + \!!counta \tabl_ntb_get_col{#1}{#2}\relax + \!!countb \tabl_ntb_get_row{#1}{#2}\relax + \!!heighta\tabl_ntb_get_ht {#1}{#2}\relax + \tablecellcolumns\!!counta % used later so don't adapt these + \tablecellrows \!!countb % used later so don't adapt these + \d_tabl_ntb_height\zeropoint + \ifnum\!!counta=\c_tabl_ntb_maximum_col\relax + % case: nc=maxcolumns + \else + \scratchcounter#1\relax + \dorecurse\!!countb + {\advance\d_tabl_ntb_height\tabl_ntb_get_hei\scratchcounter + \advance\scratchcounter\plusone}% + \ifdim\d_tabl_ntb_height<\!!heighta\relax + \d_tabl_ntb_height\!!heighta + \fi + \fi + % width + \d_tabl_ntb_width\zeropoint + \scratchcounter\c_tabl_ntb_col + \ifcase\!!counta\or + \advance\d_tabl_ntb_width\dimexpr + \tabl_ntb_get_wid\scratchcounter + \relax + \advance\scratchcounter\plusone + \else + \dorecurse\!!counta + {\advance\d_tabl_ntb_width\dimexpr + \tabl_ntb_get_wid\scratchcounter + \ifnum\recurselevel<\!!counta + +\d_tabl_ntb_columndistance + +\tabl_ntb_get_dis\scratchcounter + \fi + \relax + \advance\scratchcounter\plusone}% + \fi + % cell + \setbox\scratchbox\hbox attr \taggedattribute \attribute\taggedattribute \bgroup + \dotagTABLEsignal % maybe we need to add some packaging in this case + \tabl_ntb_get_txt{#1}{#2}% + \egroup + \ifnum\!!counta=\c_tabl_ntb_maximum_col\relax + % case: nc=maxcolumns + \else + \scratchdimen\tabl_ntb_get_hei{#1}% + \setbox\scratchbox\hpack + {\lower\ht\scratchbox\hpack{\raise\scratchdimen\box\scratchbox}}% + \ht\scratchbox\scratchdimen + \fi + \dp\scratchbox\zeropoint + \edef\!!stringa{\tabl_ntb_get_ref{#1}{#2}}% + \ifx\!!stringa\empty + \box\scratchbox + \else + \normalexpanded{\noexpand\directgotobox{\box\scratchbox}[\!!stringa]}% to be checked + \fi + \dostoptagged} % right spot + +% \def\tabl_ntb_cell_finalize +% {\doifnotinset\localwidth{\v!fit,\v!broad}% user set +% {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax +% \ifdim\localwidth>\scratchdimen +% \tabl_ntb_set_aut\c_tabl_ntb_col{\the\dimexpr\localwidth}% +% \fi}} + +\def\tabl_ntb_cell_finalize + {\ifx\localwidth\v!fit + % nothing + \orelse\ifx\localwidth\v!broad + % nothing + \orelse\ifx\localwidth\empty + % nothing (safeguard) + \else + \tabl_ntb_cell_finalize_indeed + \fi} + +\def\tabl_ntb_cell_finalize_indeed + {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax + \ifdim\localwidth>\scratchdimen + \tabl_ntb_set_aut\c_tabl_ntb_col{\the\dimexpr\localwidth}% + \fi} + +\let\tabl_ntb_preroll\relax + +\def\tabl_ntb_table_get_max_width + {\scratchdimen\wd\scratchbox\relax} + +% enable dper 2018-02-22 + +\def\tabl_ntb_table_get_max_width_step + {\advance\scratchdimen\tabl_ntb_get_wid\fastloopindex + \advance\scratchdimen\tabl_ntb_get_dis\fastloopindex} + +\def\tabl_ntb_table_get_max_width + {\scratchdimen\zeropoint + \dofastloopcs\c_tabl_ntb_maximum_col\tabl_ntb_table_get_max_width_step + \ifdim\scratchdimen<\wd\scratchbox\relax + \scratchdimen\wd\scratchbox\relax + \fi} + +\def\tabl_ntb_table_stop + {\forgetall % new, here see narrower-004.tex + %\setbox\scratchbox\hbox + % {\letnaturaltablelocalparameter\c!frame\v!off + % \letnaturaltablelocalparameter\c!background\empty + % \letnaturaltablelocalparameter\c!align\v!no + % \inheritednaturaltablelocalframed{\strut}}% + %\edef\minimalcellheight{\the\ht\scratchbox}% not used + \dorecurse\c_tabl_ntb_maximum_col + {\tabl_ntb_let_aut\recurselevel\zeropoint + % new + \c_tabl_ntb_current_col_one\recurselevel\relax + \dorecurse\c_tabl_ntb_maximum_row + {%tabl_ntb_let_wd\recurselevel\c_tabl_ntb_current_col_one\zeropoint + \tabl_ntb_let_ht\recurselevel\c_tabl_ntb_current_col_one\zeropoint}% + % till here + \tabl_ntb_let_tal\recurselevel\zerocount + \tabl_ntb_let_wid\recurselevel\zeropoint + \tabl_ntb_let_dis\recurselevel\zeropoint}% + \dorecurse\c_tabl_ntb_maximum_row + {\tabl_ntb_let_hei\recurselevel\maxdimen}% + \tabl_ntb_let_gal\zerocount + \tabl_ntb_preroll\relax + \c_tabl_tbl_pass\plusone + \let\tabl_ntb_pass\tabl_ntb_pass_one + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_a + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + \ifcase\tabl_ntb_get_gal\or + % \c_tabl_tbl_pass\plusone + % \let\tabl_ntb_pass\tabl_ntb_pass_one + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_a_extra + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + \fi + \tabl_ntb_let_dis\c_tabl_ntb_maximum_col\zeropoint + % + \tabl_ntb_table_get_max_width % \scratchdimen\scratchbox + % + \ifautoTBLspread + % experimental, stretch non fixed cells to \hsize + \tabl_ntb_check_widths_one % trial run + \tabl_ntb_check_widths_two % real run + \tabl_ntb_stretch_widths + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_b + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + % \orelse\ifdim\wd\scratchbox>\hsize + \orelse\ifdim\scratchdimen>\hsize + \ifautoTBLhsize + \tabl_ntb_check_widths_one % trial run + \tabl_ntb_check_widths_two % real run + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_b + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + \fi + \orelse\ifautoTBLrowspan + \ifnum\c_tabl_ntb_maximum_row_span>\plusone % max ? + % added jan 2002 because nx=* did no longer work + \ifnum\c_tabl_ntb_encountered_max<\c_tabl_ntb_maximum_col + % added jun 2014 because someone had less columns than nx .. sigh / see *nx* + \writestatus\m!TABLE{missing\space\number\numexpr\c_tabl_ntb_maximum_col-\c_tabl_ntb_encountered_max\relax\space column(s), guessing widths}% + \fi + \edef\savedhsize{\the\hsize}% + % \hsize\wd\scratchbox\relax % new per 17/04/2006 + \hsize\scratchdimen\relax % new per 17/04/2006 + \tabl_ntb_check_widths_one % trial run + \tabl_ntb_check_widths_two % real run + \hsize\savedhsize + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_c + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + \fi + \fi + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_d + \c_tabl_tbl_pass\plustwo + \let\tabl_ntb_pass\tabl_ntb_pass_two + \setbox\scratchbox\vbox{\settrialtypesetting \tabl_ntb_flush_content}% + \tabl_ntb_check_heights_one + \tabl_ntb_check_heights_two + \let\tabl_ntb_cell_process\tabl_ntb_cell_process_e + \c_tabl_tbl_pass\plusthree + \let\tabl_ntb_pass\tabl_ntb_pass_three + \ifnum\m_tabl_tbl_level>\plusone + \tabl_tbl_split_nop + \orelse\ifenableTBLbreak + \tabl_tbl_split_yes + \else + \tabl_tbl_split_nop + \fi} + +\def\tabl_ntb_stretch_widths % more variants, e.g. a max to \dimend + {\ifcase\c_tabl_ntb_maximum_col\else % else division by zero + \!!dimend\zeropoint + \!!dimene\dimexpr + \hsize + -\d_tabl_ntb_leftmargindistance + -\d_tabl_ntb_rightmargindistance + +\d_tabl_ntb_columndistance + \relax + \dorecurse\c_tabl_ntb_maximum_col + {\advance\!!dimend\dimexpr + \tabl_ntb_get_wid\recurselevel + \relax + \advance\!!dimene\dimexpr + -\tabl_ntb_get_dis\recurselevel + -\d_tabl_ntb_columndistance + \relax}% + \relax + % distribute width (stretch) + \ifdim\!!dimend<\!!dimene + \advance\!!dimend-\!!dimene + \divide\!!dimend\c_tabl_ntb_maximum_col + \dorecurse\c_tabl_ntb_maximum_col + {\tabl_ntb_set_wid\recurselevel{\the\dimexpr\tabl_ntb_get_wid\recurselevel-\!!dimend\relax}}% + \fi + \fi} + +\def\tabl_tbl_split_nop + {\setbox\b_tabl_ntb_final\vbox{\tabl_ntb_flush_content}% + \postprocessTABLEbox\b_tabl_ntb_final + \beforeTABLEbox + % packaging prevents max hsized box + % \hbox{\registerparoptions\box\b_tabl_ntb_final}% (*) better here + % better : + \ifinsidefloat + % no \dontleavehmode else too wide, otherwise we get a \hsized box + \else + \registerparoptions % (*) better here (also does a \dontleavehmode) + \ifhmode\else\dontleavehmode\fi + \fi + \box\b_tabl_ntb_final + \afterTABLEbox} + +\def\tabl_tbl_split_yes + {\ifinsidesplitfloat + \donetrue + \orelse\ifinsidefloat + \donefalse + \else + \donetrue + \fi + \ifdone + \expandafter\tabl_ntb_split_box + \else + \expandafter\tabl_tbl_split_nop + \fi} + +\newbox\TABLEsplitbox % public, don't change + +\let\extratblsplitheight\zeropoint % additional space taken by before/afterTABLEsplitbox + +\def\tabl_ntb_split_box + {\resettsplit + \def\tsplitminimumfreelines{2}% + \def\tsplitminimumfreespace{\dimexpr\extratblsplitheight+\naturaltablelocalparameter\c!splitoffset\relax}% + \def\tsplitbeforeresult {\beforeTABLEsplitbox}% + \def\tsplitafterresult {\afterTABLEsplitbox}% + \def\tsplitafter {\m_tabl_ntb_after_split}% + \def\tsplitbefore {\m_tabl_ntb_before_split}% supported ? + \setbox\tsplitcontent\vbox{\tabl_ntb_flush_content}% + \ifmultipleTBLheads + \dorecurse\c_tabl_ntb_n_of_head_lines + {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight + \setbox\tsplithead\vbox{\unvcopy\tsplithead\unvcopy\scratchbox}}% \vpack ? + \dorecurse\c_tabl_ntb_n_of_next_lines + {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight + \setbox\tsplitnext\vbox{\unvcopy\tsplitnext\unvcopy\scratchbox}}% \vpack ? + \fi + \edef\p_spaceinbetween{\naturaltablelocalparameter\c!spaceinbetween}% + \ifx\p_spaceinbetween\empty\else + \blank[\p_spaceinbetween]% + \fi + \def\postprocesstsplit{\postprocessTABLEsplitbox{\box\tsplitresult}}% + \handletsplit} + +% ! ! ! ! TODO: naast \postprocessTABLEsplitbox ook evt \postprocessTABLEbox voor niet split + +\let\postprocessTABLEsplitbox\gobbleoneargument +\let\postprocessTABLEbox \gobbleoneargument + +\let\beforeTABLEsplitbox\relax +\let\afterTABLEsplitbox \relax +\let\beforeTABLEbox \relax +\let\afterTABLEbox \relax + +\def\tabl_ntb_check_widths_one{\tabl_ntb_check_widths_indeed\zerocount} % 0 = trial run +\def\tabl_ntb_check_widths_two{\tabl_ntb_check_widths_indeed\plusone } % 1 = real run + +\def\tabl_ntb_check_widths_indeed#1% + {\ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths B#1\fi + \!!counta\zerocount + \!!dimena\dimexpr + \hsize + -\d_tabl_ntb_leftmargindistance + -\d_tabl_ntb_rightmargindistance + -\d_tabl_ntb_columndistance + \relax + \dorecurse\c_tabl_ntb_maximum_col + {\scratchdimen\tabl_ntb_get_aut\recurselevel\relax + \advance\!!dimena\dimexpr + -\tabl_ntb_get_dis\recurselevel + -\d_tabl_ntb_columndistance + \relax + \ifdim\scratchdimen>\zeropoint\relax + \advance\!!dimena -\scratchdimen + \else + \scratchdimen\tabl_ntb_get_wid\recurselevel\relax + \ifdim\scratchdimen>\d_tabl_ntb_maxwidth\relax + \ifcase#1\else\tabl_ntb_let_wid\recurselevel\zeropoint\fi + \advance\!!counta \plusone + \orelse\ifdim\scratchdimen>\zeropoint\relax + \advance\!!dimena -\scratchdimen + \else + % eigenlijk moet dit alleen als de kolom wordt overspannen door een + % vorige, maw extra dubbele loop en status var + \ifnum\c_tabl_ntb_encountered_max=\c_tabl_ntb_maximum_col % *nx* bah + \advance\!!counta \plusone % setting maxwidth to a large value also works + \fi + \fi + \fi}% + \ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths M#1\fi + \ifcase\!!counta \else \divide\!!dimena \!!counta \fi + \dorecurse\c_tabl_ntb_maximum_col + {\scratchdimen\tabl_ntb_get_wid\recurselevel\relax + \ifcase#1\relax + \ifdim\scratchdimen<\!!dimena % take natural width + \tabl_ntb_set_aut\recurselevel{\the\scratchdimen}% + \fi + \else + \ifdim\scratchdimen=\zeropoint % auto set width + \tabl_ntb_set_wid\recurselevel{\the\!!dimena}% + \fi + \fi}% + \ifconditional\c_tabl_ntb_trace_widths\tabl_ntb_show_widths E#1\fi} + +% todo: use scratchcounters, not !! ones + +\def\tabl_ntb_check_heights_one_indeed + {\!!countb\tabl_ntb_get_row\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\relax + % check row span + \ifnum\!!countb>\plusone + % current height in row + \dimen0=\tabl_ntb_get_ht\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three + % find nearest height in row + \dimen2=\zeropoint + \dorecurse\c_tabl_ntb_maximum_col + {\ifnum\recurselevel=\c_tabl_ntb_current_col_three\else + \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row_three\recurselevel\endcsname + \!!countc=\tabl_ntb_get_row\c_tabl_ntb_current_row_three\recurselevel\relax + \ifnum\!!countc=\plusone + \dimen4=\tabl_ntb_get_ht\c_tabl_ntb_current_row_three\recurselevel\relax + \ifdim\dimen2<\dimen4 + \dimen2=\dimen4 + \fi + \fi + \fi + \fi}% + \c_tabl_ntb_current_row_four\c_tabl_ntb_current_row_three + % calculate cummulative height + \dimen4=\dimen2 + \!!countc\c_tabl_ntb_current_row_three + \advance\!!countc\minusone + \dorecurse\!!countb + {\ifnum\c_tabl_ntb_current_row_four=\c_tabl_ntb_current_row_three\else + \advance\dimen4 \tabl_ntb_get_hei\c_tabl_ntb_current_row_four + \fi + \ifnum\recurselevel=\!!countb\else + \tabl_ntb_set_nob\!!countc + \advance\!!countc\plusone + \fi + \advance\c_tabl_ntb_current_row_four\plusone}% + % distribute overshoot equally + \ifdim\dimen2>\zeropoint % new: test on natural-003 + \ifdim\dimen4<\dimen0 + \advance\dimen0 -\dimen4 + \divide\dimen0 \!!countb + \c_tabl_ntb_current_row_four\c_tabl_ntb_current_row_three + \tabl_ntb_set_hei\c_tabl_ntb_current_row_three{\the\dimen2}% + \dorecurse\!!countb + {\dorecurse\c_tabl_ntb_maximum_col + {\ifnum\recurselevel=\c_tabl_ntb_current_col_three\else + \scratchdimen\dimexpr\tabl_ntb_get_ht\c_tabl_ntb_current_row_four\recurselevel+\dimen0\relax + \tabl_ntb_set_ht\c_tabl_ntb_current_row_four\recurselevel{\the\scratchdimen}% + \ifdim\tabl_ntb_get_hei\c_tabl_ntb_current_row_four<\scratchdimen + \tabl_ntb_set_hei\c_tabl_ntb_current_row_four{\the\scratchdimen}% + \fi + \fi}% + \advance\c_tabl_ntb_current_row_four\plusone}% + \orelse\ifdim\dimen4>\dimen0 + \iftightTBLrowspan + \tabl_ntb_set_hei\c_tabl_ntb_current_row_three{\the\dimen2}% + \fi + \fi + \fi + \fi} + +\def\tabl_ntb_check_heights_one + {\dorecurse\c_tabl_ntb_maximum_row + {\c_tabl_ntb_current_row_three\recurselevel\relax + \dorecurse\c_tabl_ntb_maximum_col + {\c_tabl_ntb_current_col_three\recurselevel\relax + \ifcsname\tabl_ntb_row_pattern\c_tabl_ntb_current_row_three\c_tabl_ntb_current_col_three\endcsname + \tabl_ntb_check_heights_one_indeed + \fi}}} + +\def\tabl_ntb_check_heights_two + {} + +\def\tabl_ntb_show_widths#1#2% + {\begingroup + \scratchdimen\zeropoint + \dorecurse\c_tabl_ntb_maximum_col + {\advance\scratchdimen\tabl_ntb_get_wid\recurselevel\relax}% + \writestatus\m!TABLE{#1 \ifcase#2trial\else real\fi: hsize: \the\hsize, total: \the\scratchdimen}% + \dorecurse\c_tabl_ntb_maximum_col + {\writestatus\m!TABLE{\space\space\recurselevel: \the\dimexpr\tabl_ntb_get_wid\recurselevel}}% + \endgroup} + +\def\tabl_ntb_char_align % called often + {\edef\p_characteralign{\naturaltablelocalparameter\c!aligncharacter}% + \ifx\p_characteralign\v!yes + \ifcase\c_tabl_tbl_pass\or + \tabl_ntb_let_tal\currentTABLEcolumn\plusone + \tabl_ntb_let_gal\plusone + \fi + \expandafter\tabl_ntb_char_align_indeed + \else + \expandafter\gobbletwoarguments + \fi} + +\def\tabl_ntb_char_align_indeed#1#2% row column + {\ifcase\c_tabl_tbl_pass \or + \setcharacteralign{#2}{\naturaltablelocalparameter\c!alignmentcharacter}% we could store the character in tal + \fi + \typo_charalign_adapt_font + \signalcharacteralign{#2}{#1}} + +\unexpanded\def\tabl_ntb_cell_process_a_extra#1#2% + {\ifcase\tabl_ntb_get_tal{#2}\relax + \expandafter\tabl_ntb_cell_process_x + \else + \expandafter\tabl_ntb_cell_process_a + \fi{#1}{#2}} + +\unexpanded\def\tabl_ntb_cell_process_x#1#2[#3]#4% + {} + +% problem: when span doesn't break we can have a span that is the sum of cells but +% still to small .. chicken egg problem ... for that we should also have a smallest +% width run +% +% nilling the background makes a run upto 25% faster + +\def\tabl_ntb_cell_process_a_check_span_one + {\ifautosqueezeTBLspan + \edef\p_width{\naturaltablelocalparameter\c!width}% + \ifcsname\??naturaltablesqueeze\p_width\endcsname\lastnamedcs\else\donefalse\fi + \else + \donetrue + \fi + \ifdone % brr, 0 + \ifnum\scratchcounter>\plusone + \tabl_ntb_set_spn\c_tabl_ntb_col + \fi + \fi} + +\let\tabl_ntb_cell_process_a_check_span_two_yes\relax + +\def\tabl_ntb_cell_process_a_check_span_two_nop + {\ifdim\tabl_ntb_get_wid\c_tabl_ntb_col<\wd\scratchbox + \tabl_ntb_set_wid\c_tabl_ntb_col{\the\wd\scratchbox}% + \fi} + +\unexpanded\def\tabl_ntb_cell_process_a#1#2[#3]#4% grouping added ! ! ! + {\bgroup + \letnaturaltablelocalparameter\c!option\empty + \tabl_ntb_setup_cell{#1}{#2}% + \setupcurrentnaturaltablelocal[#3]% + \letnaturaltablelocalparameter\c!background\empty + \letnaturaltablelocalparameter\c!frame\v!off + \scratchcounter\tabl_ntb_get_col{#1}{#2}\relax + \setbox\scratchbox\hbox + {\scratchdimen\naturaltablelocalparameter\c!distance\relax + \ifdim\scratchdimen>\tabl_ntb_get_dis{#2}\relax + \tabl_ntb_set_dis{#2}{\the\scratchdimen}% + \fi + \anch_backgrounds_text_level_start + \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop\tabl_ntb_cell_finalize}% + \anch_backgrounds_text_level_stop + \ifcase\c_anch_backgrounds_text_count\else + \tabl_ntb_let_bck{#1}{#2}\c_anch_backgrounds_text_state + \fi + }% + \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax + \ifdim\wd\scratchbox>\scratchdimen + \ifsqueezeTBLspan + \tabl_ntb_cell_process_a_check_span_one + \fi + \tabl_ntb_spn_doifelse\c_tabl_ntb_col + \tabl_ntb_cell_process_a_check_span_two_yes + \tabl_ntb_cell_process_a_check_span_two_nop + \fi + \scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax + \scratchdimen\tabl_ntb_get_hei\scratchcounter\relax + \ifdim\ht\scratchbox<\scratchdimen + \tabl_ntb_set_hei\scratchcounter{\the\ht\scratchbox}% auto set + \fi + \tabl_ntb_set_ht{#1}{#2}{\the\ht\scratchbox}% + %tabl_ntb_set_wd{#1}{#2}{\the\wd\scratchbox}% + \ifautoTBLcheckwidth + \ifdim\wd\scratchbox<.75\hsize % fuzzy guess + \ifdim\ht\scratchbox>2\openlineheight % honor width since this + \scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax % can be a figure or so + \ifdim\scratchdimen=\zeropoint + % side effect: when width is set to 0pt, + % we can force a span that fits the sum of spans widths + \tabl_ntb_set_aut\c_tabl_ntb_col{\the\scratchdimen}% + \orelse\ifdim\wd\scratchbox>\scratchdimen + % unless span + \tabl_ntb_set_aut\c_tabl_ntb_col{\the\wd\scratchbox}% + % to be translated + \writestatus\m!TABLE{no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}% + \fi + \fi + \fi + \fi + \setbox\scratchboxone\emptyhbox + \wd\scratchboxone\wd\scratchbox + \ht\scratchboxone\ht\scratchbox + \dp\scratchboxone\dp\scratchbox + \box\scratchboxone + \egroup} + +\unexpanded\def\tabl_ntb_cell_process_b_c#1#2#3[#4]#5% + {\setbox\scratchbox\hbox + {\tabl_ntb_setup_cell{#2}{#3}% + \setupcurrentnaturaltablelocal[#4,#1]% + \letnaturaltablelocalparameter\c!background\empty + \letnaturaltablelocalparameter\c!frame\v!off + \inheritednaturaltablelocalframed{\tabl_ntb_cell_start#5\tabl_ntb_cell_stop}}% + \setbox2\emptyhbox % todo: \scratchboxtwo + \wd2\wd\scratchbox + \ht2\ht\scratchbox + \dp2\dp\scratchbox + \ifautoTBLrowspan + \scratchcounter\numexpr\c_tabl_ntb_row+\plusone\relax + \ifcsname\tabl_ntb_row_pattern\scratchcounter\c_tabl_ntb_col\endcsname + \scratchdimen\tabl_ntb_get_hei\scratchcounter\relax + \ifnum\tabl_ntb_get_row\scratchcounter\c_tabl_ntb_col>\plusone + \ifdim\ht\scratchbox>\scratchdimen + \ht2\dimexpr-\scratchdimen-\ht\scratchbox\relax + \fi + \fi + \fi + \fi + \box2 } + +\unexpanded\def\tabl_ntb_cell_process_b#1#2[#3]#4% + {\scratchdimen\tabl_ntb_get_aut\c_tabl_ntb_col\relax + \ifdim\scratchdimen>\zeropoint\relax + \else + \scratchdimen\tabl_ntb_get_wid\c_tabl_ntb_col\relax + \ifdim\scratchdimen>\zeropoint\relax + \ifnum\tabl_ntb_get_col{#1}{#2}=\c_tabl_ntb_maximum_col\relax + \scratchdimen\hsize + \fi + \fi + \fi + \normalexpanded{\tabl_ntb_cell_process_b_c{\ifdim\scratchdimen>\zeropoint \c!width=\the\scratchdimen\fi}}% + {#1}{#2}[#3]{\tabl_ntb_char_align{#1}{#2}#4}} + +\unexpanded\def\tabl_ntb_cell_process_c + {\tabl_ntb_cell_process_b_c{}} + +\unexpanded\def\tabl_ntb_cell_process_d#1#2[#3]#4% + {\tabl_ntb_setup_cell{#1}{#2}% + \bgroup + \setupcurrentnaturaltablelocal[#3]% + \letnaturaltablelocalparameter\c!background\empty + \letnaturaltablelocalparameter\c!frame\v!off + \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}% + \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}% + \egroup} + +\unexpanded\def\tabl_ntb_cell_process_e#1#2[#3]#4% + {\tabl_ntb_setup_cell{#1}{#2}% + \setupcurrentnaturaltablelocal[#3]% to get the color right, the way we + \color % handle color here prevents interference due to whatsit nodes + [\naturaltablelocalparameter\c!color] % as well as permits local colors to take precedence + {\letnaturaltablelocalparameter\c!color\empty + \setnaturaltablelocalparameter\c!width{\d_tabl_ntb_width}% + \ifdim\d_tabl_ntb_height=\zeropoint\relax % case: nc=maxcolumns + \else + \setnaturaltablelocalparameter\c!height{\d_tabl_ntb_height}% + \fi + \ifcase\c_anch_backgrounds_text_count\else + \edef\p_region{\naturaltablelocalparameter\c!region}% + \ifx\p_region\empty\ifnum\tabl_ntb_get_bck{#1}{#2}>\zerocount + \letnaturaltablelocalparameter\c!region\v!yes + \fi\fi + \fi + \inheritednaturaltablelocalframed{\tabl_ntb_cell_start\tabl_ntb_char_align{#1}{#2}#4\tabl_ntb_cell_stop}}% + \hskip\tabl_ntb_get_dis{#2}} + +\newtoks\everyresetTABLEyes +\newtoks\everyresetTABLEnop + +\appendtoks + \setupTABLE [% + % + % framed defaults + % + \c!width=\v!fit,% + \c!height=\v!fit,% + \c!lines=,% + \c!offset=.25\exheight,% + \c!empty=\v!no,% + \c!frame=\v!on,% + \c!topframe=,% + \c!bottomframe=,% + \c!leftframe=,% + \c!rightframe=,% + \c!radius=.5\bodyfontsize,% + \c!rulethickness=\linewidth,% + \c!corner=\v!rectangular,% + \c!depth=\zeropoint,% + \c!foregroundcolor=,% + \c!foregroundstyle=,% + \c!background=,% + \c!backgroundcolor=,% + \c!backgroundoffset=\v!frame,% + \c!framecolor=,% + \c!frameoffset=.5\linewidth,% + % \c!backgroundcorner=\framedparameter\c!corner,% + % \c!backgrounddepth=\framedparameter\c!depth,% + % \c!backgroundradius=\framedparameter\c!radius,% + % \c!framecorner=\framedparameter\c!corner,% + % \c!framedepth=\framedparameter\c!depth,% + % \c!frameradius=\framedparameter\c!radius,% + \c!component=,% + \c!region=,% + \c!align=,% + \c!bottom=\vss,% + \c!top=,% + \c!strut=\v!yes,% + \c!autostrut=\v!no,% + \c!location=\v!normal,% + \c!orientation=,% + \c!autowidth=\v!yes,% + \c!setups=,% + \c!loffset=\zeropoint,% + \c!roffset=\zeropoint,% + \c!toffset=\zeropoint,% + \c!boffset=\zeropoint,% + % + % table specific + % + \c!aligncharacter=\v!no,% + \c!alignmentcharacter={,},% + \c!color=,% + \c!columndistance=\zeropoint,% each column (whole table) + \c!distance=\zeropoint,% individual column + \c!headcolor=,% + \c!header=,% + \c!headstyle=\v!bold,% + \c!left=,% + \c!leftmargindistance=\zeropoint,% whole table + \c!maxwidth=8\emwidth,% + \c!option=,% \v!stretch + \c!right=,% + \c!rightmargindistance=\zeropoint,% whole table + \c!spaceinbetween=,% + \c!split=\v!auto,% + \c!splitoffset=\zeropoint,% + \c!style=,% + \c!textwidth=\v!local,% was \hsize + ]% +\to \everyresetTABLEyes + +\appendtoks + \setupTABLE [% + \c!width=\v!fit,% + \c!height=\v!fit% + ]% +\to \everyresetTABLEnop + +\the\everyresetTABLEyes + +% \bgroup +% \setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}] +% \bTABLE +% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR +% \bTR \bTD 11,2 \eTD \bTD +% {\setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}] +% \bTABLE +% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR +% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR +% \bTR \bTD 11,2 \eTD \bTD 2 \eTD \eTR \eTABLE} \eTD \eTR +% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR +% \eTABLE +% \egroup + +\newconditional\resetTABLEmode \settrue\resetTABLEmode + +\def\tabl_ntb_parameters_reset % we can use setters instead + {\ifnum\m_tabl_tbl_level>\plusone % in ieder geval + \ifconditional\resetTABLEmode + \the\everyresetTABLEyes + \else + \the\everyresetTABLEnop + \fi + \fi} + +% new (for Olivier Turlier) +% +% \defineTABLEsetup [xx] [foregroundcolor=red] +% +% \bTABLE +% \bTR \bTD oeps \eTD \bTD oeps \eTD \eTR +% \bTR \bTDs[xx] oeps \eTDs \bTD oeps \eTD \eTR +% \bTRs[xx] \bTD oeps \eTD \bTD oeps \eTD \eTRs +% \eTABLE + +\installcorenamespace{naturaltablesetup} + +\unexpanded\def\defineTABLEsetup + {\dodoubleargument\tabl_ntb_define_setup} + +\def\tabl_ntb_define_setup[#1][#2]% + {\setvalue{\??naturaltablesetup#1}{#2}} + +\let\eTDs\relax +\let\eTRs\relax + +\unexpanded\def\bTDs[#1]#2\eTDs + {\normalexpanded{\bTD[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTD} + +\unexpanded\def\bTRs[#1]#2\eTRs + {\normalexpanded{\bTR[\begincsname\??naturaltablesetup#1\endcsname]}#2\eTR} + +\protect \endinput + +% todo: mode: first|next (of niets) diff --git a/tex/context/base/mkiv/tabl-tbl.mkxl b/tex/context/base/mkiv/tabl-tbl.mkxl new file mode 100644 index 000000000..dc8ae0214 --- /dev/null +++ b/tex/context/base/mkiv/tabl-tbl.mkxl @@ -0,0 +1,3022 @@ +%D \module +%D [ file=core-tbl, +%D version=1998.11.03, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Text Flow Tabulation, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Table Macros / Tabulation} + +\unprotect + +\registerctxluafile{tabl-tbl}{} % experiment + +%D I can probably reimplement this using a \LUATEX\ combination but it does not pay +%D of in development time. If I need something else I will write it from scratch +%D anyway. This module looks a bit complex which is a consequence of it dealing with +%D paragraphs being split over pages and that there are several passes over the data +%D set. We can probably do some cleanup (combine/split). +%D +%D Caching the preamble does not save much (compared to other bits and pieces of +%D \CONTEXT). There are not that many ways to deal with preambles and this is just +%D one of them. The keys are somewhat similar to those of the \TABLE\ package. + +% |p2|p3| 2:3 -> spanning (maybe) +% +% In-text tabbing environment +% +% \starttabulate[| separated template] % eg [|l|p|] or [|l|p|p|] +% \NC ... \NC ... \NC\NR +% \stoptabulate +% +% with: two pass auto width calculation when no p-width +% specified, even with multiple p's, see examples. +% +% TaBlE compatible specifications: +% +% l align column/paragraph left +% r align column/paragraph right +% c align column/paragraph center +% p p(dimen) of automatisch als alleen p +% w column width +% f font#1 +% A {alignmentoptions} +% B bold +% I italic +% S slanted +% T type +% R roman +% m math +% M display math +% h hook (inner level or par lines) +% b before (may be command#1) +% a after +% i i skip left of column +% j i skip right of column +% k i skip around column +% d digits (~) +% +% C [LMRT] {color} % T is text color +% +% | {color,n} +% +% s setups +% +% g g{char} align at char +% . align at . +% , align at , +% +% Still to be done +% +% N math numbers (best hook into existing digits mechanism) +% n numbers (best hook into existing digits mechanism) +% Q math numbers (best hook into existing digits mechanism) +% q numbers (best hook into existing digits mechanism) +% ~ \hskip.5em +% | check +% +% nesting +% +% 10 evt auto stack; dan wel andere signal dan void nodig +% +% present but not yet 100% ok +% +% \TL [width,color] bottom hrule +% \FL [width,color] first hrule +% \ML [width,color] mid hrule (with auto split) +% \LL [width,color] bottom hrule +% \BL [width,color] last hrule +% +% \HL [width,color] top rule +% \VL [width,color] +% +% \CC \CL \CM \CR color +% +% \EQ \RQ \HQ equal (raw, hook) +% \NC \RC \HC normal (raw, hook) +% +% \NR checked break +% \NB no break +% +% \HR : rule with lineheight +% +% \autotabulaterule : with lineheight, not first/last +% \autotabulateline : spaced, not first/last +% \tabulaterule : with lineheight +% \tabulateline : spaced +% +% tricky: align scans ahead, over # and expands ones before +% while doing +% +% new: +% +% \starttabulate[|cg{.}|cg{,}|cg{,}|] +% \NC period \NC comma \NC comma \NC\NR +% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR +% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR +% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR +% \NG 10 \NG 10 \NG 0,00 \NC\NR +% \stoptabulate +% +% \starttabulate[|c.|c,|c,|] +% \NC period \NC comma \NC comma \NC\NR +% \NG 100.000,00 \NG 100.000,00 \NG 100,00 \NC\NR +% \NG 10.000,00 \NG 10.000,00 \NG 1000,00 \NC\NR +% \NG 100,00 \NG 100,00 \NG 10,00 \NC\NR +% \NG 10 \NG 10 \NG 0,00 \NC\NR +% \stoptabulate + +% nice demo (for BG) +% +% \starttabulate[|r|b{$\star$}|ra{\percent}|b{=}|r|] +% \NC 500 \NC \NC 60 \NC \NC 300 \NC \NR +% \NC 500 \NC \NC 55 \NC \NC 275 \NC \NR +% \NC 500 \NC \NC 50 \NC \NC 250 \NC \NR +% \NC 500 \NC \NC 45 \NC \NC 225 \NC \NR +% \NC 500 \NC \NC 40 \NC \NC 200 \NC \NR +% \NC 500 \NC \NC 35 \NC \NC 175 \NC \NR +% \NC 500 \NC \NC 30 \NC \NC 150 \NC \NR +% \NC 500 \NC \NC 25 \NC \NC 125 \NC \NR +% \NC 500 \NC \NC 20 \NC \NC 100 \NC \NR +% \stoptabulate + +\newtoks \t_tabl_tabulate_preamble +\newtoks \t_tabl_tabulate_before +\newtoks \t_tabl_tabulate_after +\newtoks \t_tabl_tabulate_bmath +\newtoks \t_tabl_tabulate_emath +\newtoks \t_tabl_tabulate_font +\newtoks \t_tabl_tabulate_settings +\newtoks \t_tabl_tabulate_dummy +\newtoks \t_tabl_tabulate_every_row +\newtoks \t_tabl_tabulate_every_after_row +\newtoks \t_tabl_tabulate_every_real_row + +\newtoks \t_tabl_tabulate_initializers_first +\newtoks \t_tabl_tabulate_initializers_second + +\newcount \c_tabl_tabulate_nofauto +\newcount \c_tabl_tabulate_columns +\newcount \c_tabl_tabulate_column +\newcount \c_tabl_tabulate_plines_min +\newcount \c_tabl_tabulate_plines_max +\newcount \c_tabl_tabulate_max_colorcolumn +\newcount \c_tabl_tabulate_max_vrulecolumn +\newcount \c_tabl_tabulate_repeathead +\newcount \c_tabl_tabulate_noflines +\newcount \c_tabl_tabulate_totalnoflines +\newcount \c_tabl_tabulate_minusnoflines +\newcount \c_tabl_tabulate_align +\newcount \c_tabl_tabulate_nofrealrows +\newcount \c_tabl_tabulate_autocolor + +\newcount \c_tabl_tabulate_nofcolumns % set at the lua end by parser +\newcount \c_tabl_tabulate_has_rule_spec_first % set at the lua end by parser (for the moment a count) +\newcount \c_tabl_tabulate_has_rule_spec_last % set at the lua end by parser (for the moment a count) + +\newconditional \c_tabl_tabulate_nopbreak +\newconditional \c_tabl_tabulate_firstflushed +\newconditional \c_tabl_tabulate_equal +\newconditional \c_tabl_tabulate_split \settrue\c_tabl_tabulate_split +\newconditional \c_tabl_tabulate_automode +\newconditional \c_tabl_tabulate_handlepbreak \settrue\c_tabl_tabulate_handlepbreak +\newconditional \c_tabl_tabulate_autorulespacing \settrue\c_tabl_tabulate_autorulespacing +\newconditional \c_tabl_tabulate_someamble +\newconditional \c_tabl_tabulate_tolerant_break +\newconditional \c_tabl_tabulate_splitoff_whitespace +\newconditional \c_tabl_tabulate_pwidth_set +\newconditional \c_tabl_tabulate_reshape + +\newdimen \d_tabl_tabulate_width_p +\newdimen \d_tabl_tabulate_width_w +\newdimen \d_tabl_tabulate_width +\newdimen \d_tabl_tabulate_unit +\newdimen \d_tabl_tabulate_height_p_max +\newdimen \d_tabl_tabulate_vrulethickness_default +\newdimen \d_tabl_tabulate_hrulethickness_default +\newdimen \d_tabl_tabulate_vrulethickness +\newdimen \d_tabl_tabulate_hrulethickness % not used +\newdimen \d_tabl_tabulate_vrulethickness_local +\newdimen \d_tabl_tabulate_hrulethickness_local +\newdimen \d_tabl_tabulate_indent +\newdimen \d_tabl_tabulate_splitoff_betweenskip +\newdimen \d_tabl_tabulate_margin + +\newskip \s_tabl_tabulate_pre +\newskip \s_tabl_tabulate_post +\newskip \s_tabl_tabulate_first +\newskip \s_tabl_tabulate_last +\newskip \s_tabl_tabulate_separator + +\newbox \b_tabl_tabulate + +\newconstant \c_tabl_tabulate_pass +\newconstant \c_tabl_tabulate_type +\newconstant \c_tabl_tabulate_kind % 1=strong 2=equals +\newconstant \c_tabl_tabulate_splitlinemode \c_tabl_tabulate_splitlinemode\plusone +\newconstant \c_tabl_tabulate_colorspan +\newconstant \c_tabl_tabulate_localcolorspan +\newconstant \c_tabl_tabulate_modus + +\let\tabulatesplitlinemode\c_tabl_tabulate_splitlinemode % temp hack, we need an interface + +\let \m_tabl_tabulate_separator_factor \empty % fraction + +\newtoks \everytabulatepar % where used ? +\newtoks \everytabulate % public ? + +\unexpanded\def\tolerantTABLEbreaktrue {\settrue \c_tabl_tabulate_tolerant_break} % used in styles ! +\unexpanded\def\handletabulatepbreakfalse{\setfalse\c_tabl_tabulate_handlepbreak } % depricated + +\def\noftabulaterows{\number\c_tabl_tabulate_noflines} % handy for testing if a table is empty + +\installcorenamespace{tabulatebox} +\installcorenamespace{tabulatesetup} +\installcorenamespace{tabulatehook} +\installcorenamespace{tabulatesplit} +\installcorenamespace{tabulateseparator} +\installcorenamespace{tabulatecolor} +\installcorenamespace{tabulateheader} +\installcorenamespace{tabulatealigning} +\installcorenamespace{tabulatepreamble} +\installcorenamespace{tabulatevrule} + +\installcorenamespace{tabulatehead} +\installcorenamespace{tabulatefoot} +\installcorenamespace{tabulatenext} + +\prependtoks + \global\c_tabl_tabulate_nofrealrows\zerocount +\to \t_tabl_tabulate_initializers_first + +\prependtoks + \global\c_tabl_tabulate_nofrealrows\zerocount +\to \t_tabl_tabulate_initializers_second + +\prependtoks + \global\advance\c_tabl_tabulate_nofrealrows\plusone +\to \t_tabl_tabulate_every_real_row + +\def\b_tabl_tabulate_current#1% + {\csname\??tabulatebox\number#1\endcsname} % beware, a synonym + +\def\tabl_tabulate_initialize_boxes#1% + {\scratchcounter#1\relax + \tabl_tabulate_initialize_boxes_step} + +\def\tabl_tabulate_initialize_boxes_step + {\ifnum\scratchcounter>\zerocount + \tabl_tabulate_initialize_box\scratchcounter + \advance\scratchcounter\minusone + \expandafter\tabl_tabulate_initialize_boxes_step + \fi} + +\def\tabl_tabulate_initialize_box#1% also used elsewhere + {\ifcsname\??tabulatebox\number#1\endcsname + \tabl_tabulate_initialize_box_yes + \else + \tabl_tabulate_initialize_box_nop#1% + \fi} + +\def\tabl_tabulate_initialize_box_yes {\global \setbox\lastnamedcs\emptybox} +\def\tabl_tabulate_initialize_box_nop#1{\expandafter\newbox\csname\??tabulatebox\number#1\endcsname} + +\tabl_tabulate_initialize_boxes{16} % not really needed + +\let\initializetablebox \tabl_tabulate_initialize_box % used elsewhere, will change +\let\initializetableboxes\tabl_tabulate_initialize_boxes % used elsewhere, will change +\let\tablebox \b_tabl_tabulate_current + +% 0 = NC column next EQ equal column +% 1 = RC column raw RQ equal column raw +% 2 = HC column hook HQ equal column hook + +% handy helper + +\def\tabulatenoalign % public ? + {\noalign + \bgroup + \let\noalign\relax + \let\tabulatenoalign\relax + \let\next=} + +\def\starttabulatenoalign % public ? + {\tabulatenoalign\bgroup} + +\let\stoptabulatenoalign\egroup + +% [|lg{.}|] => \NG 12.34 \NC + +\def\tabl_tabulate_nobreak_inject_tracer + {\red % maybe use the fast color switcher here + \hrule\s!height.5\linewidth\s!depth.5\linewidth + \par + \kern-\linewidth + \tabl_tabulate_break_no} + +\installtextracker + {tables.tabulate.breaks} + {\let\tabl_tabulate_break_no_tracer\tabl_tabulate_nobreak_inject_tracer} + {\let\tabl_tabulate_break_no_tracer\donothing} + +\let\tabl_tabulate_break_no_tracer\donothing + +\def\tabl_tabulate_nobreak_inject_indeed + {\tabl_tabulate_break_no + \tabl_tabulate_break_no_tracer} + +\def\tabl_tabulate_nobreak_inject + {\tabulatenoalign{\tabl_tabulate_nobreak_inject_indeed}} + +\unexpanded\def\tabl_tabulate_hook_check + {\ifnum\c_tabl_tabulate_type<\plustwo + \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop + \else + \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes + \fi} + +\unexpanded\def\tabl_tabulate_setups_check + {\begincsname\??tabulatesetup\the\c_tabl_tabulate_column\endcsname} + +\unexpanded\def\tabl_tabulate_entry_before{\ignorespaces\tabl_tabulate_hook} +\unexpanded\def\tabl_tabulate_entry_after {\unskip\unskip\ifmmode\else\endgraf\fi} + +\unexpanded\def\tabl_tabulate_shaped_par_begin + {\dowithnextboxcs\tabl_tabulate_shaped_par_finish\vbox\bgroup} + +\def\tabl_tabulate_shaped_par_finish + {\clf_doreshapeframedbox\nextbox\relax + \ifvmode\unvbox\else\box\fi\nextbox} + +\let\tabl_tabulate_shaped_par_end\egroup + +\ifdefined\dotagtabulatecell \else \let\dotagtabulatecell \relax \fi +\ifdefined\dotagtabulatesignal \else \let\dotagtabulatesignal\relax \fi + +\unexpanded\def\tabl_tabulate_check_local_color_first#1#2% + {\relax} + +\unexpanded\def\tabl_tabulate_check_local_color_second#1#2% + {\relax + \ifx\m_tabl_tabulate_color_local\empty + \xdef\m_tabl_tabulate_color{#1}% + \else + \glet\m_tabl_tabulate_color\m_tabl_tabulate_color_local + \glet\m_tabl_tabulate_color_local\empty + \fi + \ifcase\c_tabl_tabulate_localcolorspan + \global\c_tabl_tabulate_colorspan#2\relax + \else + \global\c_tabl_tabulate_colorspan\c_tabl_tabulate_localcolorspan + \global\c_tabl_tabulate_localcolorspan\zerocount + \fi} + +\unexpanded\def\tabl_tabulate_check_local_vrule_thickness#1% + {\relax + \ifcase\d_tabl_tabulate_vrulethickness_local + \global\d_tabl_tabulate_vrulethickness#1\relax + \else + \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_local + \global\d_tabl_tabulate_vrulethickness_local\zeropoint + \fi} + +\unexpanded\def\tabl_tabulate_check_local_vrule_color_first#1% + {\relax} + +\unexpanded\def\tabl_tabulate_check_local_vrule_color_second#1% + {\relax + \ifx\m_tabl_tabulate_vrule_color_local\empty + \xdef\m_tabl_tabulate_vrule_color{#1}% + \else + \glet\m_tabl_tabulate_vrule_color\m_tabl_tabulate_vrule_color_local + \glet\m_tabl_tabulate_vrule_color_local\empty + \fi} + +\let\tabl_tabulate_check_local_color \gobbletwoarguments +\let\tabl_tabulate_check_local_vrule_color\gobbleoneargument + +\appendtoks + \let\tabl_tabulate_check_local_color \tabl_tabulate_check_local_color_first + \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_first +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\tabl_tabulate_check_local_color \tabl_tabulate_check_local_color_second + \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_second +\to \t_tabl_tabulate_initializers_second + +% \unexpanded % we can expand this one +\def\tabl_tabulate_inject_pre_skip#1% + {\ifdim#1>\zeropoint + \kern#1\relax % was \hskip + \orelse\ifnum\c_tabl_tabulate_column=\zerocount + \ifconditional\c_tabl_tabulate_autorulespacing + \ifcase\c_tabl_tabulate_has_rule_spec_first\else + \kern\s_tabl_tabulate_first\relax % was \hskip + \fi + \fi + \fi} + +% \unexpanded % we can expand this one +\def\tabl_tabulate_inject_post_skip#1% + {\ifdim#1>\zeropoint + \kern#1\relax % was \hskip + \orelse\ifnum\c_tabl_tabulate_columns=\c_tabl_tabulate_nofcolumns + \ifconditional\c_tabl_tabulate_autorulespacing + \ifcase\c_tabl_tabulate_has_rule_spec_last\else + \kern\s_tabl_tabulate_last\relax % was \hskip + \fi + \fi + \fi} + +\let\tabl_tabulate_hook_b\donothing +\let\tabl_tabulate_hook_e\donothing + +\let\tabl_tabulate_hook_g\donothing + +\def\tabl_tabulate_set_preamble_step#1#2% only makes sense for many tabulates + {\etoksapp\t_tabl_tabulate_preamble{% + \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness + \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color + \tabl_tabulate_check_local_color\constantemptyargument\m_tabl_tabulate_color\constantnumberargument\c_tabl_tabulate_colorspan + \tabl_tabulate_color_side_right + \aligntab + \tabl_tabulate_column_vrule_inject + \tabl_tabulate_color_side_left + \tabl_tabulate_inject_pre_skip{\the\dimexpr\s_tabl_tabulate_pre}% get rid of plus + \alignmark\alignmark + \aligntab + \tabl_tabulate_color_side_both + \global\c_tabl_tabulate_colorspan\zerocount + \global\c_tabl_tabulate_column\constantnumber\c_tabl_tabulate_columns + \tabl_tabulate_hook_g + \tabl_tabulate_setups_check % unexpandable + \tabl_tabulate_hook_check % unexpandable + \ifzeropt\d_tabl_tabulate_width + \ifcase\c_tabl_tabulate_modus\else + \settrue\c_tabl_tabulate_automode + \fi + \else + \ifcase\c_tabl_tabulate_modus + \hbox to + \else + \hsize + \fi + \the\d_tabl_tabulate_width + \fi + \bgroup + \tabl_tabulate_bbskip + \bgroup % we cannot combine the if because a cell may have only one ## + \tabl_tabulate_hook_b + \c_tabl_tabulate_align\constantnumber\c_tabl_tabulate_align % needed in tag passing + \ifx\m_tabl_tabulate_alignment\empty \else + \spac_align_use_now{\m_tabl_tabulate_alignment}% + \fi + \noexpand\dostarttagged\noexpand\t!tabulatecell\noexpand\empty + \noexpand\dotagtabulatecell + \noexpand#1% + \ifconditional\c_tabl_tabulate_reshape + \tabl_tabulate_shaped_par_begin + \fi + \dotagtabulatesignal % empty cells .. todo (can be removed as soon as build) + \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else + \the\t_tabl_tabulate_bmath % maybe later? can interfere with char 0 + \the\t_tabl_tabulate_font + \the\t_tabl_tabulate_settings + \the\t_tabl_tabulate_before + \ifx\m_tabl_tabulate_text_color\empty + \expandafter\gobbleoneargument + \else + \expandafter\dofastcoloractivation + \fi\m_tabl_tabulate_text_color + \noexpand\fi + % grouping needs to be outside macros (or expandable), nice test + % example \NC \string \aligntab \NC which will fail otherwise (mk) + \bgroup + \tabl_tabulate_entry_before + \alignmark\alignmark + \tabl_tabulate_entry_after + \egroup + \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else + \the\t_tabl_tabulate_after + \the\t_tabl_tabulate_emath + \noexpand\fi + \ifconditional\c_tabl_tabulate_reshape + \tabl_tabulate_shaped_par_end + \fi + \noexpand#2% + \tabl_tabulate_hook_e + \egroup + \egroup + \aligntab + \noexpand\dostoptagged + \tabl_tabulate_inject_post_skip{\the\dimexpr\s_tabl_tabulate_post}% get rid of plus + \alignmark\alignmark + }% + \toksapp\t_tabl_tabulate_dummy{\NC}% + \s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\relax + \ifnum\c_tabl_tabulate_columns<\numexpr\c_tabl_tabulate_nofcolumns-\plusone\relax + \s_tabl_tabulate_post\s_tabl_tabulate_pre + \else + \s_tabl_tabulate_post\zeropoint + \fi + %\let\gettabulateexit\dogettabulateexit % still needed ? + \d_tabl_tabulate_width\zeropoint} + +\unexpanded\def\installtabulatepreambleoption#1#2% + {\setvalue{\??tabulatepreamble\string#1}{#2}}% + +\installtabulatepreambleoption{x}{\c_tabl_tabulate_align\zerocount + \tabl_tabulate_set_preamble} % internal +\installtabulatepreambleoption{l}{\c_tabl_tabulate_align\plusone + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{r}{\c_tabl_tabulate_align\plustwo + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{c}{\c_tabl_tabulate_align\plusthree + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{p}{\tabl_tabulate_set_paragraph} +\installtabulatepreambleoption{s}{\tabl_tabulate_set_setups} +\installtabulatepreambleoption{w}{\tabl_tabulate_set_width} +\installtabulatepreambleoption{f}{\tabl_tabulate_set_font} +\installtabulatepreambleoption{B}{\t_tabl_tabulate_font{\bf}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{I}{\t_tabl_tabulate_font{\it}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{S}{\t_tabl_tabulate_font{\sl}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{T}{\t_tabl_tabulate_font{\tt}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{R}{\t_tabl_tabulate_font{\rm}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{m}{\t_tabl_tabulate_bmath{\normalstartimath}% + \t_tabl_tabulate_emath{\normalstopimath}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{M}{\t_tabl_tabulate_bmath{\normalstartimath\displaystyle}% + \t_tabl_tabulate_emath{\normalstopimath}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{h}{\tabl_tabulate_set_hook} +\installtabulatepreambleoption{b}{\tabl_tabulate_set_before} +\installtabulatepreambleoption{a}{\tabl_tabulate_set_after} +\installtabulatepreambleoption{i}{\tabl_tabulate_set_preskip} +\installtabulatepreambleoption{j}{\tabl_tabulate_set_posskip} +\installtabulatepreambleoption{k}{\tabl_tabulate_set_preposskip} +\installtabulatepreambleoption{e}{\toksapp\t_tabl_tabulate_settings{\global\settrue\c_tabl_tabulate_equal}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{g}{\tabl_tabulate_set_align} +\installtabulatepreambleoption{.}{\tabl_tabulate_set_align.} +\installtabulatepreambleoption{,}{\tabl_tabulate_set_align,} +\installtabulatepreambleoption{C}{\tabl_tabulate_set_color_span} +\installtabulatepreambleoption{d}{\toksapp\t_tabl_tabulate_settings{\fixedspaces}% + \tabl_tabulate_set_preamble} +\installtabulatepreambleoption{ }{\tabl_tabulate_set_preamble} +\installtabulatepreambleoption{A}{\tabl_tabulate_set_alignment} + +%D We no longer deal with \type {~} here but map it onto \type {d} instead. Of +%D course we could prefix a key with \type {\meaning} instead, which works ok (and +%D is needed in order to pseudo expand \type {\next}, but is ugly at the same time. +%D The type {d} stands for digitspace. + +%D \starttyping +%D \installtabulatepreambleoption{~}{...} % see 'd' +%D \stoptyping +%D +%D Also, as there is always a key, we no longer do some after assigment or future +%D let but just pick up the key. + +% \installtabulatepreambleoption \s!unknown % +% {\writestatus{tabulate}{unknown preamble key [\normalmeaning\next]}% +% \tabl_tabulate_set_preamble} +% +% \def\tabl_tabulate_set_preamble +% {\afterassignment\dosettabulatepreamble\let\next=} +% +% \def\dosettabulatepreamble +% {\ifx\next\relax \else +% \csname\??tabulatepreamble +% \ifcsname\??tabulatepreamble\next\endcsname\next\else\s!unknown\fi +% \expandafter\endcsname +% \fi} + +\installtabulatepreambleoption\relax + {} % finished + +\def\tabl_tabulate_set_preamble#1% + {\ifcsname\??tabulatepreamble\string#1\endcsname + %\expandafter\tabl_tabulate_set_preamble_yes + \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument + \else + \expandafter\tabl_tabulate_set_preamble_nop + \fi{#1}} + +\def\tabl_tabulate_set_preamble_yes#1% + {\csname\??tabulatepreamble\string#1\expandafter\endcsname} + +\def\tabl_tabulate_set_preamble_nop#1% + {\writestatus{tabulate}{unknown preamble key: #1}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_preskip#1% + {\doifelsenumber{#1}% + {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }% + {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}} + +\def\tabl_tabulate_set_posskip#1% + {\doifelsenumber{#1}% + {\s_tabl_tabulate_post#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble }% + {\s_tabl_tabulate_post.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}} + +\def\tabl_tabulate_set_preposskip#1% + {\doifelsenumber{#1}% + {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble }% + {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble#1}} + +\def\tabl_tabulate_set_setups#1% + {\setvalue{\??tabulatesetup\the\c_tabl_tabulate_columns}{\setups[#1]}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_hook#1% + {\setvalue{\??tabulatehook\the\c_tabl_tabulate_columns}{#1}% + \tabl_tabulate_set_preamble} + +% begin of character align plugin + +\newconditional\c_tabl_auto_align_mode % reset later + +\def\tabl_tabulate_hook_g % partly expanded + {\ifconditional\c_tabl_auto_align_mode + \signalcharacteralign\c_tabl_tabulate_column{\c_tabl_tabulate_noflines+\plusone}% + \typo_charalign_adapt_font + \fi} + +\def\tabl_tabulate_set_align#1% + {\global\settrue\c_tabl_auto_align_mode + \setcharacteralign\c_tabl_tabulate_columns{#1}% + \tabl_tabulate_set_preamble} + +% end of character align plugin + +\def\tabl_tabulate_set_before#1% + {\t_tabl_tabulate_before{#1}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_after#1% + {\t_tabl_tabulate_after{#1}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_font#1% + {\t_tabl_tabulate_font{#1}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_pickup_width + {\doifelsenextparenthesis\tabl_tabulate_set_width_indeed\tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_width + {\setfalse\c_tabl_tabulate_pwidth_set + \c_tabl_tabulate_modus\zerocount + \tabl_tabulate_pickup_width} + +\def\tabl_tabulate_set_alignment#1% + {\edef\m_tabl_tabulate_alignment{#1}% + \spac_align_use_later\m_tabl_tabulate_alignment + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_paragraph + {\doifelsenextparenthesis + {\c_tabl_tabulate_modus\plusone + \settrue\c_tabl_tabulate_pwidth_set + \tabl_tabulate_pickup_width} + {\c_tabl_tabulate_modus\plustwo + \setfalse\c_tabl_tabulate_pwidth_set + \tabl_tabulate_set_preamble}} + +% \startbuffer +% \toplinebox{\framed[width=3cm,height=2cm]{tufte}} +% \stopbuffer +% \starttabulate[|p(fixed)|p|] +% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} +% \stoptabulate +% \starttabulate[|p(fit)|p|] +% \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR} +% \stoptabulate + +\def\tabl_tabulate_set_width_indeed(#1)% + {\processallactionsinset % can be made faster + [#1]% + [ \v!fit=>\c_tabl_tabulate_modus\plusthree, + \v!fixed=>\c_tabl_tabulate_modus\plusthree + \settrue\c_tabl_tabulate_nopbreak, + \v!auto=>\c_tabl_tabulate_modus\plusthree + \settrue\c_tabl_tabulate_reshape, + \s!unknown=>\d_tabl_tabulate_width#1\relax]% + \ifconditional\c_tabl_tabulate_pwidth_set + \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth + \fi + \tabl_tabulate_set_preamble} + +% faster but seldom used +% +% \installcorenamespace{tabulatewidth} +% +% \setvalue{\??tabulatewidth\v!fit }{\c_tabl_tabulate_modus\plusthree} +% \setvalue{\??tabulatewidth\v!fixed}{\c_tabl_tabulate_modus\plusthree\settrue\c_tabl_tabulate_nopbreak} +% \setvalue{\??tabulatewidth\v!auto }{\c_tabl_tabulate_modus\plusthree\settrue\c_tabl_tabulate_reshape} +% +% \def\tabl_tabulate_set_width_step#1% +% {\ifcsname\??tabulatewidth#1\endcsname +% \lastnamedcs +% \else +% \d_tabl_tabulate_width#1\relax +% \fi} +% +% \def\tabl_tabulate_set_width_indeed(#1)% +% {\rawprocesscommacommand[#1]\tabl_tabulate_set_width_step +% \ifconditional\c_tabl_tabulate_pwidth_set +% \global\advance\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth +% \fi +% \tabl_tabulate_set_preamble} +% +\def\tabl_tabulate_set_raggedright {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedright \fi} +\def\tabl_tabulate_set_raggedcenter{\ifnum\c_tabl_tabulate_type=\plusone \else\raggedcenter\fi} +\def\tabl_tabulate_set_raggedleft {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedleft \fi} +\def\tabl_tabulate_set_notragged {\ifnum\c_tabl_tabulate_type=\plusone \else\notragged \fi} +\def\tabl_tabulate_set_hss {\ifnum\c_tabl_tabulate_type=\plusone \else\hss \fi} % never change this to a fill + +\def\tabl_tabulate_bskip_raggedright {\tabl_tabulate_bskip\tabl_tabulate_set_raggedright } +\def\tabl_tabulate_bskip_raggedleft {\tabl_tabulate_bskip\tabl_tabulate_set_raggedleft } +\def\tabl_tabulate_bskip_raggedcenter{\tabl_tabulate_bskip\tabl_tabulate_set_raggedcenter} + +\def\tabl_tabulate_set_width_normal + {\ifcase\c_tabl_tabulate_align\relax + \tabl_tabulate_set_preamble_step\empty \tabl_tabulate_set_hss \or + \tabl_tabulate_set_preamble_step\empty \tabl_tabulate_set_hss \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\empty \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\tabl_tabulate_set_hss \fi} + +\def\tabl_tabulate_set_width_fixed + {\ifcase\c_tabl_tabulate_align\relax + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi} + +\def\tabl_tabulate_set_width_auto + {\global\advance\c_tabl_tabulate_nofauto\plusone + \ifcase\c_tabl_tabulate_align\relax + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft \tabl_tabulate_eskip \or + \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi} + +\def\tabl_tabulate_set_width_simple + {\tabl_tabulate_set_preamble_step\tabl_tabulate_xbskip\tabl_tabulate_xeskip} + +% \def\tabl_tabulate_set_color_span#1#2% +% {\xdef\m_tabl_tabulate_color{#2}% +% \global\c_tabl_tabulate_colorspan\if#1L\plusone\else\if#1M\plustwo\else\if#1R\plusthree\else\zerocount\fi\fi\fi\relax +% \tabl_tabulate_set_preamble} + +\installcorenamespace{tabulatecolorspec} + +\setvalue{\??tabulatecolorspec C}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\zerocount} +\setvalue{\??tabulatecolorspec L}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plusone } +\setvalue{\??tabulatecolorspec M}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plustwo } +\setvalue{\??tabulatecolorspec R}#1{\xdef\m_tabl_tabulate_color {#1}\global\c_tabl_tabulate_colorspan\plusthree} +\setvalue{\??tabulatecolorspec T}#1{\xdef\m_tabl_tabulate_text_color{#1}} + +\def\tabl_tabulate_set_color_span#1#2% + {\csname\??tabulatecolorspec#1\endcsname{#2}% + \tabl_tabulate_set_preamble} + +\def\tabl_tabulate_set_vrule_command#1% + {\doifelsenumber{#1} + {\global\d_tabl_tabulate_vrulethickness#1\d_tabl_tabulate_vrulethickness_default} + {\xdef\m_tabl_tabulate_vrule_color{#1}}} + +\def\tabl_tabulate_set_entry#1#2% rulespec template + {\c_tabl_tabulate_align\v_tabl_tabulate_align + \c_tabl_tabulate_modus\zerocount + \setfalse\c_tabl_tabulate_pwidth_set + \setfalse\c_tabl_tabulate_reshape + \t_tabl_tabulate_before\emptytoks + \t_tabl_tabulate_after\emptytoks + \t_tabl_tabulate_bmath\emptytoks + \t_tabl_tabulate_emath\emptytoks + \t_tabl_tabulate_font\emptytoks + \t_tabl_tabulate_settings\emptytoks + \glet\m_tabl_tabulate_alignment\empty + \glet\m_tabl_tabulate_color\empty + \glet\m_tabl_tabulate_text_color\empty + \glet\m_tabl_tabulate_vrule_color\empty + \global\c_tabl_tabulate_colorspan\zerocount + \global\setfalse\c_tabl_auto_align_mode + \global\advance\c_tabl_tabulate_columns\plusone + \expandafter\let\csname\??tabulatesetup\the\c_tabl_tabulate_columns\endcsname\donothing % here ? + \edef\currenttabulationtrulespec{#1}% + \ifx\currenttabulationtrulespec\empty + \global\d_tabl_tabulate_vrulethickness\zeropoint + \else + \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default + \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command + \fi + \tabl_tabulate_set_preamble#2\relax\relax % permits i without n + \ifcase\c_tabl_tabulate_modus\relax + \tabl_tabulate_set_width_normal + \or % fixed width + \tabl_tabulate_set_width_fixed + \or % auto width + \tabl_tabulate_set_width_auto + \or % simple + \tabl_tabulate_set_width_simple + \fi} + +\def\tabl_tabulate_set_last_entry#1% rulespec + {\glet\m_tabl_tabulate_color\empty + \glet\m_tabl_tabulate_vrule_color\empty + \edef\currenttabulationtrulespec{#1}% + \ifx\currenttabulationtrulespec\empty + \global\d_tabl_tabulate_vrulethickness\zeropoint + \else + \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default + \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command + \fi + \etoksapp\t_tabl_tabulate_preamble{% + \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness + \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color + \tabl_tabulate_column_vrule_inject}} + +\let\settabulateentry \tabl_tabulate_set_entry % used at the lua end +\let\settabulatelastentry\tabl_tabulate_set_last_entry % used at the lua end + +\def\tabl_tabulate_normalize_splitline + {\ifcase\c_tabl_tabulate_splitlinemode + % nothing + \or + \ht\b_tabl_tabulate\strutht + \dp\b_tabl_tabulate\strutdp + \or + \ifdim\ht\b_tabl_tabulate<\strutht + \ht\b_tabl_tabulate\strutht + \fi + \ifdim\dp\b_tabl_tabulate<\strutdp + \dp\b_tabl_tabulate\strutdp + \fi + \fi} + +\def\tabl_tabulate_whitespace + {\ifdim\d_tabl_tabulate_splitoff_betweenskip>\zeropoint + \vskip\d_tabl_tabulate_splitoff_betweenskip + \global\d_tabl_tabulate_splitoff_betweenskip\zeropoint + \fi} + +\def\tabl_tabulate_check_whitespace + {\setbox\scratchbox\vpack + {\splitdiscards + \unskip + \ifdim\lastskip>\d_tabl_tabulate_splitoff_betweenskip + \global\d_tabl_tabulate_splitoff_betweenskip\lastskip + \fi}} + +\installtexdirective + {tabulate.linenumbers} + {\def\tabl_tabulate_check_linenumbers{\page_postprocessors_linenumbers_deepbox\b_tabl_tabulate}} + {\let\tabl_tabulate_check_linenumbers\relax} + +\let\tabl_tabulate_check_linenumbers\relax + +\def\tabl_tabulate_splitoff_box + {\dontcomplain + \global\setbox\b_tabl_tabulate\vsplit\b_tabl_tabulate_current\c_tabl_tabulate_column to \lineheight % % % global ? % % % + \setbox\b_tabl_tabulate\vbox + {\unvbox\b_tabl_tabulate}% + \ifconditional\c_tabl_tabulate_splitoff_whitespace + \tabl_tabulate_check_whitespace + \fi + \tabl_tabulate_color_repeat % needs to end up in a cell + \setbox\b_tabl_tabulate\hpack to \wd\b_tabl_tabulate + {\hss\tabl_tabulate_hook_yes{\box\b_tabl_tabulate}\hss}% + \tabl_tabulate_normalize_splitline + \tabl_tabulate_check_linenumbers + \box\b_tabl_tabulate} + +\unexpanded\def\tabl_tabulate_hook_nop + {} + +\let\tabl_tabulate_hook\tabl_tabulate_hook_nop + +\def\tabl_tabulate_hook_yes{\begincsname\??tabulatehook\the\c_tabl_tabulate_column\endcsname} + +\def\tabl_tabulate_pheight_reset + {\global\c_tabl_tabulate_plines_min\plusone + \ifdim\d_tabl_tabulate_height_p_max>\zeropoint + \getnoflines\d_tabl_tabulate_height_p_max + \global\c_tabl_tabulate_plines_max\noflines + \else + \global\c_tabl_tabulate_plines_max\zerocount + \fi + \global\d_tabl_tabulate_height_p_max\zeropoint} + +\def\tabl_tabulate_pheight_set + {\scratchdimen\ht\b_tabl_tabulate_current\c_tabl_tabulate_column\relax + \ifdim\scratchdimen>\d_tabl_tabulate_height_p_max + \global\d_tabl_tabulate_height_p_max\scratchdimen + \fi} + +\def\tabl_tabulate_pbreak_inject + {\ifconditional\c_tabl_tabulate_handlepbreak + \ifconditional\c_tabl_tabulate_nopbreak + \tabl_tabulate_nobreak_inject + \orelse\ifnum\c_tabl_tabulate_plines_max>\plusone + \ifnum\c_tabl_tabulate_plines_min=\plusone + \tabl_tabulate_nobreak_inject + \fi + \global\advance\c_tabl_tabulate_plines_min\plusone + \ifnum\c_tabl_tabulate_plines_min=\c_tabl_tabulate_plines_max\relax + \tabl_tabulate_nobreak_inject + \fi + \fi + \fi} + +\def\tabl_tabulate_pbreak_check + {\starttabulatenoalign + \tabl_tabulate_pbreak_inject + \ifconditional\c_tabl_tabulate_splitoff_whitespace + \tabl_tabulate_whitespace + \fi + \stoptabulatenoalign} + +%D \startbuffer +%D \starttabulate[|c|p|p|] +%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR +%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR +%D \NC 2 \NC \thinrules[n=3] \NC \thinrules[n=3] \NC\NR +%D \NC 3 \NC oh yes \NC simply no \NC\NR +%D \NC 4 \NC very true \NC as false as can be \NC\NR +%D \NC 5 \NC \thinrules[n=5] \NC \thinrules[n=5] \NC\NR +%D \NC 6 \NC \thinrules[n=3] \NC \thinrules[n=4] \NC\NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer {\tracetabulatetrue\getbuffer} +%D +%D \startbuffer +%D \starttabulate[|c|p|p|] +%D \NC \bf Alpha \NC \bf Beta \NC \bf Gamma \NC\NR +%D \NC 1 \NC right indeed \NC definitely wrong \NC\NR +%D \NC 2 \NC oh yes \NC simply no \NC\NR +%D \NC 3 \NC very true \NC as false as can be \NC\NR +%D \NC 4 \NC the whole truth \NC but the truth \NC\NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer {\tracetabulatetrue\getbuffer} + +%D Because we want to be compatible we use an indirect way to implement the +%D definers. The next examples demonstrate the difference: +%D +%D \starttyping +%D \definetabulate[test][|l|c|r|] +%D \definetabulate[test][two][|r|c|l|] +%D +%D \definetabulation[more][format={|l|c|r|}] +%D \definetabulation[more:two][format={|r|c|l|}] +%D +%D \starttest +%D \NC t \NC t \NC t \NC \NR +%D \NC te \NC te \NC te \NC \NR +%D \NC tes \NC tes \NC tes \NC \NR +%D \NC test \NC test \NC test \NC \NR +%D \stoptest +%D +%D \starttest[two] +%D \NC t \NC t \NC t \NC \NR +%D \NC te \NC te \NC te \NC \NR +%D \NC tes \NC tes \NC tes \NC \NR +%D \NC test \NC test \NC test \NC \NR +%D \stoptest +%D \startmore +%D \NC t \NC t \NC t \NC \NR +%D \NC te \NC te \NC te \NC \NR +%D \NC tes \NC tes \NC tes \NC \NR +%D \NC test \NC test \NC test \NC \NR +%D \stopmore +%D +%D \startmore[two] +%D \NC t \NC t \NC t \NC \NR +%D \NC te \NC te \NC te \NC \NR +%D \NC tes \NC tes \NC tes \NC \NR +%D \NC test \NC test \NC test \NC \NR +%D \stopmore +%D \stoptyping + +\installcorenamespace {tabulation} + +\installcommandhandler \??tabulation {tabulation} \??tabulation + +\setuptabulation + [\c!unit=1em, + EQ={:}, + \c!format={|l|p|}, + \c!frame=\v!off, + %\c!bodyfont=, + \c!rule=\v!normal, + %\c!rulecolor=, + \c!rulethickness=\linewidth, + %\c!inner=, + \c!before=\blank, + \c!after=\blank, + \c!distance={\v!depth,\v!medium}, + \c!align=\v!normal, + \c!margin=\!!zeropoint, + \c!split=\v!auto, + \c!header=\v!yes, + %\c!title=, + \c!indenting=\v!no] + +\unexpanded\def\definetabulate + {\dotripleempty\tabl_tabulate_define} + +\def\tabl_tabulate_define[#1][#2][#3]% + {\ifthirdargument + % [tag] [sub] [template] + \ifcsname\namedtabulationhash{#1}\s!check\endcsname \else + \definetabulation[#1][\c!format={#3},\s!check=]% + \fi + \definetabulation[#1:#2][#1][\c!format={#3},\s!check=]% + \orelse\ifsecondargument + % [tag] [template] + \definetabulation[#1][\c!format={#2},\s!check=]% + \else + % [tag] + \definetabulation[#1][\c!format={|l|p|},\s!check=]% + \fi} + +\unexpanded\def\setuptabulate + {\dotripleempty\tabl_tabulate_setup} + +\def\tabl_tabulate_setup[#1][#2][#3]% + {\ifthirdargument + % [tag] [sub] [settings] + \setuptabulation[#1:#2][#3]% + \orelse\ifsecondargument + % [tag] [settings] + \setuptabulation[#1][#2]% + \else + % [tag] + \setuptabulation[#1]% + \fi} + +\appendtoks + \setuevalue{\e!start\currenttabulation}{\tabl_start_defined[\currenttabulation]}% + \letvalue{\e!stop\currenttabulation}\relax + \letvalue{\??tabulatehead\currenttabulation}\empty + \letvalue{\??tabulatefoot\currenttabulation}\empty +\to \everydefinetabulation + +\let\tabulateparameter\tabulationparameter % will stay for a while +\def\currenttabulate {\currenttabulation} % will stay for a while + +% Here begins the implementation. + +\let\tabl_tabulate_insert_head\empty +\let\tabl_tabulate_insert_body\empty +\let\tabl_tabulate_insert_foot\empty + +\def\tabl_tabulate_insert_head_content + {\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}% + \begincsname\??tabulatehead\currenttabulation\endcsname + \tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}% + +\def\tabl_tabulate_insert_foot_content + {\tabulatenoalign{\global\settrue\c_tabl_tabulate_someamble}% + \begincsname\??tabulatefoot\currenttabulation\endcsname + \tabulatenoalign{\global\setfalse\c_tabl_tabulate_someamble}}% + +\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header + {\ifcsname\??tabulatehead\currenttabulation\endcsname + %\expandafter\ifx\csname\??tabulatehead\currenttabulation\endcsname\empty + \expandafter\ifx\lastnamedcs\empty + \let\tabl_tabulate_insert_head\empty + \else + \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content + \fi + \else + \let\tabl_tabulate_insert_head\empty + \fi + \ifcsname\??tabulatefoot\currenttabulation\endcsname + \expandafter\ifx\csname\??tabulatefoot\currenttabulation\endcsname\empty + %\expandafter\ifx\lastnamedcs\empty + \let\tabl_tabulate_insert_foot\empty + \else + \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content + \fi + \else + \let\tabl_tabulate_insert_foot\empty + \fi} + +\def\tabl_tabulate_insert_content + {\tabl_tabulate_insert_head + \ifcase\c_tabl_tabulate_repeathead \else + \tabulatenoalign{\penalty\zerocount}% added 7/5/2014 WS mail + \fi + \tabl_tabulate_insert_body + \tabl_tabulate_insert_foot + \tabl_tabulate_remove_funny_line} + +\def\tabl_tabulate_remove_funny_line + {\ifhmode + \strut\crcr + \tabulatenoalign{\kern-\lineheight}% + \fi} + +% todo: make footer synonym to tail + +\setuvalue{\e!start\v!tabulatehead}{\doifelsenextoptionalcs\tabl_tabulate_start_head_yes\tabl_tabulate_start_head_nop} +\setuvalue{\e!start\v!tabulatetail}{\doifelsenextoptionalcs\tabl_tabulate_start_foot_yes\tabl_tabulate_start_foot_nop} + +\let\m_tabl_tabulate_data\empty + +\def\tabl_tabulate_start_head_yes[#1]% + {\processcontent{\e!stop\v!tabulatehead}\m_tabl_tabulate_data{\letvalue{\??tabulatehead#1}\m_tabl_tabulate_data}} + +\def\tabl_tabulate_start_foot_yes[#1]% + {\processcontent{\e!stop\v!tabulatetail}\m_tabl_tabulate_data{\letvalue{\??tabulatefoot#1}\m_tabl_tabulate_data}} + +\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]} +\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]} + +\unexpanded\def\tabl_start_defined[#1]% + {\bgroup + \edef\currenttabulationparent{#1}% + \let\currenttabulation\currenttabulationparent + \edef\p_format{\tabulationparameter\c!format}% + \ifx\p_format\v!none + % this is special case: we need to define the generic english + % \starttabulate in other interfaces as well + \expandafter\dodoubleempty \expandafter\tabl_start_regular + \else + \expandafter\dodoubleargument\expandafter\tabl_start_defined_indeed + \fi} + +\def\tabl_start_defined_indeed + {\iffirstargument + \ifsecondargument + \doubleexpandafter\tabl_start_defined_two + \else + \doubleexpandafter\tabl_start_defined_one + \fi + \else + \singleexpandafter\tabl_start_defined_zero + \fi} + +\def\tabl_start_defined_one[#1][#2]% + {\ifcondition\validassignment{#1}% + \setuptabulation[\currenttabulation][#1]% + \else + \edef\currenttabulation{\currenttabulation:#1}% + \fi + \tabl_tabulate_start_building} + +\def\tabl_start_defined_two[#1][#2]% + {\edef\currenttabulation{\currenttabulation:#1}% + \setuptabulation[\currenttabulation][#2]% + \tabl_tabulate_start_building} + +\def\tabl_start_defined_zero[#1][#2]% + {\tabl_tabulate_start_building} + +% \definetabulate[\v!tabulate][|l|p|] % we need to get rid of this one + +\unexpanded\setuvalue{\e!start\v!tabulate}% + {\bgroup % whole thing + \let\currenttabulationparent\empty + \dodoubleempty\tabl_start_regular} + +\def\tabl_start_regular + {\let\currenttabulation\currenttabulationparent + \ifsecondargument + \expandafter\tabl_start_regular_two + \else + \expandafter\tabl_start_regular_one + \fi} + +\def\tabl_default_format{|l|p|} + +\def\tabl_start_regular_one[#1][#2]% + {\ifcondition\validassignment{#1}% + \lettabulationparameter\c!format\tabl_default_format + \setupcurrenttabulation[#1]% + \else + \def\p_format{#1}% + \ifx\p_format\empty + \def\p_format{|l|p|}% + \fi + \lettabulationparameter\c!format\p_format + \fi + \tabl_tabulate_start_building} + +\def\tabl_start_regular_two[#1][#2]% + {\def\p_format{#1}% + \ifx\p_format\empty + \let\p_format\tabl_default_format + \fi + \lettabulationparameter\c!format\p_format + \setupcurrenttabulation[#2]% + \tabl_tabulate_start_building} + +\letvalue{\e!stop\v!tabulate }\relax +\letvalue{\e!stop\v!tabulatehead}\relax +\letvalue{\e!stop\v!tabulatetail}\relax + +\unexpanded\def\tabl_tabulate_start_ignore + {\em Nested tabulate is not (yet) supported.\relax + \expandafter\gobbleuntil\csname\ifconditional\c_tabl_generic stoptabulate\else\e!stop\v!tabulate\fi\endcsname} + +\appendtoks + \letvalue{\e!start\v!tabulate}\tabl_tabulate_start_ignore % only the main one +\to \everytabulate + +\setvalue{\??tabulatesplit\v!yes }{\settrue\c_tabl_tabulate_split} +\setvalue{\??tabulatesplit\v!repeat}{\settrue\c_tabl_tabulate_split} +\setvalue{\??tabulatesplit\v!no }{\setfalse\c_tabl_tabulate_split} +\setvalue{\??tabulatesplit\v!auto }{\ifinsidefloat\ifinsidesplitfloat\else\setfalse\c_tabl_tabulate_split\fi\fi} + +% todo: spacing around tabulate when bodyfont is set + +% \let\tabl_tabulate_inside_before \relax +% \let\tabl_tabulate_inside_after \relax +% \let\tabl_tabulate_inside_inbetween\relax +% +% \def\tabl_tabulate_outside_before +% {\whitespace +% \tabulationparameter\c!before} +% +% \def\tabl_tabulate_outside_after +% {\tabulationparameter\c!after} + +% \showboxes +% +% \startcombination +% {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {} +% {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {} +% \stopcombination +% +% \startcombination +% {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {} +% {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {} +% \stopcombination +% +% \startcombination +% {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {} +% {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {} +% \stopcombination + +\let\tabl_tabulate_inside_after \relax +\let\tabl_tabulate_outside_after \relax +\let\tabl_tabulate_inside_inbetween \relax +\let\tabl_tabulate_outside_inbetween\relax + +\unexpanded\def\tabl_tabulate_inside_before + {\ifhmode\par\fi + \ifhmode + \ifinsidesplitfloat + \let\tabl_tabulate_inside_after\relax + \else + \vbox\bgroup + \let\tabl_tabulate_inside_after\egroup + \fi + \else + \let\tabl_tabulate_inside_after\relax + \fi} + +\unexpanded\def\tabl_tabulate_outside_before + {\ifhmode\par\fi + \ifhmode + \vbox\bgroup + \let\tabl_tabulate_outside_after \egroup + \let\tabl_tabulate_outside_inbetween\relax + \orelse\ifinner + \let\tabl_tabulate_outside_after \relax + \let\tabl_tabulate_outside_inbetween\relax + \else + \whitespace + \tabulationparameter\c!before + \relax + \let\tabl_tabulate_outside_after \tabl_tabulate_outside_after_indeed + \let\tabl_tabulate_outside_inbetween\tabl_tabulate_outside_inbetween_indeed + \fi} + +\def\tabl_tabulate_outside_after_indeed + {\tabulationparameter\c!after} + +\def\tabl_tabulate_outside_inbetween_indeed + {\doifempty{\tabulationparameter\c!after} + {\vskip\strutdp + \verticalstrut + \vskip-\struttotal}} + +\def\tabl_tabulate_inside_inbetween % needs checking + {\doifempty{\tabulationparameter\c!after} + {\vskip\strutdp + \verticalstrut + \vskip-\struttotal}} + +\unexpanded\def\tabl_tabulate_start_building + {\ifinsidefloat + \tabl_tabulate_inside_before + \else + \tabl_tabulate_outside_before + \fi + \bgroup % settings + % + \t_tabl_tabulate_preamble\emptytoks + \t_tabl_tabulate_dummy \emptytoks + % + \resetcharacteralign + % + \edef\p_distance {\tabulationparameter\c!distance}% + \edef\p_align {\tabulationparameter\c!align}% + \edef\p_line {\tabulationparameter\c!rule}% + \edef\p_rulecolor {\tabulationparameter\c!rulecolor}% + \edef\p_rulethickness{\tabulationparameter\c!rulethickness}% + \edef\p_bodyfont {\tabulationparameter\c!bodyfont} + \edef\p_indenting {\tabulationparameter\c!indenting}% + \edef\p_keeptogether {\tabulationparameter\c!keeptogether}% + \edef\p_blank {\tabulationparameter\c!blank}% + % + \ifx\p_keeptogether\v!no + \settrue \c_tabl_tabulate_tolerant_break + %\setfalse\c_tabl_tabulate_handlepbreak + \else + \setfalse\c_tabl_tabulate_tolerant_break + %\settrue \c_tabl_tabulate_handlepbreak + \fi + % + \settrue\c_tabl_tabulate_split + \begincsname\??tabulatesplit\tabulationparameter\c!split\endcsname + % + \let\m_tabl_tabulate_blank_default\p_blank + % + \d_tabl_tabulate_unit\tabulationparameter\c!unit + \d_tabl_tabulate_margin\tabulationparameter\c!margin + \let\m_tabl_tabulate_vrule_color_default\p_rulecolor + \let\m_tabl_tabulate_hrule_color_default\p_rulecolor + \d_tabl_tabulate_vrulethickness_default\p_rulethickness + \d_tabl_tabulate_hrulethickness_default\p_rulethickness + \ifx\p_bodyfont\empty\else + \switchtobodyfont[\p_bodyfont]% + \fi + \postponenotes % new, to be tested / will be configurable + \widowpenalty\zerocount % otherwise lines are not broken + \clubpenalty \zerocount % but overlap in funny ways + \the\everytabulate + \tabulationparameter\c!inner + \d_tabl_tabulate_indent\dimexpr\leftskip+\hangindent\ifx\p_indenting\v!yes+\parindent\fi\relax + \global\c_tabl_tabulate_column\zerocount + \processcontent + {\ifconditional\c_tabl_generic stoptabulate\else\e!stop\ifx\currenttabulationparent\empty\v!tabulate\else\currenttabulationparent\fi\fi} + \tabl_tabulate_insert_body + \tabl_tabulate_process} + +\def\tabulateEQ + {\ifconditional\c_tabl_tabulate_firstflushed\else + \dostarttaggedchained\t!ignore\empty\empty + \dostarttagged\t!ignore\empty + \tabulationparameter{EQ}% + \dostoptagged + \dostoptagged + \fi + \global\setfalse\c_tabl_tabulate_equal} + +% The next ones will be token registers + +\let\tabulatenormalpos\relax % hooks, todo +\let\tabulateequalpos \relax % hooks, todo + +% color columns + +\let\m_tabl_tabulate_color_previous \empty +\let\m_tabl_tabulate_color \empty +\let\m_tabl_tabulate_text_color \empty +\let\m_tabl_tabulate_color_local \empty +\let\m_tabl_tabulate_vrule_color \empty +\let\m_tabl_tabulate_vrule_color_local \empty +\let\m_tabl_tabulate_vrule_color_default\empty % used local +\let\m_tabl_tabulate_hrule_color_default\empty % used local +\let\m_tabl_tabulate_blank_default \empty + +\appendtoks + \glet\m_tabl_tabulate_color_previous \empty + \glet\m_tabl_tabulate_color \empty + \glet\m_tabl_tabulate_text_color \empty + \glet\m_tabl_tabulate_color_local \empty + \glet\m_tabl_tabulate_vrule_color \empty + \glet\m_tabl_tabulate_vrule_color_local \empty + \global \d_tabl_tabulate_vrulethickness_local\zeropoint +\to \t_tabl_tabulate_every_row + +\unexpanded\def\tabl_tabulate_color_side_right_second + {\ifx\m_tabl_tabulate_color_previous\empty \else + \tabl_tabulate_color_set\m_tabl_tabulate_color_previous + \glet\m_tabl_tabulate_color_previous\empty + \fi} + +\unexpanded\def\tabl_tabulate_color_side_left_second + {\ifx\m_tabl_tabulate_color\empty \else + \ifcase\c_tabl_tabulate_colorspan + \or + \tabl_tabulate_color_set\m_tabl_tabulate_color + \or + \tabl_tabulate_color_set\m_tabl_tabulate_color + \fi + \fi} + +\unexpanded\def\tabl_tabulate_color_side_both_second + {\ifx\m_tabl_tabulate_color\empty \else + \tabl_tabulate_color_set\m_tabl_tabulate_color + \ifcase\c_tabl_tabulate_colorspan + %\glet\m_tabl_tabulate_color_previous\empty + \or + \glet\m_tabl_tabulate_color_previous\empty + \or + \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color + \or + \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color + \fi + \fi} + +\let\tabl_tabulate_color_side_right \relax +\let\tabl_tabulate_color_side_left \relax +\let\tabl_tabulate_color_side_both \relax + +\appendtoks + \let\tabl_tabulate_color_side_right\tabl_tabulate_color_side_right_second + \let\tabl_tabulate_color_side_left \tabl_tabulate_color_side_left_second + \let\tabl_tabulate_color_side_both \tabl_tabulate_color_side_both_second +\to \t_tabl_tabulate_initializers_second + +\def\tabl_tabulate_set_color_column#1% overloaded + {\unskip + \doifelsefastoptionalcheck{\tabl_tabulate_set_color_column_yes#1}{\tabl_tabulate_set_color_column_nop#1}} + +\def\tabl_tabulate_set_color_column_nop + {\tabl_tabulate_column_normal\zerocount} + +\def\tabl_tabulate_set_color_column_yes#1[#2]% + {\xdef\m_tabl_tabulate_color_local{#2}% + \tabl_tabulate_column_normal\zerocount#1} + +% normal columns: + +\def\tabl_tabulate_column_normal#1#2% + {\unskip + \aligntab + \ifconditional\c_tabl_tabulate_equal\tabulateequalpos\else\tabulatenormalpos\fi + \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn\else + \tabl_tabulate_column_vrule_setup + \fi + \aligntab + \global\c_tabl_tabulate_kind#1% + \global\c_tabl_tabulate_type#2% + \aligntab} + +% equal columns + +\def\tabl_tabulate_column_equal#1#2% + {\unskip + \aligntab + \tabulateequalpos + \aligntab + \global\c_tabl_tabulate_kind#1% + \global\c_tabl_tabulate_type#2% + \aligntab} + +% ruled columns + +\def\tabl_tabulate_column_vruled_preset + {\glet\m_tabl_tabulate_vrule_color_local\m_tabl_tabulate_vrule_color_default + \global\d_tabl_tabulate_vrulethickness_local\d_tabl_tabulate_vrulethickness_default} + +\def\tabl_tabulate_column_vruled#1#2% + {\unskip % 0-n + %\ifnum\c_tabl_tabulate_column=\plusone + % \global\c_tabl_tabulate_has_rule_spec_first\plusone + %\orelse\ifnum\c_tabl_tabulate_column=\c_tabl_tabulate_nofcolumns + % \global\c_tabl_tabulate_has_rule_spec_last\plusone + %\fi + \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn + \global\c_tabl_tabulate_max_vrulecolumn\c_tabl_tabulate_column + \fi + \doifelsefastoptionalcheck{\tabl_tabulate_column_vruled_yes#1#2}{\tabl_tabulate_column_vruled_nop#1#2}} + +\def\tabl_tabulate_column_vrule_setup + {\begincsname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname} + +\def\tabl_tabulate_column_vruled_nop + {\expandafter\glet\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname\tabl_tabulate_column_vruled_preset + \tabl_tabulate_column_normal} + +\def\tabl_tabulate_column_vruled_step#1% + {\doifelsenumber{#1} + {\global\d_tabl_tabulate_vrulethickness_local#1\d_tabl_tabulate_vrulethickness_default} + {\xdef\m_tabl_tabulate_vrule_color_local{#1}}} + +\def\tabl_tabulate_column_vruled_yes#1#2[#3]% + {\expandafter\gdef\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname + {\tabl_tabulate_column_vruled_preset + \rawprocesscommalist[#3]\tabl_tabulate_column_vruled_step}% + \tabl_tabulate_column_normal#1#2} + +\def\tabl_tabulate_vrule_reset + {\ifcase\c_tabl_tabulate_max_vrulecolumn\else + \tabl_tabulate_vrule_reset_indeed + \fi} + +\def\tabl_tabulate_vrule_reset_indeed + {\dofastloopcs\c_tabl_tabulate_max_vrulecolumn\tabl_tabulate_vrule_reset_step + \global\c_tabl_tabulate_max_vrulecolumn\zerocount} + +\def\tabl_tabulate_vrule_reset_step % undefined or relax + {\expandafter\glet\csname\??tabulatevrule\the\fastloopindex\endcsname\undefined} + +\appendtoks + \tabl_tabulate_vrule_reset +\to \t_tabl_tabulate_every_after_row + +% sometimes more efficient: +% +% \def\tabl_tabulate_column_vruled_yes#1#2[#3]% +% {\rawprocesscommalist[#3]\tabl_tabulate_column_vruled_step +% \expandafter\xdef\csname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname +% {\global\d_tabl_tabulate_vrulethickness_local\the\d_tabl_tabulate_vrulethickness_default +% \noexpand\xdef\noexpand\m_tabl_tabulate_vrule_color_local{\m_tabl_tabulate_vrule_color_local}}% +% \tabl_tabulate_column_normal#1#2} + +\def\tabl_tabulate_column_vruled_normal + {\vrule\s!width\d_tabl_tabulate_vrulethickness\relax} + +\def\tabl_tabulate_column_vruled_colored + {\dousecolorparameter\m_tabl_tabulate_vrule_color + \vrule\s!width\d_tabl_tabulate_vrulethickness\relax} + +\unexpanded\def\tabl_tabulate_column_vrule_inject_first + {\ifcase\d_tabl_tabulate_vrulethickness\else + \tabl_tabulate_column_vruled_normal % could be a skip instead + \fi + \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one + +\unexpanded\def\tabl_tabulate_column_vrule_inject_second + {\ifcase\d_tabl_tabulate_vrulethickness\else + \ifx\m_tabl_tabulate_vrule_color\empty + \tabl_tabulate_column_vruled_normal + \else + \tabl_tabulate_column_vruled_colored + \fi + \fi + \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one + +\let\tabl_tabulate_column_vrule_inject\relax + +\appendtoks + \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_first +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_second +\to \t_tabl_tabulate_initializers_second + +% auto columns + +\def\tabl_tabulate_column_inject_auto + {\tabl_tabulate_column_normal\zerocount\zerocount + \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_columns\relax + \expandafter\NR + \else + \expandafter\ignorespaces % interferes with the more tricky hooks + \fi} + +\unexpanded\def\setquicktabulate#1% see \startlegend \startgiven (for the moment still public) + {\let#1\tabl_tabulate_column_inject_auto + \let\\\tabl_tabulate_column_inject_auto} % brrr, will go + +\setvalue{\??tabulateseparator\v!blank }{\s_tabl_tabulate_separator\bigskipamount} +\setvalue{\??tabulateseparator\v!depth }{\s_tabl_tabulate_separator\strutdp} +\setvalue{\??tabulateseparator\v!small }{\def\m_tabl_tabulate_separator_factor{.25}} +\setvalue{\??tabulateseparator\v!medium}{\def\m_tabl_tabulate_separator_factor{.5}} +\setvalue{\??tabulateseparator\v!big }{} +\setvalue{\??tabulateseparator\v!none }{\s_tabl_tabulate_separator\zeropoint\let\m_tabl_tabulate_separator_factor\zerocount} +\setvalue{\??tabulateseparator\v!grid }{\s_tabl_tabulate_separator\zeropoint\let\m_tabl_tabulate_separator_factor\zerocount} + +\def\tabl_tabulate_column_rule_separator_step#1% + {\ifcsname\??tabulateseparator#1\endcsname + \lastnamedcs + \else + \s_tabl_tabulate_separator#1\relax + \fi} + +\def\tabl_tabulate_column_rule_separator_inject % can be sped up (will do when used frequently) + {\bgroup + \s_tabl_tabulate_separator\strutdp + \ifx\p_distance\empty\else + \let\m_tabl_tabulate_separator_factor\plusone + \processcommacommand[\p_distance]\tabl_tabulate_column_rule_separator_step + \s_tabl_tabulate_separator\m_tabl_tabulate_separator_factor\s_tabl_tabulate_separator + \fi + % someamble: footer or header: unfortunately a skip can trigger a page break (weird + % as we have lots of nobreaks) + % \ifconditional\c_tabl_tabulate_someamble\kern\else\vskip\fi\s_tabl_tabulate_separator % new + % \directvspacing{\the\s_tabl_tabulate_separator}% new + \directvskip\s_tabl_tabulate_separator + \egroup} + +\def\tabl_tabulate_hrule_spec_ignore#1% + {%\glet\currenttabulationlocalhrulecolor\empty + %\global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default + \doifelsefastoptionalcheck#1#1} + +\def\tabl_tabulate_hrule_spec_pickup#1% + {\glet\currenttabulationlocalhrulecolor\m_tabl_tabulate_hrule_color_default + \global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default + \doifelsefastoptionalcheck{\tabl_tabulate_hrule_preset#1}#1} + +\def\tabl_tabulate_hrule_preset_step#1% + {\doifelsenumber{#1} + {\global\d_tabl_tabulate_hrulethickness_local#1\d_tabl_tabulate_hrulethickness_default} + {\xdef\currenttabulationlocalhrulecolor{#1}}} + +\def\tabl_tabulate_hrule_preset#1[#2]% + {\rawprocesscommalist[#2]\tabl_tabulate_hrule_preset_step + #1} + +\def\tabl_tabulate_hrule_inject_normal + {\autorule + \s!height.5\d_tabl_tabulate_hrulethickness_local + \s!depth .5\d_tabl_tabulate_hrulethickness_local + \s!left \d_tabl_tabulate_indent + \relax} + +\def\tabl_tabulate_hrule_inject_colored + {\dousecolorparameter\currenttabulationlocalhrulecolor + \tabl_tabulate_hrule_inject_normal} + +\unexpanded\def\tabl_tabulate_hrule_inject_first + {\ifcase\d_tabl_tabulate_hrulethickness_local\else + \tabl_tabulate_hrule_inject_normal + \fi} + +\unexpanded\def\tabl_tabulate_hrule_inject_second + {\ifcase\d_tabl_tabulate_hrulethickness_local\else + \ifx\currenttabulationlocalhrulecolor\empty + \tabl_tabulate_hrule_inject_normal + \else + \tabl_tabulate_hrule_inject_colored + \fi + \fi} + +\let\tabl_tabulate_hrule_inject\relax + +\appendtoks + \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_first +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_second +\to \t_tabl_tabulate_initializers_second + +%D Color: + +% \starttabulate[||p||] +% \NC test \NC test \NC test \NC \NR +% \NC test \CC[green] \input tufte \CC[yellow] test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \CC[blue] test \CC[red] test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \CC[gray] test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \CC[blue] test \NC test \NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \NC test \CC[magenta] test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \CC[cyan] \dorecurse{10}{\input ward }\NC test \NC \NR +% \NC test \NC test \NC test \NC \NR +% \NC test \CC[yellow] test \NC test \NC \NR +% \stoptabulate + +\unexpanded\def\tabl_tabulate_color_set#1% we could store the attributes at the cost of a lua call + {\begingroup + \clf_enablebackgroundalign % was \node_backgrounds_align_initialize + \glet\tabl_tabulate_color_repeat\tabl_tabulate_color_repeat_second + \global\settrue\c_tabl_tabulate_has_colors + \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_colorcolumn + \global\c_tabl_tabulate_max_colorcolumn\c_tabl_tabulate_column + \fi + \expandafter\xdef\csname\??tabulatecolor\the\c_tabl_tabulate_column\endcsname{#1}% + \hpack \thealignbackgroundcolorattr{#1}{}% pack ? + \endgroup} + +\def\tabl_tabulate_color_repeat_second % for split off lines + {\begingroup + \scratchcounter\numexpr\c_tabl_tabulate_column-\plusone\relax % ugly ! + \ifcsname\??tabulatecolor\the\scratchcounter\endcsname + % \hbox \thealignbackgroundcolorattr{\csname\??tabulatecolor\the\scratchcounter\endcsname}{}% pack ? + \hpack \expandafter\thealignbackgroundcolorattr\expandafter{\lastnamedcs}{}% pack ? + \fi + \endgroup} + +\let\tabl_tabulate_color_repeat\relax + +\appendtoks + \let\tabl_tabulate_color_repeat\relax +\to \everytabulate + +\def\tabl_tabulate_color_reset + {\ifcase\c_tabl_tabulate_max_colorcolumn\else + \tabl_tabulate_color_reset_indeed + \fi} + +% \def\tabl_tabulate_color_reset_indeed +% {\dorecurse\c_tabl_tabulate_max_colorcolumn{\letgvalue{\??tabulatecolor\recurselevel}\undefined}} % slow + +\def\tabl_tabulate_color_reset_indeed + {\dofastloopcs\c_tabl_tabulate_max_colorcolumn\tabl_tabulate_color_reset_step} + +\def\tabl_tabulate_color_reset_step % undefined or empty? + {\expandafter\glet\csname\??tabulatecolor\number\fastloopindex\endcsname\undefined} + +\appendtoks + \tabl_tabulate_color_reset +\to \t_tabl_tabulate_every_after_row + +% \def\tabl_tabulate_register_par_options_indeed +% {\iftrialtypesetting \else +% \registerparoptions +% \ifinsidefloat +% % that is, an unbreakable one +% \glet\tabl_tabulate_register_par_options\empty +% \else +% % unsafe in crossing pages, at each b... +% % \glet\tabl_tabulate_register_par_options\empty +% \fi +% \fi} +% +% \appendtoks +% \glet\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_indeed +% \to \everytabulate + +\def\tabl_tabulate_register_par_options_first % maybe track here if needed + {} + +\def\tabl_tabulate_register_par_options_second + {\registerparoptions + \ifinsidefloat + % that is, an unbreakable one + \glet\tabl_tabulate_register_par_options\empty + \else + % unsafe in crossing pages, at each b... + % \glet\tabl_tabulate_register_par_options\empty + \fi} + +\let\tabl_tabulate_register_par_options\relax + +\appendtoks + \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_first +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_second +\to \t_tabl_tabulate_initializers_second + +\appendtoks + \tabl_tabulate_register_par_options +\to \t_tabl_tabulate_every_row + +\def\tabl_tabulate_flush_indent_indeed + {\hbox to \d_tabl_tabulate_indent % pack ? + {% we now have a local hsize, and since we want to + % register positional info (i.e. real hsizes) we + % need to reconstitute the original hsize + \advance\hsize\d_tabl_tabulate_indent + % this is indeed rather messy and took a few hours + % to dis/uncover + \the\t_tabl_tabulate_every_row + \hss}} + +\def\tabl_tabulate_flush_indent + {\ifnum\c_tabl_tabulate_column=\zerocount + \tabl_tabulate_flush_indent_indeed + \fi} + +\def\tabl_tabulate_digits{\digits} + +%D Beware, we cannot use \type {\unexpanded} on \type {\HL} cum suis, since \TEX's +%D hard coded noalign lookahead fails on it! I mistakenly added this for a while. + +\setvalue{\??tabulatealigning\v!normal}{0} +\setvalue{\??tabulatealigning\v!right }{1} +\setvalue{\??tabulatealigning\v!left }{2} +\setvalue{\??tabulatealigning\v!middle}{3} + +\setvalue{\??tabulateheader\v!repeat}{\plusone} +\setvalue{\??tabulateheader\v!text }{\plustwo} + +\unexpanded\def\tabl_tabulate_bskip_first {\setbox\b_tabl_tabulate\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop} +\unexpanded\def\tabl_tabulate_eskip_first {\par\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes} +\unexpanded\def\tabl_tabulate_xbskip_first{\hpack\bgroup\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop} +\unexpanded\def\tabl_tabulate_xeskip_first{\par\egroup\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes} + +\let\tabl_tabulate_bbskip\relax +\let\tabl_tabulate_eeskip\relax +\let\tabl_tabulate_bskip \relax +\let\tabl_tabulate_eskip \relax +\let\tabl_tabulate_xbskip\relax +\let\tabl_tabulate_xeskip\relax + +\appendtoks + \let\tabl_tabulate_bbskip\relax + %\let\tabl_tabulate_eeskip\relax % adapted by bskip + \let\tabl_tabulate_bskip \tabl_tabulate_bskip_first + \let\tabl_tabulate_eskip \tabl_tabulate_eskip_first + \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_first + \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_first +\to \t_tabl_tabulate_initializers_first + +\def\tabl_tabulate_baselinecorrection % keep an eye on this one + {\def\dobaselinecorrection{\vskip\dimexpr-\prevdepth+\strutdp+\strutdp\relax}% todo: mkiv + \baselinecorrection} + +% some hack to prevent an allowbreak ... actually we could set up a system then +% that is dealt with atthe lua end in the skip handler: turn penalties with attributes +% values into other penalties that get removed + +\installcorenamespace{tabulatenobreak} + +\def\tabl_tabulate_break_allow{\directvpenalty\zerocount} +\def\tabl_tabulate_break_maybe{\directvpenalty\zerocount} +\def\tabl_tabulate_break_no {\directvpenalty\plustenthousand} % ,order:2}} + +\let\tabl_tabulate_break_state_set \relax +\let\tabl_tabulate_break_state_reset \relax +\let\tabl_tabulate_break_state_allowbreak\tabl_tabulate_break_maybe + +% so far + +\unexpanded\def\tabl_tabulate_VL_first{\tabl_tabulate_column_vruled\zerocount\zerocount} +\unexpanded\def\tabl_tabulate_NC_first{\tabl_tabulate_column_normal\zerocount\zerocount} +\unexpanded\def\tabl_tabulate_RC_first{\tabl_tabulate_column_normal\zerocount\plusone} +\unexpanded\def\tabl_tabulate_HC_first{\tabl_tabulate_column_normal\zerocount\plustwo} +\unexpanded\def\tabl_tabulate_EQ_first{\tabl_tabulate_column_equal \plustwo \zerocount} +\unexpanded\def\tabl_tabulate_RQ_first{\tabl_tabulate_column_equal \zerocount\plusone} +\unexpanded\def\tabl_tabulate_HQ_first{\tabl_tabulate_column_equal \zerocount\plustwo} + +\unexpanded\def\tabl_tabulate_NG_first{\tabl_tabulate_column_normal\zerocount\zerocount} +\unexpanded\def\tabl_tabulate_NN_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % new, undocumented, test first +\unexpanded\def\tabl_tabulate_ND_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % same, for old times sake + +\unexpanded\def\tabl_tabulate_NR_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_check_penalties} % next row +\unexpanded\def\tabl_tabulate_NB_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_nobreak_inject } % next row no break + +\unexpanded\def\tabl_tabulate_NR_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_check_penalties} % next row +\unexpanded\def\tabl_tabulate_NB_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_nobreak_inject } % next row no break + +\unexpanded\def\tabl_tabulate_CC_first{\global\c_tabl_tabulate_localcolorspan\zerocount\tabl_tabulate_set_color_column\zerocount} +\unexpanded\def\tabl_tabulate_CL_first{\global\c_tabl_tabulate_localcolorspan\plusone \tabl_tabulate_set_color_column\zerocount} +\unexpanded\def\tabl_tabulate_CM_first{\global\c_tabl_tabulate_localcolorspan\plustwo \tabl_tabulate_set_color_column\zerocount} +\unexpanded\def\tabl_tabulate_CR_first{\global\c_tabl_tabulate_localcolorspan\plusthree\tabl_tabulate_set_color_column\zerocount} + +%D Sort of special: +%D +%D \startbuffer +%D \startitemize[n] +%D \starttabulate[|||||] +%D \NC p \NC \itemtag \NC q \NC r \NC \NR +%D \NC p \NC \itemtag \NC q \NC r \NC \NR +%D \NC p \NC \itemtag \NC q \NC r \NC \NR +%D \NC p \NC \itemtag \NC q \NC r \NC \NR +%D \stoptabulate +%D \stopitemize +%D +%D \startitemize[n] +%D \starttabulate[|||||] +%D \NI b \NC c \NC d \NC \NR +%D \NC a \NI c \NC d \NC \NR +%D \NC a \NC b \NI d \NC \NR +%D \NC a \NC b \NC c \NI \NR +%D \stoptabulate +%D \stopitemize +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\unexpanded\def\tabl_tabulate_NI_first{\doifelsefastoptionalcheck\tabl_tbl_NI_yes\tabl_tbl_NI_nop} + +\def\tabl_tbl_NI_yes[#1]{\NC \itemtag[#1]\NC} +\def\tabl_tbl_NI_nop {\NC \itemtag \NC} + +%D The following shortcut is handy for tables where one needs bold headers: + +\unexpanded\def\tabl_tabulate_BC_first + {\tabl_tabulate_column_normal\plusone\zerocount + \let\fontstyle\globalfontstyle + \bf} + +\appendtoks + \let\VL\tabl_tabulate_VL_first + \let\NC\tabl_tabulate_NC_first + \let\BC\tabl_tabulate_BC_first + \let\RC\tabl_tabulate_RC_first + \let\HC\tabl_tabulate_HC_first + \let\EQ\tabl_tabulate_EQ_first + \let\RQ\tabl_tabulate_RQ_first + \let\HQ\tabl_tabulate_HQ_first + \let\NG\tabl_tabulate_NG_first + \let\NN\tabl_tabulate_NN_first + \let\ND\tabl_tabulate_ND_first + \let\NR\tabl_tabulate_NR_first + \let\NB\tabl_tabulate_NB_first + \let\CC\tabl_tabulate_CC_first + \let\CL\tabl_tabulate_CL_first + \let\CM\tabl_tabulate_CM_first + \let\CR\tabl_tabulate_CR_first + \let\NI\tabl_tabulate_NI_first +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\NR\tabl_tabulate_NR_second + \let\NB\tabl_tabulate_NB_second +\to \t_tabl_tabulate_initializers_second + +\appendtoks + \let\SR\NR + \let\FR\NR + \let\MR\NR + \let\LR\NR + \let\AR\NR +\to \t_tabl_tabulate_initializers_first + +\unexpanded\def\tabl_tabulate_NR_common#1#2% + {\global\advance\c_tabl_tabulate_noflines\plusone + \global\setfalse\c_tabl_tabulate_firstflushed + \global\setfalse\c_tabl_tabulate_equal + \global\c_tabl_tabulate_column\zerocount + \ifconditional#1\relax + \tabl_tabulate_break_state_reset + \fi + \tabl_tabulate_pheight_reset + \unskip\unskip\crcr\tabl_tabulate_flush_collected + % can we omit the next one in the first run? probably + \starttabulatenoalign + \the\t_tabl_tabulate_every_after_row + #2% + \stoptabulatenoalign} + +\def\tabl_tabulate_check_penalties + {\ifconditional\c_tabl_tabulate_tolerant_break\else + \ifnum\c_tabl_tabulate_totalnoflines=\plusone + % \tabl_tabulate_break_allow + \else + \ifconditional\c_tabl_tabulate_someamble \ifcase\c_tabl_tabulate_repeathead \else + \tabl_tabulate_break_allow + \fi \fi + \ifnum\c_tabl_tabulate_noflines=\plusone + \tabl_tabulate_nobreak_inject + \orelse\ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_minusnoflines + \ifnum\c_tabl_tabulate_plines_max<\plustwo + \tabl_tabulate_nobreak_inject + \else + \tabl_tabulate_break_allow % needed with pbreak prevention + \fi + \else + \tabl_tabulate_break_state_allowbreak + \fi + \fi + \fi + \global\setfalse\c_tabl_tabulate_firstflushed} + +\unexpanded\def\tabl_tabulate_bbskip_second_split_yes + {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column + \ifx\tabl_tabulate_flush_collected_indeed\empty\else + \setbox0\hbox + \fi + \fi} + +\unexpanded\def\tabl_tabulate_eskip_second + {\par\egroup + \tabl_tabulate_pheight_set + \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes + \tabl_tabulate_splitoff_box} + +\unexpanded\def\tabl_tabulate_bskip_second_split_yes + {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column + % first line + \global\setbox\b_tabl_tabulate_current\c_tabl_tabulate_column\vbox + \bgroup + \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop + \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi + % \begstrut % interferes with pre-\pars + % evt: \appendtoks\begstrut\to\everypar + \ignorespaces + \let\tabl_tabulate_eskip\tabl_tabulate_eskip_second + \else + % successive lines + \let\tabl_tabulate_eskip\empty + \dontcomplain + \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes + \expandafter\tabl_tabulate_splitoff_box + \fi} + +\unexpanded\def\tabl_tabulate_xbskip_second{\tabl_tabulate_bskip} +\unexpanded\def\tabl_tabulate_xeskip_second{\tabl_tabulate_eskip} + +\unexpanded\def\tabl_tabulate_flush_second_indeed + {\glet\tabl_tabulate_flush_collected_indeed\empty + \global\c_tabl_tabulate_column\zerocount + \tabl_tabulate_pbreak_check + \dofastloopcs\c_tabl_tabulate_columns\tabl_tabulate_flush_second_step + \global\settrue\c_tabl_tabulate_firstflushed} + +\unexpanded\def\tabl_tabulate_flush_second_step + {\ifvoid\b_tabl_tabulate_current\fastloopindex\else + \gdef\tabl_tabulate_flush_collected_indeed{\the\t_tabl_tabulate_dummy}% + \fi} + +\def\tabl_tabulate_flush_second + {\tabulatenoalign{\tabl_tabulate_flush_second_indeed}% + \tabl_tabulate_flush_collected_indeed} + +\unexpanded\def\tabl_tabulate_bskip_second_split_nop + {\vtop\bgroup + \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi + % \begstrut % interferes with pre-\pars + % evt: \appendtoks\begstrut\to\everypar + \ignorespaces} + +\unexpanded\def\tabl_tabulate_eskip_second_split_nop % vertical strut added august 2003 + {\par\verticalstrut + \vskip-\struttotal + \egroup} + +% \let\tabl_tabulate_eskip \relax % adapted by bskip +% \let\tabl_tabulate_eeskip\relax % adapted by bskip + +\appendtoks + \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_second + \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_second + \ifconditional\c_tabl_tabulate_split + \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_yes + \let\tabl_tabulate_bbskip\tabl_tabulate_bbskip_second_split_yes + \else + \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_nop + \let\tabl_tabulate_eskip \tabl_tabulate_eskip_second_split_nop + \fi +\to \t_tabl_tabulate_initializers_second + +% see *** +% +% \enabletrackers[nodes.page_vspacing] +% \starttext +% \starttabulate[||] \dorecurse{100}{\NC Eins \NC \NR \HL} \stoptabulate +% \stoptext + +\def\tabl_tabulate_XX_none + {\starttabulatenoalign + \tabl_tabulate_break_state_set + \tabl_tabulate_hrule_spec_ignore + \stoptabulatenoalign} + +\def\tabl_tabulate_FL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_FL_second_indeed} +\def\tabl_tabulate_ML_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_ML_second_indeed} +\def\tabl_tabulate_LL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_LL_second_indeed} +\def\tabl_tabulate_TL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_TL_second_indeed} +\def\tabl_tabulate_BL_second{\starttabulatenoalign\tabl_tabulate_hrule_spec_pickup\tabl_tabulate_BL_second_indeed} + +\unexpanded\def\tabl_tabulate_FL_second_indeed + {\ifinsidefloat\else + \doifempty{\tabulationparameter\c!before}\tabl_tabulate_baselinecorrection % no expansion + \fi + \tabl_tabulate_hrule_inject + \tabl_tabulate_nobreak_inject + \tabl_tabulate_column_rule_separator_inject + \prevdepth\strutdp + \tabl_tabulate_nobreak_inject + \stoptabulatenoalign} + +\def\spac_vspacing_no_topskip % use grouped + {\attribute\skipcategoryattribute\plusten} + +\unexpanded\def\tabl_tabulate_ML_second_indeed + {\tabl_tabulate_break_no + \tabl_tabulate_column_rule_separator_inject + \tabl_tabulate_break_no + \tabl_tabulate_hrule_inject + \vskip-\p_rulethickness\relax + \begingroup + \spac_vspacing_no_topskip + \tabl_tabulate_hrule_inject + \endgroup + \tabl_tabulate_break_no + \tabl_tabulate_column_rule_separator_inject + \stoptabulatenoalign} + +\unexpanded\def\tabl_tabulate_LL_second_indeed + {\tabl_tabulate_nobreak_inject + \tabl_tabulate_column_rule_separator_inject + \tabl_tabulate_nobreak_inject + \tabl_tabulate_hrule_inject + \ifinsidefloat + \tabl_tabulate_inside_inbetween + \else + \tabl_tabulate_outside_inbetween + \fi + \stoptabulatenoalign} + +\unexpanded\def\tabl_tabulate_TL_second_indeed + {\tabl_tabulate_nobreak_inject + \tabl_tabulate_column_rule_separator_inject + \tabl_tabulate_nobreak_inject + \tabl_tabulate_hrule_inject + \tabl_tabulate_nobreak_inject + \tabl_tabulate_column_rule_separator_inject + %\prevdepth\strutdp % todo, might differ between TL and BL + \tabl_tabulate_nobreak_inject + \stoptabulatenoalign} + +\let\tabl_tabulate_BL_second_indeed\tabl_tabulate_TL_second_indeed + +\def\tabl_tabulate_HL_second + {\csname + \ifnum\c_tabl_tabulate_noflines=\zerocount F\orelse + \ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_totalnoflines L\else + M\fi + L\endcsname} + +\appendtoks + \let\FL\tabl_tabulate_XX_none + \let\ML\tabl_tabulate_XX_none + \let\LL\tabl_tabulate_XX_none + \let\TL\tabl_tabulate_XX_none + \let\BL\tabl_tabulate_XX_none + \let\HL\tabl_tabulate_XX_none + \let\HR\tabl_tabulate_XX_none +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \let\FL\tabl_tabulate_FL_second + \let\ML\tabl_tabulate_ML_second + \let\LL\tabl_tabulate_LL_second + \let\TL\tabl_tabulate_TL_second + \let\BL\tabl_tabulate_BL_second + \let\HL\tabl_tabulate_HL_second + \let\HR\tabl_tabulate_HL_second +\to \t_tabl_tabulate_initializers_second + +% \def\tabulatedoHRfive % horizontal rule line (break untested) +% {\starttabulatenoalign +% \glet\dotabulateautoline\dotabulatelinerule +% %\ifcase#1\or % todo: check what this does +% \ifnum\noftabulatelines=\zerocount +% \glet\dotabulateautoline\donothing +% \else\ifnum\noftabulatelines=\totalnoftabulatelines +% \glet\dotabulateautoline\donothing +% \fi\fi +% %\fi +% \dotabulatenobreak +% \stoptabulatenoalign +% \dotabulateautoline +% \starttabulatenoalign +% \tabl_tabulate_break_no +% \ifx\dotabulateautoline\dotabulatelinerule\kern-\lineheight\fi +% \ifnum\noftabulatelines=\totalnoftabulatelines +% \expandafter\dotabulatenobreak +% \else +% \expandafter\tabl_tabulate_break_allow +% \fi +% \stoptabulatenoalign +% \dotabulateautoline +% \starttabulatenoalign +% \dotabulatenobreak +% \stoptabulatenoalign} + +% \dorecurse{10}{ +% \starttabulate[|l|] +% \FL +% \NC first line, bound to next rule \NC \NR +% \TL +% \NC bound to previous rule \NC \NR +% \NC some line \NC \NR +% \NC some line \NC \NR +% \NC some line \NC \NR +% \NC bound to next rule \NC \NR +% \ML +% \NC bound to previous rule \NC \NR +% \NC bound to next rule \NC \NR +% \BL +% \NC last line, bound to previous rule \NC \NR +% \LL +% \stoptabulate +% } + +% This needs checking: + +\def\tabulaterule {\HR} % a rule with lineheight +\def\tabulateline {\HL} % just a spaced rule +\def\tabulateautorule{\HR}% +\def\tabulateautoline{\HL} % no longer different (to be looked into) + +%D When support for vertical rules we needed a way to pick up the specification for +%D the final rule and a \type {|{}} interface was chosen. As a result parsing had to +%D become more complex and I was not in the mood for messing up the code too much. +%D Therefore from now on the preamble is split by \LUA. There are definitely more +%D places where we can use \LUA\ code (for instance in alignment of numbers. The +%D repeat parser is replace at the \LUA\ end as well. + +\let\tabl_tabulate_flush_collected \empty +\let\tabl_tabulate_flush_collected_indeed\empty + +\let\v_tabl_tabulate_align\!!zerocount + +\def\tabl_tabulate_check_side_float % new per 29-07-2016 + {\ifdefined\page_sides_check_floats_indeed + \page_sides_check_floats_indeed + \ifdim\hangindent>\zeropoint + \advance\d_tabl_tabulate_indent\hangindent + \fi + \fi} + +\def\tabl_tabulate_set_local_hsize + {\setlocalhsize + \hsize\localhsize} + +\def\tabl_tabulate_process + {\c_tabl_tabulate_pass\plusone + \tabl_tabulate_check_full_content + \edef\v_tabl_tabulate_align{\ifcsname\??tabulatealigning\p_align\endcsname\lastnamedcs\else0\fi}% + \s_tabl_tabulate_first.5\d_tabl_tabulate_unit + \s_tabl_tabulate_last\s_tabl_tabulate_first + \s_tabl_tabulate_pre\zeropoint + \s_tabl_tabulate_post\s_tabl_tabulate_first % was: \zeropoint + \global\c_tabl_tabulate_columns\zerocount + \global\c_tabl_tabulate_nofauto\zerocount + \global\c_tabl_tabulate_noflines\zerocount + \c_tabl_tabulate_totalnoflines\zerocount + \c_tabl_tabulate_minusnoflines\zerocount + \global\d_tabl_tabulate_width_p\zeropoint + \global\d_tabl_tabulate_width_w\zeropoint + \global\setfalse\c_tabl_tabulate_equal + \tabl_tabulate_pheight_reset + \tabskip\zeropoint + \ifinsidesplitfloat + \donetrue + \orelse\ifinsidefloat + \donefalse + \else + \donetrue + \fi + \global\c_tabl_tabulate_repeathead + \ifdone + \ifcsname\??tabulateheader\tabulationparameter\c!header\endcsname + \lastnamedcs + \else + \zerocount + \fi + \else + \zerocount + \fi + % + \the\t_tabl_tabulate_initializers_first % collect more here + % + \glet\tabl_tabulate_flush_collected\empty + \ifdim\d_tabl_tabulate_margin>\zeropoint + \t_tabl_tabulate_preamble + {\aligntab + \tabl_tabulate_flush_indent +% \global\advance\c_tabl_tabulate_noflines\plusone + \strut + \alignmark\alignmark + \tabskip\d_tabl_tabulate_margin + \strut + \aligntab + \alignmark\alignmark + \tabskip\zeropoint}% + \else + \t_tabl_tabulate_preamble + {\aligntab + \tabl_tabulate_flush_indent +% \global\advance\c_tabl_tabulate_noflines\plusone + \strut + \alignmark\alignmark + \aligntab + \alignmark\alignmark + \tabskip\zeropoint}% + \fi + \d_tabl_tabulate_width\zeropoint + % these counters are set at the lua end + \c_tabl_tabulate_nofcolumns \zerocount + \c_tabl_tabulate_has_rule_spec_first\zerocount + \c_tabl_tabulate_has_rule_spec_last \zerocount + \clf_presettabulate{\detokenizedtabulationparameter\c!format}% + % + % \edef\totaltabulatecolumns{\the\numexpr3*\c_tabl_tabulate_columns+\plusfour}% + \d_tabl_tabulate_width\zeropoint + \tabl_tabulate_initialize_boxes\c_tabl_tabulate_columns + \toksapp\t_tabl_tabulate_preamble{% + \aligntab\alignmark\alignmark + \global\advance\c_tabl_tabulate_column\plusone % maybe just set it already + }% + \toksapp\t_tabl_tabulate_dummy{% + \NC\unskip\unskip\crcr\tabl_tabulate_flush_collected % no count + }% + \global\c_tabl_tabulate_column\zerocount + \tabl_tabulate_pheight_reset + \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes + \ifx\p_indenting\v!no + \forgetparindent + \fi + \ifinsidefloat + \d_tabl_tabulate_indent\zeropoint + \else + \tabl_tabulate_check_side_float + \tabl_tabulate_set_local_hsize + \fi + \dontcomplain + \forgetall % hm, interference with preceding \forgetparindent probably bug, to be solved + \everypar\everytabulatepar + \setbox\scratchbox\vbox % outside \if because of line counting + {\notesenabledfalse + \d_tabl_tabulate_indent\zeropoint + \settrialtypesetting % very important + \anch_backgrounds_text_level_start + \expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}}% + \anch_backgrounds_text_level_stop + \ifcase\c_anch_backgrounds_text_state\else + \global\settrue\tablehaspositions + \fi + \ifnum\c_tabl_tabulate_nofauto>\zerocount + % so, even if the natural size is larger, in the final run, we force the calculated width + \d_tabl_tabulate_width\dimexpr\hsize-\wd\scratchbox-\d_tabl_tabulate_width_p-\d_tabl_tabulate_width_w\relax + \ifnum\c_tabl_tabulate_nofauto>\zerocount + \divide\d_tabl_tabulate_width \c_tabl_tabulate_nofauto\relax + \fi + \fi + \setbox\scratchbox\emptybox % free memory + \ifconditional\c_tabl_tabulate_split + \splittopskip\strutht + \glet\tabl_tabulate_flush_collected_indeed\empty + \glet\tabl_tabulate_flush_collected\tabl_tabulate_flush_second + \fi + \c_tabl_tabulate_totalnoflines\c_tabl_tabulate_noflines + \c_tabl_tabulate_minusnoflines\numexpr\c_tabl_tabulate_noflines+\minusone\relax + \global\c_tabl_tabulate_noflines\zerocount + % + \c_tabl_tabulate_pass\plustwo % final pass + \the\t_tabl_tabulate_initializers_second % collect more here + % + \ifx\p_line\v!line + \let\HL\HR + \let\tabulateautoline\tabulateautorule + \let\tabulateline\tabulaterule + \fi + % + \ifcase\c_tabl_tabulate_repeathead + \ifinsidesplitfloat + \global\setbox\b_tabl_tabulate\vbox \bgroup + \else + \startframedcontent[\tabulationparameter\c!frame]% + \fi + \else + \global\setbox\b_tabl_tabulate\vbox \bgroup + \fi + % + \dostarttaggedchained\t!tabulate\empty\??tabulation + \dostarttagged\t!tabulaterow\empty + \setfalse\inhibitmargindata % new per 2012.06.13 ... really needed + % \everycr\expandafter{\the\everycr\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}% + \toksapp\everycr{\noalign{\the\t_tabl_tabulate_every_real_row}\dostoptagged\dostarttagged\t!tabulaterow\empty}% + \expandafter\halign\expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}% + \dostoptagged + \dostoptagged + \ifhmode\par\prevdepth\strutdp\fi % nog eens beter, temporary hack + \ifx\p_distance\v!grid + \vskip-\strutdp % experimental tm-prikkels + \fi + % + \ifcase\c_tabl_tabulate_repeathead + \ifinsidesplitfloat + \egroup % box + \egroup % settings + \tabl_split_box\b_tabl_tabulate + \else + \stopframedcontent + \egroup + \fi + \else + \egroup % box + \egroup % settings + \tabl_split_box\b_tabl_tabulate + \fi + % + \ifinsidefloat + \tabl_tabulate_inside_after + \else + \tabl_tabulate_outside_after + \fi + \egroup} % whole thing + +% \egroup + +% \setuptabulate[split=yes,header=text,title=Vervolg van Tabel] +% +% % \starttabulatehead +% % \NC test \NC hans\NC \NR +% % \stoptabulatehead +% +% \starttabulate +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input knuth \relax \NC \NR +% \NC test \NC \input knuth \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \NC test \NC \input tufte \relax \NC \NR +% \stoptabulate + +\def\tabl_split_box#1% #1 <> 0/2 / derived from the one in core-ntb.tex + {\ifinsidesplitfloat + \tabl_split_box_indeed#1% + \orelse\ifinsidefloat + \unvbox#1% + \else + \tabl_split_box_indeed#1% + \fi} + +\def\tabl_split_box_indeed#1% + {\resettsplit + \def\tsplitminimumfreelines{2}% + \def\tsplitminimumfreespace{0pt}% + \setbox\tsplitcontent\box#1% + \ifcase\c_tabl_tabulate_repeathead\or + \setbox\tsplithead\vsplit\tsplitcontent to \lineheight + \setbox\tsplithead\vbox{\unvbox\tsplithead}% + \or + \setbox\tsplithead\vbox{\hbox{\strut\tabulationparameter\c!title}}% + \fi + \handletsplit} + +%D \starttyping +%D \setuptabulate[split=no,rule=line] +%D +%D \starttabulate +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule +%D \stoptabulate +%D \stoptyping + +%D Spacing: +% +% \starttabulate +% \NC text \NC text \NC \NR +% \TB[small] +% \NC text \NC text \NC \NR +% \TB[4*big] +% \NC text \NC text \NC \NR +% \stoptabulate + +\def\tabl_tabulate_TB + {\starttabulatenoalign + \dosingleempty\tabl_tabulate_TB_indeed} + +\def\tabl_tabulate_TB_indeed[#1]% + {\iffirstargument + \blank[#1] + \orelse\ifx\m_tabl_tabulate_blank_default\empty + \blank + \else + \blank[\m_tabl_tabulate_blank_default]% + \fi + \stoptabulatenoalign} + +% to be tested: +% +% \def\tabl_tabulate_TB +% {\starttabulatenoalign +% \doiffastoptionalcheckelse\tabl_tabulate_TB_yes\tabl_tabulate_TB_nop} +% +% \def\tabl_tabulate_TB_yes[#1]% +% {\blank[#1] +% \stoptabulatenoalign} +% +% \def\tabl_tabulate_TB_nop[#1]% +% {\blank +% \stoptabulatenoalign} + +\appendtoks + \let\TB\tabl_tabulate_TB +\to \everytabulate + +% %D Between alignment lines certain rules apply, and even a simple test can mess +% %D up a table, which is why we have a special test facilityL +% %D +% %D \startbuffer +% %D \starttabulate[|l|p|] +% %D \NC 1test \NC test \NC \NR +% %D \tableifelse{\doifelse{a}{a}}{\NC Xtest \NC test \NC \NR}{}% +% %D \stoptabulate +% %D \stopbuffer +% %D +% %D \typebuffer \getbuffer +% +% \def\tableifelse#1% should be tabulatenoalign then +% {\tablenoalign +% {#1% +% {\aftergroup \firstoftwoarguments}% +% {\aftergroup\secondoftwoarguments}}} +% +% \def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}} + +%D Some new trickery: +%D +%D \startbuffer +%D \settrue\c_tabl_tabulate_splitoff_whitespace +%D +%D \starttabulate[|p(2cm)|p(2cm)|p(2cm)|] +%D \NC test 1a \NC test 2a \NC test 3a +%D \par +%D test 3b \NC \NR +%D \NC test 1a \NC test 2a \NC test 3a +%D \blank[line] +%D test 3b \NC \NR +%D \NC test 1a \NC test 2a \NC test 3a +%D \blank[halfline] +%D test 3b +%D \blank[halfline] +%D test 3c \NC \NR +%D \NC \blank \NC \blank \NC \blank \NC \NR +%D \NC test 1a \NC test 2a \NC test 3a +%D \blank[halfline] +%D test 3b +%D \blank[halfline] +%D test 3c \NC \NR +%D \NC \blank \NC \blank \NC \NC \NR +%D \NC test 1a +%D \par +%D test 1b +%D \par +%D test 1b \NC test 2a +%D \par +%D test 2b +%D \par +%D test 2b \NC test 3a \NC \NR +%D \NC test 1a +%D \blank +%D test 1b +%D \par +%D test 1b \NC test 2a +%D \par +%D test 2b +%D \blank +%D test 2b \NC test 3a \NC \NR +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer \start \getbuffer \stop + +% \starttabulatie[|mc|] +% \NC \digits{100.000,00} \NC\NR +% \NC \digits{@10.000,00} \NC\NR +% \NC \digits{@@@.100,00} \NC\NR +% \NC \digits{@@@.@10,@@} \NC\NR +% \NC \digits{@@@.@@1,@@} \NC\NR +% \stoptabulatie +% +% \starttabulatie[|mc|] +% \ND 100.000,00 \NC\NR +% \ND @10.000,00 \NC\NR +% \ND @@@.100,00 \NC\NR +% \ND @@@.@10,@@ \NC\NR +% \ND @@@.@@1,@@ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \ND $100.000,00$ \NC\NR +% \ND $@10.000,00$ \NC\NR +% \ND $@@@.100,00$ \NC\NR +% \ND $@@@.@10,@@$ \NC\NR +% \ND $@@@.@@1,@@$ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \NC $\digits 100.000,00 $ \NC\NR +% \NC $\digits @10.000,00 $ \NC\NR +% \NC $\digits @@@.100,00 $ \NC\NR +% \NC $\digits @@@.@10,@@ $ \NC\NR +% \NC $\digits @@@.@@1,@@ $ \NC\NR +% \stoptabulatie +% +% \starttabulatie[|c|] +% \NC \digits $100.000,00$ \NC\NR +% \NC \digits $@10.000,00$ \NC\NR +% \NC \digits $@@@.100,00$ \NC\NR +% \NC \digits $@@@.@10,@@$ \NC\NR +% \NC \digits $@@@.@@1,@@$ \NC\NR +% \stoptabulatie + +%D Predefined categories (moved from core-mis): + +\definetabulate + [\v!legend] + [|emj1|i1|mR|] + +\setuptabulate + [\v!legend] + [\c!unit=.75em,\c!inner=\setquicktabulate\leg,EQ={=}] + +\definetabulate + [\v!legend][\v!two] + [|emj1|emk1|i1|mR|] + +\definetabulate + [\v!fact] + [|R|ecmj1|i1mR|] + +\setuptabulate + [\v!fact] + [\c!unit=.75em,\c!inner=\setquicktabulate\fact,EQ={=}] + +%D Another example: +%D +%D \starttyping +%D \definetabulate +%D [whatever] +%D [|l|r|] +%D +%D \definetabulate +%D [whatever][else] +%D [|l|c|r|] +%D +%D \startwhatever +%D \NC l \NC r \NC \NR +%D \NC left \NC right \NC \NR +%D \stopwhatever +%D +%D \startwhatever[else] +%D \NC l \NC m \NC r \NC \NR +%D \NC left \NC middle \NC right \NC \NR +%D \stopwhatever +%D +%D \startwhatever[else][format={|c|c|c|c|}] +%D \NC l \NC m \NC m \NC r \NC \NR +%D \NC left \NC middle \NC middle \NC right \NC \NR +%D \stopwhatever +%D \stoptyping + +%D This is needed because we sometimes use the english command in tracing macros. In +%D fact, most detailed tracing macros that are done with \LUA\ only work in the +%D english interface anyway. + +% \definetabulate[tabulate] \setuptabulate[tabulate][\c!format=\v!none] % so no \v! here + +\newconditional\c_tabl_generic + +\unexpanded\setuvalue{starttabulate}% + {\bgroup % whole thing + \settrue\c_tabl_generic + \let\currenttabulationparent\empty + \dodoubleempty\tabl_start_regular} + +\letvalue{stoptabulate}\relax + +%D The following helpers are just there because we also have them at the \LUA\ end: +%D +%D \startbuffer +%D \starttabulate[|l|c|r|] +%D \tabulaterow {a,b,c} +%D \tabulaterowbold{aa,bb,cc} +%D \tabulaterowtype{aaa,bbb,ccc} +%D \tabulaterowtyp {aaaa,bbbb,cccc} +%D \stoptabulate +%D \stopbuffer +%D +%D \typebuffer \getbuffer + +\def\tabl_tabulate_compact_row#1#2% + {\NC\tabl_tabulate_compact_step#1#2,\end,} + +\def\tabl_tabulate_compact_step#1#2#3,% + {\ifx#2\end + \NR + \expandafter\gobbleoneargument + \else + #1{#2#3}\NC + \expandafter\tabl_tabulate_compact_step + \fi#1} + +\unexpanded\def\tabulaterow {\tabl_tabulate_compact_row\relax} +\unexpanded\def\tabulaterowbold{\tabl_tabulate_compact_row\bold} +\unexpanded\def\tabulaterowtype{\tabl_tabulate_compact_row\type} +\unexpanded\def\tabulaterowtyp {\tabl_tabulate_compact_row\typ} + +%D Here we plug in a row background feature. As we only have support for +%D \type {frame=name} we can use these variables. +%D +%D \starttyping +%D \startuseMPgraphic{foo} +%D fill unitsquare +%D xyscaled (RuleWidth,RuleHeight+RuleDepth) enlarged (ExHeight/4,ExHeight/8) +%D randomized ExHeight +%D shifted (-ExHeight/8,ExHeight/16) +%D withcolor RuleColor ; +%D \stopuseMPgraphic +%D +%D \setuptabulate % wel only have frame=name so we can use these: +%D [background=foo, +%D backgroundcolor=darkred, +%D foregroundcolor=white] +%D +%D \definelinefiller[foo][mp=foo,color=darkgreen] +%D \definelinefiller[bar][mp=foo,color=darkred] +%D +%D \starttabulate[|||] +%D \DB foo \BC bar \BC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \stoptabulate +%D +%D \starttabulate[|||] +%D \PB foo \BC bar \BC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \stoptabulate +%D +%D \starttabulate[|||] +%D \FB[bar] foo \BC bar \BC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \stoptabulate +%D +%D \startnarrower +%D \starttabulate[|||] +%D \DB foo \DB bar \BC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \stoptabulate +%D \stopnarrower +%D +%D \starttabulate[|||] +%D \BC foo \BC bar \BC \NR +%D \NL[magenta] foo \NC bar \NC \NR +%D \NL[yellow] foo \NC bar \NC \NR +%D \NL[cyan] foo \NC bar \NC \NR +%D \NL[gray] foo \NC bar \NC \NR +%D \stoptabulate +%D +%D \starttabulate +%D \NL[red] foo \NC bar \NC \NR +%D \NL[green] foo \NL[red] bar \NC \NR +%D \NC foo \NC bar \NC \NR +%D \NL[blue] foo \NC \input tufte \NC \NR +%D \NL[gray] foo \NC bar \NC \NR +%D \NL[yellow] foo \NC bar \NC \NR +%D \stoptabulate +%D \stoptyping + +% \setuptabulate +% [\c!background=, +% \c!backgroundcolor=, +% \c!foregroundcolor=, +% \c!foregroundstyle=] + +\let\m_table_current_row_background \empty +\let\m_table_current_row_background_default \empty +\let\m_table_current_row_background_filler \empty +\let\m_table_current_row_background_defaultfiller\empty +\let\m_table_current_row_background_auto \empty + +\unexpanded\def\tabl_register_row_background#1% + {\xdef\m_table_current_row_background{#1}} + +\unexpanded\def\tabl_register_row_background_filler#1% + {\xdef\m_table_current_row_background_filler{#1}} + +\unexpanded\def\tabl_synchronize_row_background + {\iftrialtypesetting\else + \ifx\m_table_current_row_background_filler\empty + \ifx\m_table_current_row_background\empty + % nothing + \tabl_synchronize_row_background_dummy + \else + \tabl_synchronize_row_background_indeed\m_table_current_row_background + \fi + \else + \tabl_synchronize_row_background_filler_indeed\m_table_current_row_background_filler + \fi + \fi} + +\unexpanded\def\tabl_synchronize_row_background_dummy + {\iftrialtypesetting\else + \begingroup + %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\zerocount\zeropoint + \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\zerocount\zeropoint + \endgroup + \fi} + +\unexpanded\def\tabl_synchronize_row_background_indeed#1% + {\iftrialtypesetting\else + \begingroup + \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata + \dousecolorparameter{#1}% + \setbox\scratchbox\hpack{}% + %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\scratchbox\d_tabl_tabulate_indent + \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent + \endgroup + \fi} + +\unexpanded\def\tabl_synchronize_row_background_filler_indeed#1% + {\iftrialtypesetting\else + \begingroup + \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata + \node_linefiller_set{#1}% + \setbox\scratchbox\hpack{}% + %\clf_setbackgroundrowdata\numexpr\c_tabl_tabulate_nofrealrows+\minusone\relax\scratchbox\d_tabl_tabulate_indent + \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent + \endgroup + \fi} + +\appendtoks + \glet\m_table_current_row_background\empty + \glet\m_table_current_row_background_filler\empty + \global\c_tabl_tabulate_nofrealrows\zerocount + \global\c_tabl_tabulate_autocolor\zerocount + \clf_resetbackgroundrowdata +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \glet\m_table_current_row_background\empty + \glet\m_table_current_row_background_filler\empty + \global\c_tabl_tabulate_nofrealrows\zerocount + \global\c_tabl_tabulate_autocolor\zerocount + \clf_resetbackgroundrowdata +\to \t_tabl_tabulate_initializers_second + +\appendtoks + \tabl_synchronize_row_background +\to \t_tabl_tabulate_every_real_row + +\appendtoks + \glet\m_table_current_row_background\empty + \glet\m_table_current_row_background_filler\empty +\to \t_tabl_tabulate_every_after_row + +\unexpanded\def\tabl_tabulate_NL_first[#1]% + {\tabl_tabulate_column_normal\zerocount\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background{#1}% + \fi + \ignorespaces} + +\unexpanded\def\tabl_tabulate_ND_first + {\tabl_tabulate_column_normal\zerocount\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background\m_table_current_row_background_default + \fi + \ignorespaces} + +\unexpanded\def\tabl_tabulate_LB_first[#1]% + {\tabl_tabulate_column_normal\plusone\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background{#1}% + \fi + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \ignorespaces} + +\unexpanded\def\tabl_tabulate_DB_first + {\tabl_tabulate_column_normal\plusone\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background\m_table_current_row_background_default + \fi + \let\fontstyle\globalfontstyle + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \ignorespaces} + +\unexpanded\def\tabl_tabulate_NF_first[#1]% + {\tabl_tabulate_column_normal\zerocount\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background_filler{#1}% + \fi + \ignorespaces} + +\unexpanded\def\tabl_tabulate_NP_first + {\tabl_tabulate_column_normal\zerocount\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background_filler\m_table_current_row_background_default_filler + \fi + \ignorespaces} + +\unexpanded\def\tabl_tabulate_FB_first[#1]% + {\tabl_tabulate_column_normal\plusone\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background_filler{#1}% + \fi + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \ignorespaces} + +\unexpanded\def\tabl_tabulate_PB_first + {\tabl_tabulate_column_normal\plusone\zerocount\relax + \ifcase\c_tabl_tabulate_column\or + \tabl_register_row_background_filler\m_table_current_row_background_default_filler + \fi + \let\fontstyle\globalfontstyle + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \ignorespaces} + +\unexpanded\def\tabl_tabulate_BC_first % overloaded + {\tabl_tabulate_column_normal\plusone\zerocount + \let\fontstyle\globalfontstyle + \ifx\m_table_current_row_background\empty + \ifx\m_table_current_row_background_filler\empty + \usetabulationstyleandcolor\c!headstyle\c!headcolor + \else + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \fi + \else + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \fi} + +\unexpanded\def\tabl_tabulate_A_first + {\global\advance\c_tabl_tabulate_autocolor\plusone + \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\number\c_tabl_tabulate_autocolor}}% + \ifx\m_table_current_row_background_auto\empty + \global\c_tabl_tabulate_autocolor\plusone + \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\number\c_tabl_tabulate_autocolor}}% + \fi + \ifx\m_table_current_row_background_auto\empty + \let\m_table_current_row_background_auto\empty % \m_table_current_row_background_default + \fi + \tabl_register_row_background{\m_table_current_row_background_auto}} + +\unexpanded\def\tabl_tabulate_NA_first + {\tabl_tabulate_column_normal\zerocount\zerocount\relax + \iftrialtypesetting\else + \ifcase\c_tabl_tabulate_column\or + \tabl_tabulate_A_first + \fi + \fi + \ignorespaces} + +\unexpanded\def\tabl_tabulate_BA_first + {\tabl_tabulate_column_normal\plusone\zerocount\relax + \iftrialtypesetting\else + \ifcase\c_tabl_tabulate_column\or + \tabl_tabulate_A_first + \fi + \fi + \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor + \ignorespaces} + +\appendtoks + \let\NL\tabl_tabulate_NL_first % NC with Line + \let\ND\tabl_tabulate_ND_first % NC with Default Line + \let\LB\tabl_tabulate_LB_first % BC with Line + \let\DB\tabl_tabulate_DB_first % BC with Default Line + \let\NF\tabl_tabulate_NF_first % NC with Filler + \let\NP\tabl_tabulate_NP_first % NC with Predefined Filler + \let\FB\tabl_tabulate_FB_first % BC with Filler + \let\PB\tabl_tabulate_PB_first % BC with Predefined Filler + \let\NA\tabl_tabulate_NA_first % NC with Auto Line + \let\BA\tabl_tabulate_BA_first % NC with Auto Line +\to \t_tabl_tabulate_initializers_first + +\appendtoks + \edef\m_table_current_row_background_default {\tabulateparameter\c!backgroundcolor}% + \edef\m_table_current_row_background_default_filler{\tabulateparameter\c!background}% + \let \m_table_current_row_background_auto \empty +\to \everytabulate + +\setuptabulate + [\c!headcolor=, + \c!headstyle=\bf, + \c!backgroundcolor=\tabulationparameter\c!rulecolor, + \c!foregroundcolor=, + \c!foregroundstyle=\tabulationparameter\c!headstyle] + +\protect \endinput diff --git a/tex/context/base/mkiv/type-ini.mklx b/tex/context/base/mkiv/type-ini.mklx new file mode 100644 index 000000000..67dbb7f6d --- /dev/null +++ b/tex/context/base/mkiv/type-ini.mklx @@ -0,0 +1,618 @@ +%D \module +%D [ file=type-ini, +%D version=2001.03.05, +%D title=\CONTEXT\ Typescript Macros, +%D subtitle=Initialization, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Typescript Macros / Initialization} + +\registerctxluafile{type-ini}{} + +%D The default fontclass is empty. We could demand always using fontclasses, and +%D then make the calling macros simplier (always assume fontclass) but apart from +%D downward compatibility issues, it would make global, class spanning definitions a +%D pain. Some day we will introduce a default class. +%D +%D The \type {type-ini} and \type {font-ini} modules come as a pair and have mutual +%D dependencies. +%D +%D At some point we will only store in memory so some code can go away. + +\unprotect + +\definesystemvariable {ts} % TypeScript / for the moment we keep this one + +\newcount \c_font_typescripts_n_of_preloaded +\newconditional\c_font_typescripts_quit +\newtoks \c_font_typescripts_document +\newconditional\c_font_typescripts_preload +\newconditional\c_font_typescripts_first_pass \settrue\c_font_typescripts_first_pass + +\newif \iftypescriptfound % will become a mode +\newif \iftracetypescripts + +\newtoks \everybeforedefinetypeface +\newtoks \everyafterdefinetypeface + +\let\typescriptfiles \empty +\let\currenttypescripts\empty +\let\currenttypefile \empty + +\installmacrostack\currenttypefile + +\let\typescriptone \empty % public, used in typescripts +\let\typescripttwo \empty % public, used in typescripts +\let\typescriptthree\empty % public, used in typescripts + +\installmacrostack\typescriptone +\installmacrostack\typescripttwo +\installmacrostack\typescriptthree + +\let\fontclassstyle \empty + +\installmacrostack\fontclassstyle + +\let\m_font_typescripts_one \empty +\let\m_font_typescripts_two \empty +\let\m_font_typescripts_three\empty +\let\m_font_typescripts_check\empty +\let\m_font_typescripts_match\empty + +\installmacrostack\m_font_typescripts_one +\installmacrostack\m_font_typescripts_two +\installmacrostack\m_font_typescripts_three + +\let\t_font_typescripts\relax % uses as synonym + +\installcorenamespace{typescriptcache} +\installcorenamespace{typescriptfiles} +\installcorenamespace{typescriptonce} +\installcorenamespace{typescriptsynonyms} +\installcorenamespace{typescriptprefix} +\installcorenamespace{typescriptinheritances} +\installcorenamespace{typescriptdefaultstyles} +\installcorenamespace{typescriptrelatives} + +\definesystemvariable{ts} % TypeScript + +% tricky ... here we push/pop ... so \let + +\let\typescriptmethod\plusone % 1: empty==all==true 2: empty==false +\let\typescriptstate \plustwo % 1: process 2: store + +\installmacrostack\typescriptmethod +\installmacrostack\typescriptstate + +\unexpanded\def\starttypescriptcollection + {\dosingleempty\font_typescripts_collection_start} + +\def\font_typescripts_collection_start[#tag]% + {} + +\let\stoptypescriptcollection\relax + +\unexpanded\def\usetypescriptfile[#filename]% + {\doifelse{#filename}\v!reset + {\let\typescriptfiles\empty} + {\splitfilename{#filename}% + \addtocommalist\splitoffbase\typescriptfiles}} + +\unexpanded\def\usetypescript {\dotripleempty\font_typescripts_use_one} +\unexpanded\def\usetypescriptexact{\dotripleempty\font_typescripts_use_two} + +\def\font_typescripts_use_one{\let\typescriptmethod\plusone\font_typescripts_use} +\def\font_typescripts_use_two{\let\typescriptmethod\plustwo\font_typescripts_use} + +\installmacrostack\stoptypescript + +\unexpanded\def\font_typescripts_use[#one][#two][#three]% + {\push_macro_m_font_typescripts_one + \push_macro_m_font_typescripts_two + \push_macro_m_font_typescripts_three + \edef\m_font_typescripts_one {\truetypescript{#one}}% + \edef\m_font_typescripts_two {\truetypescript{#two}}% + \edef\m_font_typescripts_three{\truetypescript{#three}}% + \push_macro_typescriptone + \push_macro_typescripttwo + \push_macro_typescriptthree + \push_macro_typescriptmethod + \push_macro_typescriptstate + \push_macro_stoptypescript + \typescriptfoundfalse + \let\typescriptstate\plusone % why + \iftracetypescripts + \writestatus\m!fonts{request: [\m_font_typescripts_one] [\m_font_typescripts_two] [\m_font_typescripts_three]}% + \fi + \ifhmode + \font_typescripts_use_inline + \else + \font_typescripts_use_display + \fi + \setfalse\c_font_typescripts_first_pass + \pop_macro_stoptypescript + \pop_macro_typescriptstate + \pop_macro_typescriptmethod + \pop_macro_typescriptthree + \pop_macro_typescripttwo + \pop_macro_typescriptone + \pop_macro_m_font_typescripts_three + \pop_macro_m_font_typescripts_two + \pop_macro_m_font_typescripts_one} + +\def\font_typescripts_use_display + {\processcommacommand[\typescriptfiles]\font_typescripts_load_file + \the\c_font_typescripts_document} + +\let\font_typescripts_use_inline\font_typescripts_use_display + +\unexpanded\def\preloadtypescripts + {\ifproductionrun\settrue\c_font_typescripts_preload\fi} + +\prependtoks + \preloadtypescripts +\to \everyjob + +\unexpanded\def\loadtypescriptfile[#1]% + {\push_macro_typescriptstate + \let\typescriptstate\plustwo % assumes 2 at the outer level + \clf_loadtypescriptfile{#1}% + \pop_macro_typescriptstate} + +\unexpanded\def\loadfoundtypescriptfile#1% + {\startreadingfile + \unprotect + \pushendofline + \input{#1}% + \popendofline + \protect + \stopreadingfile} + +\unexpanded\def\quittypescriptscanning + {\settrue\c_font_typescripts_quit} % public + +\def\font_typescripts_start_store#definitions\stoptypescript + {\global\advance\c_font_typescripts_n_of_preloaded\plusone + \expandafter\normalgdef\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname + {\starttypescript#definitions\stoptypescript}% + \gtoksapp\t_font_typescripts\expandafter + {\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname}} + +\def\font_typescripts_collection_start_store#definitions\stoptypescriptcollection + {\global\advance\c_font_typescripts_n_of_preloaded\plusone + \expandafter\normalgdef\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname + {\starttypescriptcollection#definitions\stoptypescriptcollection}% + \gtoksapp\t_font_typescripts\expandafter + {\csname\??typescriptcache\the\c_font_typescripts_n_of_preloaded\endcsname}} + +\def\font_typescripts_load_file#filename% + {\setfalse\c_font_typescripts_quit + \push_macro_currenttypefile + \def\currenttypefile{#filename}% + \ifconditional\c_font_typescripts_preload + \font_typescript_process_typescript_file_and_store + \else + \font_typescript_process_typescript_file + \fi + \pop_macro_currenttypefile + \ifconditional\c_font_typescripts_quit + \quitcommalist + \setfalse\c_font_typescripts_quit + \fi} + +\def\font_typescript_process_typescript_file_and_store + {\expandafter\let\expandafter\t_font_typescripts\csname\??typescriptfiles\currenttypefile\endcsname + \ifx\t_font_typescripts\relax + \font_typescript_process_typescript_store_indeed + \fi + \the\t_font_typescripts} + +\def\font_typescript_process_typescript_store_indeed + {\newtoks\t_font_typescripts % is \relaxed elsewhere + \begingroup + \let\starttypescript \font_typescripts_start_store + \let\starttypescriptcollection\font_typescripts_collection_start_store + \font_typescript_process_typescript_file + \endgroup + \expandafter\let\csname\??typescriptfiles\currenttypefile\endcsname\t_font_typescripts} + +\def\font_typescript_process_typescript_file + {\clf_doprocesstypescriptfile{\currenttypefile}} + +\unexpanded\def\usetypescriptonce + {\dotripleempty\font_typescripts_use_once} + +\def\font_typescripts_use_once[#one][#two][#three]% + {\ifcsname\??typescriptonce#one:#two:#three\endcsname + \writestatus\m!fonts{once (#one) (#two) (#three)}% + \else + \expandafter\let\csname\??typescriptonce#one:#two:#three\endcsname\relax + \font_typescripts_use[#one][#two][#three]% + \fi} + +% \definetypescriptsynonym[lbr][cmr] + +\unexpanded\def\definetypescriptsynonym + {\dodoubleempty\font_typescripts_synonym_define} + +\def\font_typescripts_synonym_define[#name][#synonym]% + {\ifsecondargument\setevalue{\??typescriptsynonyms#name}{#synonym}\fi} + +\def\truetypescript#name% recursive so no \lastnamedcs + {\ifcsname\??typescriptsynonyms#name\endcsname + %\expandafter\truetypescript\csname\??typescriptsynonyms#name\endcsname + \expandafter\truetypescript\lastnamedcs + \else + #name% + \fi} + +% script [serif] [default] [size] +% script [serif] [computer-modern] [size] +% script [serif] [computer-modern] [ec] +% script [serif] [computer-modern] [name] +% script [serif] [computer-modern] [special] + +\prependtoks + \settrue\c_font_typescripts_first_pass +\to \everyjob + +\unexpanded\def\starttypescript + {\ifcase\typescriptstate + % 0 = skip + \expandafter\font_typescripts_start_gobble + \or + % 1 = process + \expandafter\font_typescripts_start_process + \or + % 2 = store + \expandafter\font_typescripts_start_document + \else + % ? = skip + \expandafter\font_typescripts_start_gobble + \fi} + +\def\font_typescripts_start_gobble#definitions\stoptypescript{} + +\def\font_typescripts_start_document#definitions\stoptypescript + {\toksapp\c_font_typescripts_document{\starttypescript#definitions\stoptypescript}} + +\def\font_typescripts_start_process % could be a faster \doifelsenextoptionalif needed + {\let\typescriptone \m_font_typescripts_one + \let\typescripttwo \m_font_typescripts_two + \let\typescriptthree\m_font_typescripts_three + \let\m_font_typescripts_match\empty + \doifelsenextoptionalcs\font_typescripts_start_process_one\font_typescripts_start_process_all} + +\def\font_typescripts_start_process_all % could be a \let + {\ifconditional\c_font_typescripts_first_pass + \expandafter\font_typescripts_start_process_indeed + \else + % skip this since it may do unwanted resets, like + % setting symbolic font names to unknown, especially + % in run time user type scripts + \expandafter\font_typescripts_start_gobble + \fi} + +\def\font_typescripts_show_match + {\writestatus\m!fonts{match:\ifx\currenttypefile\relax\space *\fi \m_font_typescripts_match}} + +\def\font_typescripts_start_process_yes + {\ifdone + \typescriptfoundtrue + \iftracetypescripts\font_typescripts_show_match\fi + \expandafter\font_typescripts_start_process_indeed + \else + \expandafter\font_typescripts_start_gobble + \fi} + +\def\font_typescripts_start_process_one + {\font_typescripts_check\m_font_typescripts_one\typescriptone\font_typescripts_start_process_again_one} + +\def\font_typescripts_start_process_two + {\font_typescripts_check\m_font_typescripts_two\typescripttwo\font_typescripts_start_process_again_two} + +\def\font_typescripts_start_process_three + {\font_typescripts_check\m_font_typescripts_three\typescriptthree\font_typescripts_start_process_again_three} + +\def\font_typescripts_start_process_again_one + {\doifelsenextoptionalcs\font_typescripts_start_process_two\font_typescripts_start_process_yes} + +\def\font_typescripts_start_process_again_two + {\doifelsenextoptionalcs\font_typescripts_start_process_three\font_typescripts_start_process_yes} + +\let\font_typescripts_start_process_again_three\font_typescripts_start_process_yes + +\def\font_typescripts_start_process_indeed + {\push_macro_fontclass} + +\unexpanded\def\stoptypescript + {\pop_macro_fontclass} + +\def\font_typescripts_check#asked#target#followup[#value]% script use value next + {\donefalse + \edef\m_font_typescripts_check{#value}% + \ifx\m_font_typescripts_check\empty % no longer needed / met + \ifcase\typescriptmethod\or\donetrue\fi + \orelse\ifx#asked\s!all + \donetrue + \orelse\ifx\m_font_typescripts_check\s!all + \donetrue + \orelse\ifx#asked\m_font_typescripts_check % saves 10% trace so probably faster too + \donetrue + \let#target\m_font_typescripts_check + \else + \doifelsecommon\m_font_typescripts_check#asked\donetrue\donefalse + \ifdone + \let#target\commalistelement + \fi + \fi + \ifdone + \iftracetypescripts\extendtypescriptmatch\fi + \expandafter#followup% + \else + \expandafter\font_typescripts_start_gobble + \fi} + +\def\extendtypescriptmatch + {\edef\m_font_typescripts_match{\m_font_typescripts_match\space[\m_font_typescripts_check]}} + +%D Map files will go away in \LUATEX, but till that happens we use stripped down +%D support for loading them. + +\unexpanded\def\loadmapfile{\dosingleempty\font_map_load_file} +\unexpanded\def\loadmapline{\dodoubleempty\font_map_load_line} + +\def\font_map_load_file[#filename]% + {\clf_loadmapfile{#filename}} + +\def\font_map_load_line[#kind][#data]% + {\clf_loadmapline{#kind}{#data}} + +\unexpanded\def\forgetmapfiles + {\clf_resetmapfiles} + +% \prependtoks +% \loadmapfile[mkiv-base.map]% can't we preload this one? +% \to \everystarttext + +%D A handy shortcut: + +% \definetypescriptprefix[serif][Serif] +% \definetypescriptprefix[sans] [Sans] +% \definetypescriptprefix[mono] [Mono] +% +% \starttypescript [serif,sans,mono] [handling,hanging,hz] [pure,normal,hz,quality] +% \setupfontsynonym [\typescriptprefix\typescriptone] [handling=\typescriptthree] +% \stoptypescript + +\unexpanded\def\definetypescriptprefix + {\dodoubleargument\font_typescripts_define_prefix} + +\def\font_typescripts_define_prefix[#name][#prefix]% + {\setgvalue{\??typescriptprefix#name}{#prefix}} % made global + +\def\typescriptprefix#name% + %{\ifcsname\??typescriptprefix#name\endcsname\csname\??typescriptprefix#name\endcsname\else#name\fi} + {\ifcsname\??typescriptprefix#name\endcsname\lastnamedcs\else#name\fi} + +% defining typefaces: +% +% \definetypeface [joke] [rm] +% \definetypeface [joke] [rm] [settings] +% \definetypeface [joke] [rm] [serif] [lucida] +% \definetypeface [joke] [rm] [serif] [lucida] [size] +% \definetypeface [joke] [rm] [serif] [lucida] [size] [settings] +% \definetypeface [joke] [specification] + +\unexpanded\def\definetypeface + {\dosixtupleargument\font_typefaces_define} + +\appendtoks + \font_helpers_reset_fontclass_math_families\fontclass +\to \everybeforedefinetypeface + +%D This hooks into the font switcher: + +\settrue\autotypescripts + +\unexpanded\def\trycurrentfontclass#typeface% + {\ifconditional\autotypescripts + \usetypescript[#typeface]% + \ifcsname\??fontclassyes#typeface\endcsname + \edef\fontclass{#typeface}% + \else + \iftracetypescripts\writestatus\m!fonts{auto load typescript file 1: [#typeface]}\fi + \usetypescriptfile[#typeface]% + \usetypescript[#typeface]% + \ifcsname\??fontclassyes#typeface\endcsname + \edef\fontclass{#typeface}% + \else + % todo: message + \letvalueempty{\??fontclassnop#typeface}% + \fi + \fi + \else + % todo: message + \letvalueempty{\??fontclassnop#typeface}% + \fi} + +%D Now we define: + +\def\font_typefaces_define + {\iffifthargument + \expandafter\font_typefaces_define_a + \orelse\iffourthargument + \expandafter\font_typefaces_define_b + \orelse\ifthirdargument + \expandafter\font_typefaces_define_c + \else + \expandafter\font_typefaces_define_d + \fi} + +\def\font_typefaces_define_a[#name][#style][#fontshape][#fontname][#fontsize][#settings]% + {\iftracetypescripts\writestatus\m!fonts{define: [#name] [#style] [#fontshape] [#fontname]}\fi + \font_typefaces_define_indeed[#name][#style]% + \font_typefaces_defining_start{#name}{#style}{#settings}% + \font_typescripts_use_one[#fontshape][#fontname][\s!name]% [\s!name,\s!default]% + \iftypescriptfound + % we're okay + \orelse\ifconditional\autotypescripts + \iftracetypescripts\writestatus\m!fonts{auto load typescript file 2: [#fontname]}\fi + \usetypescriptfile[#fontname]% + \font_typescripts_use_one[#fontshape][#fontname][\s!name]% [\s!name,\s!default]% + \fi + \font_typescripts_use_one[#fontshape][#fontsize][\s!size]% + \font_typefaces_defining_stop} + +\def\font_typefaces_define_b[#name][#style][#fontshape][#fontname][#dummya][#dummyb]% + {\font_typefaces_define_a[#name][#style][#fontshape][#fontname][\s!default][#dummyb]} + +\def\font_typefaces_define_c[#name][#style][#dummya][#dummyb][#dummyc][#dummyd]% + {\font_typefaces_define_indeed[#name][#style]} + +\def\font_typefaces_define_d[#name][#specification][#dummya][#dummyb][#dummyc][#dummyd]% use definitions in lfg file + {\clf_definetypeface{#name}{#specification}} + +\def\font_typefaces_define_indeed[#name][#style]% saveguard against redefinition + {\doifsomething{#name} + {\ifcsname\??typescriptdefaultstyles#name\endcsname \else + \registerfontclass{#name}% + \setxvalue{\??typescriptdefaultstyles#name}{#style}% + \fi + \ifcsname#name\endcsname \else + \setugvalue{#name}{\switchtotypeface[#name][#style]}% + \fi}} + +\def\font_typefaces_defining_start#name#style#settings% + {\let\@@tsrscale \!!plusone % as we push/pop + \let\@@tsfeatures \empty + \let\@@tsfallbacks \empty + \let\@@tsgoodies \empty + \let\@@tsdirection \empty + \let\@@tsdesignsize\empty + \geteparameters[\??ts][#settings]% todo raw + \push_macro_fontclass + \push_macro_fontclassstyle + \setcurrentfontclass{#name}% + \savefontclassparameters{#style}\@@tsrscale\@@tsfeatures\@@tsfallbacks\@@tsgoodies\@@tsdesignsize\@@tsdirection + \the\everybeforedefinetypeface} + +\def\tsvar#key#default% undocumented and unofficial + {\expandafter\ifx\csname\??ts#key\endcsname\empty + #default% + \else + \csname\??ts#key\endcsname + \fi} + +\def\font_typefaces_defining_stop + {\the\everyafterdefinetypeface + \pop_macro_fontclassstyle + \pop_macro_fontclass} + +\def\dofastdefinetypeface#name#style#fontshape#fontsize#settings% called from the lua end (via case d) + {\font_typefaces_define_indeed[#name][#style]% + \font_typefaces_defining_start{#name}{#style}{#settings}% + \font_typescripts_use_one[#fontshape][#fontsize][\s!size]% + \font_typefaces_defining_stop} + +\unexpanded\def\setuptypeface% [class] [settings] + {\dodoubleempty\font_typefaces_setup} + +\unexpanded\def\switchtotypeface% [class] [settings] + {\dodoubleempty\font_typefaces_switch} + +\def\font_typefaces_setup[#class][#settings]% + {\setcurrentfontclass{#class}% + \let\globalfontclass\fontclass + \ifsecondargument + \setupbodyfont[#settings]% + \orelse\ifx\fontclass\empty + \setupbodyfont[\s!rm]% + \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname + %\setupbodyfont[\csname\??typescriptdefaultstyles\fontclass\endcsname]% + \expandafter\setupbodyfont\expandafter[\lastnamedcs]% + \else + \setupbodyfont[\s!rm]% + \fi + \ifmmode\mr\else\tf\fi} % needed ? + +\def\font_typefaces_switch[#class][#settings]% + {\setcurrentfontclass{#class}% + \let\globalfontclass\globalfontclass + \ifsecondargument + \switchtobodyfont[#settings]% + \orelse\ifx\fontclass\empty + \switchtobodyfont[\s!rm]% + \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname + %\switchtobodyfont[\csname\??typescriptdefaultstyles\fontclass\endcsname]% + \expandafter\switchtobodyfont\expandafter[\lastnamedcs]% + \else + \switchtobodyfont[\s!rm]% + \fi + \ifmmode\mr\else\tf\fi} % needed ? + +%D For Taco: +%D +%D \starttyping +%D \inherittypeface[palatino][rm][postscript] +%D \inherittypeface[palatino][rm][\fontclass] +%D \inherittypeface[palatino][rm] % == \fontclass +%D \inherittypeface[palatino] % == [rm,ss,tt,mm] +%D \stoptyping + +\unexpanded\def\inherittypeface + {\dotripleempty\font_typescripts_inherit_indeed} + +\def\font_typescripts_inherit_indeed[#name][#styles][#parentclass]% + {\doifelsenothing{#styles} + {\font_typescripts_inherit_indeed[#name][\s!rm,\s!ss,\s!tt,\s!mm][\fontclass]} + {\doifnot{#name}{#parentclass} + {\glet\font_typescripts_inherit_check\font_typescripts_inherit_check_indeed + \def\font_typescripts_inherit_check_step#style{\setevalue{\??typescriptinheritances#name:#style}{#parentclass}}% + \processcommalist[#styles]\font_typescripts_inherit_check_step}}} + +\let\font_typescripts_inherit_check_step\relax + +%D This hooks into the font mechanism with: + +\def\font_typescripts_inherit_check_indeed#name% called often + {\ifcsname\??typescriptinheritances\fontclass:#name\endcsname + %\expandafter\let\expandafter\fontclass\csname\??typescriptinheritances\fontclass:#name\endcsname + \expandafter\let\expandafter\fontclass\lastnamedcs + \fi} + +\let\font_typescripts_inherit_check\gobbleoneargument + +% not yet: +% +% \def\font_helpers_check_relative_font_id +% {\ifcsname\??typescriptrelatives\fontclass\endcsname +% \expandafter\let\expandafter\relativefontid\csname\??typescriptrelatives\fontclass\endcsname +% \else +% \expandafter\normalxdef\csname\??typescriptrelatives\fontclass\endcsname{\the\lastfontid}% +% \let\relativefontid\minusone +% \fi} + +\def\v_font_string_d % default fontstyle (expands to \s!Serif in font-ini) + {\expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!rm \s!Serif \else + \expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!ss \s!Sans \else + \expandafter\ifx\csname\??typescriptdefaultstyles\fontclass\endcsname\s!tt \s!Mono \else + \s!Serif \fi\fi\fi} + +\unexpanded\def\font_helpers_set_fontstyle_of_fontclass + {\ifx\fontclass\empty + \let\fontstyle\s!rm + \orelse\ifcsname\??typescriptdefaultstyles\fontclass\endcsname + %\edef\fontstyle{\csname\??typescriptdefaultstyles\fontclass\endcsname}% + \edef\fontstyle{\lastnamedcs}% + \else + \let\fontstyle\s!rm + \fi} + +\protect \endinput diff --git a/tex/context/base/mkiv/type-ini.mkvi b/tex/context/base/mkiv/type-ini.mkvi index 8cb370f58..6f0a9a9da 100644 --- a/tex/context/base/mkiv/type-ini.mkvi +++ b/tex/context/base/mkiv/type-ini.mkvi @@ -15,13 +15,13 @@ \registerctxluafile{type-ini}{} -%D The default fontclass is empty. We could demand always using fontclasses, -%D and then make the calling macros simplier (always assume fontclass) but -%D apart from downward compatibility issues, it would make global, class -%D spanning definitions a pain. Some day we will introduce a default class. +%D The default fontclass is empty. We could demand always using fontclasses, and +%D then make the calling macros simplier (always assume fontclass) but apart from +%D downward compatibility issues, it would make global, class spanning definitions a +%D pain. Some day we will introduce a default class. %D -%D The \type {type-ini} and \type {font-ini} modules come as a pair and have -%D mutual dependencies. +%D The \type {type-ini} and \type {font-ini} modules come as a pair and have mutual +%D dependencies. %D %D At some point we will only store in memory so some code can go away. @@ -183,8 +183,8 @@ \preloadtypescripts \to \everyjob -% The next will change .. we can load a file inside a typescript but as the state is -% 1 then, it doesn't get stored without doing that explicitly +%D The next will change .. we can load a file inside a typescript but as the state is +%D 1 then, it doesn't get stored without doing that explicitly \unexpanded\def\loadtypescriptfile[#1]% {\push_macro_typescriptstate @@ -412,8 +412,8 @@ \def\extendtypescriptmatch {\edef\m_font_typescripts_match{\m_font_typescripts_match\space[\m_font_typescripts_check]}} -%D Map files will go away in \LUATEX, but till that happens we -%D use stripped down support for loading them. +%D Map files will go away in \LUATEX, but till that happens we use stripped down +%D support for loading them. \unexpanded\def\loadmapfile{\dosingleempty\font_map_load_file} \unexpanded\def\loadmapline{\dodoubleempty\font_map_load_line} diff --git a/tex/context/base/mkiv/util-sci.lua b/tex/context/base/mkiv/util-sci.lua index d58b3387f..a3fcbc928 100644 --- a/tex/context/base/mkiv/util-sci.lua +++ b/tex/context/base/mkiv/util-sci.lua @@ -40,7 +40,7 @@ local knownlexers = { mkii = "tex", bib = "bibtex", cld = "tex", - lua = "lua", + lua = "lua", lmt = "lua", lfg = "lua", lus = "lua", luv = "lua", mp = "mps", mpiv = "mps", diff --git a/tex/context/base/mkiv/util-str.lua b/tex/context/base/mkiv/util-str.lua index 5470c2fd6..ad22302df 100644 --- a/tex/context/base/mkiv/util-str.lua +++ b/tex/context/base/mkiv/util-str.lua @@ -584,6 +584,26 @@ local template = [[ return function(%s) return %s end ]] +-- this might move + +local pattern = Cs(Cc('"') * ( + (1-S('"\\\n\r'))^1 + + P('"') / '\\"' + + P('\\') / '\\\\' + + P('\n') / '\\n' + + P('\r') / '\\r' +)^0 * Cc('"')) + +patterns.escapedquotes = pattern + +function string.escapedquotes(s) + return lpegmatch(pattern,s) +end + +-- print(string.escapedquotes('1\\23\n"')) + +-- but for now here + local preamble = "" local environment = { @@ -611,6 +631,7 @@ local environment = { formattedfloat = number.formattedfloat, stripzero = patterns.stripzero, stripzeros = patterns.stripzeros, + escapedquotes = string.escapedquotes, FORMAT = string.f9, } @@ -685,11 +706,13 @@ local format_q = function() -- lua 5.3 has a different q than lua 5.2 (which does a tostring on numbers) -- return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n) return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) + -- return format("(a%s ~= nil and escapedquotes(tostring(a%s)) or '')",n,n) end -local format_Q = function() -- can be optimized +local format_Q = function() -- fast escaping n = n + 1 - return format("format('%%q',tostring(a%s))",n) +-- return format("format('%%q',tostring(a%s))",n) + return format("escapedquotes(tostring(a%s))",n) end local format_i = function(f) diff --git a/tex/context/base/mkiv/util-tab.lua b/tex/context/base/mkiv/util-tab.lua index 2f425cca3..f970d8ace 100644 --- a/tex/context/base/mkiv/util-tab.lua +++ b/tex/context/base/mkiv/util-tab.lua @@ -314,21 +314,21 @@ end -- best keep [%q] keys (as we have some in older applications i.e. saving user data (otherwise -- we also need to check for reserved words) -local f_hashed_string = formatters["[%q]=%q,"] -local f_hashed_number = formatters["[%q]=%s,"] -local f_hashed_boolean = formatters["[%q]=%l,"] -local f_hashed_table = formatters["[%q]="] +local f_hashed_string = formatters["[%Q]=%Q,"] +local f_hashed_number = formatters["[%Q]=%s,"] +local f_hashed_boolean = formatters["[%Q]=%l,"] +local f_hashed_table = formatters["[%Q]="] -local f_indexed_string = formatters["[%s]=%q,"] +local f_indexed_string = formatters["[%s]=%Q,"] local f_indexed_number = formatters["[%s]=%s,"] local f_indexed_boolean = formatters["[%s]=%l,"] local f_indexed_table = formatters["[%s]="] -local f_ordered_string = formatters["%q,"] +local f_ordered_string = formatters["%Q,"] local f_ordered_number = formatters["%s,"] local f_ordered_boolean = formatters["%l,"] -function table.fastserialize(t,prefix) +function table.fastserialize(t,prefix) -- todo, move local function out -- prefix should contain the = -- not sorted @@ -525,27 +525,27 @@ local f_start_key_nop = formatters["%w{"] local f_stop = formatters["%w},"] local f_key_num_value_num = formatters["%w[%s]=%s,"] -local f_key_str_value_num = formatters["%w[%q]=%s,"] +local f_key_str_value_num = formatters["%w[%Q]=%s,"] local f_key_boo_value_num = formatters["%w[%l]=%s,"] -local f_key_num_value_str = formatters["%w[%s]=%q,"] -local f_key_str_value_str = formatters["%w[%q]=%q,"] -local f_key_boo_value_str = formatters["%w[%l]=%q,"] +local f_key_num_value_str = formatters["%w[%s]=%Q,"] +local f_key_str_value_str = formatters["%w[%Q]=%Q,"] +local f_key_boo_value_str = formatters["%w[%l]=%Q,"] local f_key_num_value_boo = formatters["%w[%s]=%l,"] -local f_key_str_value_boo = formatters["%w[%q]=%l,"] +local f_key_str_value_boo = formatters["%w[%Q]=%l,"] local f_key_boo_value_boo = formatters["%w[%l]=%l,"] local f_key_num_value_not = formatters["%w[%s]={},"] -local f_key_str_value_not = formatters["%w[%q]={},"] +local f_key_str_value_not = formatters["%w[%Q]={},"] local f_key_boo_value_not = formatters["%w[%l]={},"] local f_key_num_value_seq = formatters["%w[%s]={ %, t },"] -local f_key_str_value_seq = formatters["%w[%q]={ %, t },"] +local f_key_str_value_seq = formatters["%w[%Q]={ %, t },"] local f_key_boo_value_seq = formatters["%w[%l]={ %, t },"] local f_val_num = formatters["%w%s,"] -local f_val_str = formatters["%w%q,"] +local f_val_str = formatters["%w%Q,"] local f_val_boo = formatters["%w%l,"] local f_val_not = formatters["%w{},"] local f_val_seq = formatters["%w{ %, t },"] @@ -554,7 +554,7 @@ local f_fin_seq = formatters[" %, t }"] local f_table_return = formatters["return {"] local f_table_name = formatters["%s={"] local f_table_direct = formatters["{"] -local f_table_entry = formatters["[%q]={"] +local f_table_entry = formatters["[%Q]={"] local f_table_finish = formatters["}"] ----- f_string = formatters["%q"] diff --git a/tex/context/interface/mkii/keys-it.xml b/tex/context/interface/mkii/keys-it.xml index c852ae515..ac2816578 100644 --- a/tex/context/interface/mkii/keys-it.xml +++ b/tex/context/interface/mkii/keys-it.xml @@ -150,6 +150,7 @@ + @@ -480,6 +481,7 @@ + @@ -641,6 +643,7 @@ + @@ -738,7 +741,9 @@ + + diff --git a/tex/context/interface/mkiv/context-en.xml b/tex/context/interface/mkiv/context-en.xml index 9b1c7f57b..e90ec342e 100644 --- a/tex/context/interface/mkiv/context-en.xml +++ b/tex/context/interface/mkiv/context-en.xml @@ -652,6 +652,9 @@ + + + @@ -2432,7 +2435,7 @@ - + @@ -2440,7 +2443,7 @@ - + @@ -2448,7 +2451,7 @@ - + @@ -2464,7 +2467,23 @@ - + + + + + + + + + + + + + + + + + @@ -2472,7 +2491,47 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2711,6 +2770,14 @@ + + + + + + + + @@ -2719,6 +2786,14 @@ + + + + + + + + @@ -2727,6 +2802,14 @@ + + + + + + + + @@ -2735,6 +2818,14 @@ + + + + + + + + @@ -2743,6 +2834,14 @@ + + + + + + + + @@ -2751,6 +2850,14 @@ + + + + + + + + @@ -3574,6 +3681,13 @@ + + + + + + + @@ -3595,6 +3709,20 @@ + + + + + + + + + + + + + + @@ -5190,106 +5318,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -6336,7 +6364,7 @@ - + @@ -6493,6 +6521,7 @@ + @@ -6673,6 +6702,13 @@ + + + + + + + @@ -7857,22 +7893,6 @@ - - - - - - - - - - - - - - - - @@ -10068,14 +10088,50 @@ - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + @@ -10542,6 +10598,17 @@ + + + + + + + + + + + @@ -10620,6 +10687,17 @@ + + + + + + + + + + + @@ -10705,6 +10783,17 @@ + + + + + + + + + + + @@ -10798,6 +10887,17 @@ + + + + + + + + + + + @@ -10872,6 +10972,17 @@ + + + + + + + + + + + @@ -11130,6 +11241,17 @@ + + + + + + + + + + + @@ -14622,7 +14744,7 @@ - + @@ -16825,6 +16947,8 @@ + + @@ -17808,6 +17932,18 @@ + + + + + + + + + + + + @@ -17915,7 +18051,214 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -17930,10 +18273,215 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22304,6 +22852,14 @@ + + + + + + + + @@ -22312,6 +22868,14 @@ + + + + + + + + @@ -22320,6 +22884,14 @@ + + + + + + + + @@ -22715,6 +23287,8 @@ + + @@ -22922,6 +23496,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22931,6 +23537,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22945,6 +23601,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23064,6 +23770,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -23078,6 +23834,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -24446,8 +25252,16 @@ + + + + + + + + @@ -25678,6 +26492,13 @@ + + + + + + + @@ -25974,6 +26795,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -26925,7 +27794,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + @@ -27201,7 +28092,17 @@ - + + + + + + + + + + + @@ -28164,6 +29065,7 @@ + @@ -33560,6 +34462,7 @@ + @@ -33774,6 +34677,8 @@ + + @@ -33950,7 +34855,212 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -33961,7 +35071,212 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -34056,7 +35371,212 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -34079,10 +35599,10 @@ - - - - + + + + @@ -34258,10 +35778,10 @@ - - - - + + + + @@ -35128,6 +36648,10 @@ + + + + @@ -35321,6 +36845,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -36162,6 +37714,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -36986,6 +38565,16 @@ + + + + + + + + + + @@ -43051,7 +44640,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43063,7 +44704,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43075,7 +44768,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43087,7 +44832,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43099,7 +44896,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45822,6 +47671,9 @@ + + + diff --git a/tex/context/interface/mkiv/i-attachment.xml b/tex/context/interface/mkiv/i-attachment.xml index 85cf8843b..550cc57ce 100644 --- a/tex/context/interface/mkiv/i-attachment.xml +++ b/tex/context/interface/mkiv/i-attachment.xml @@ -36,6 +36,9 @@ + + + diff --git a/tex/context/interface/mkiv/i-boxes.xml b/tex/context/interface/mkiv/i-boxes.xml index e89be4fd0..39034e32b 100644 --- a/tex/context/interface/mkiv/i-boxes.xml +++ b/tex/context/interface/mkiv/i-boxes.xml @@ -725,21 +725,21 @@ - + - + - + @@ -753,14 +753,63 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -950,6 +999,13 @@ + + + + + + + @@ -957,6 +1013,13 @@ + + + + + + + @@ -964,6 +1027,13 @@ + + + + + + + @@ -971,6 +1041,13 @@ + + + + + + + @@ -978,6 +1055,13 @@ + + + + + + + @@ -985,6 +1069,13 @@ + + + + + + + diff --git a/tex/context/interface/mkiv/i-capitals.xml b/tex/context/interface/mkiv/i-capitals.xml index 4cfb4a080..6115b1519 100644 --- a/tex/context/interface/mkiv/i-capitals.xml +++ b/tex/context/interface/mkiv/i-capitals.xml @@ -167,6 +167,12 @@ + + + + + + @@ -185,6 +191,18 @@ + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-chart.xml b/tex/context/interface/mkiv/i-chart.xml index 7f0a51393..43672efa0 100644 --- a/tex/context/interface/mkiv/i-chart.xml +++ b/tex/context/interface/mkiv/i-chart.xml @@ -541,4 +541,4 @@ - + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-columns.xml b/tex/context/interface/mkiv/i-columns.xml index bbc022ac6..aa290a0a9 100644 --- a/tex/context/interface/mkiv/i-columns.xml +++ b/tex/context/interface/mkiv/i-columns.xml @@ -34,10 +34,10 @@ - + - + @@ -81,7 +81,7 @@ - + @@ -103,9 +103,9 @@ - + - + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-common-argument.xml b/tex/context/interface/mkiv/i-common-argument.xml index de000148b..da821c516 100644 --- a/tex/context/interface/mkiv/i-common-argument.xml +++ b/tex/context/interface/mkiv/i-common-argument.xml @@ -524,7 +524,7 @@ - + @@ -532,4 +532,26 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-common-instance.xml b/tex/context/interface/mkiv/i-common-instance.xml index dc8cead79..3d4864de7 100644 --- a/tex/context/interface/mkiv/i-common-instance.xml +++ b/tex/context/interface/mkiv/i-common-instance.xml @@ -187,6 +187,7 @@ + diff --git a/tex/context/interface/mkiv/i-common-string.xml b/tex/context/interface/mkiv/i-common-string.xml index 5ef1fc71a..0c0bb2ef3 100644 --- a/tex/context/interface/mkiv/i-common-string.xml +++ b/tex/context/interface/mkiv/i-common-string.xml @@ -169,4 +169,26 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-common-value.xml b/tex/context/interface/mkiv/i-common-value.xml index a6884185f..253a03ccf 100644 --- a/tex/context/interface/mkiv/i-common-value.xml +++ b/tex/context/interface/mkiv/i-common-value.xml @@ -301,6 +301,17 @@ + + + + + + + + + + + @@ -770,4 +781,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf index 237b4ec2b..e1c0e85ae 100644 Binary files a/tex/context/interface/mkiv/i-context.pdf and b/tex/context/interface/mkiv/i-context.pdf differ diff --git a/tex/context/interface/mkiv/i-context.xml b/tex/context/interface/mkiv/i-context.xml index 01adac436..53741ad55 100644 --- a/tex/context/interface/mkiv/i-context.xml +++ b/tex/context/interface/mkiv/i-context.xml @@ -53,7 +53,6 @@ - @@ -198,6 +197,7 @@ + diff --git a/tex/context/interface/mkiv/i-conversion.xml b/tex/context/interface/mkiv/i-conversion.xml index a2e975368..9226693a2 100644 --- a/tex/context/interface/mkiv/i-conversion.xml +++ b/tex/context/interface/mkiv/i-conversion.xml @@ -360,7 +360,7 @@ - + @@ -502,6 +502,7 @@ + @@ -642,4 +643,10 @@ + + + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-direction.xml b/tex/context/interface/mkiv/i-direction.xml index 3b2d937a4..87e64e457 100644 --- a/tex/context/interface/mkiv/i-direction.xml +++ b/tex/context/interface/mkiv/i-direction.xml @@ -52,22 +52,4 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-fittingpage.xml b/tex/context/interface/mkiv/i-fittingpage.xml index 7fc3a6cff..f5daafcf1 100644 --- a/tex/context/interface/mkiv/i-fittingpage.xml +++ b/tex/context/interface/mkiv/i-fittingpage.xml @@ -4,6 +4,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -17,27 +41,7 @@ - - - - - - - - - - - - - - - - - - - - - + @@ -66,17 +70,17 @@ - diff --git a/tex/context/interface/mkiv/i-math.xml b/tex/context/interface/mkiv/i-math.xml index ae8fa1c3e..888d2bac5 100644 --- a/tex/context/interface/mkiv/i-math.xml +++ b/tex/context/interface/mkiv/i-math.xml @@ -139,6 +139,15 @@ + + + + + + + + + @@ -146,6 +155,15 @@ + + + + + + + + + @@ -153,6 +171,15 @@ + + + + + + + + + @@ -310,6 +337,31 @@ + + @@ -511,4 +563,8 @@ + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-mathfence.xml b/tex/context/interface/mkiv/i-mathfence.xml index 5e1abec2b..a214c3bfd 100644 --- a/tex/context/interface/mkiv/i-mathfence.xml +++ b/tex/context/interface/mkiv/i-mathfence.xml @@ -69,7 +69,48 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -78,7 +119,7 @@ - + @@ -90,7 +131,7 @@ - + @@ -192,7 +233,7 @@ - + @@ -204,7 +245,7 @@ - + diff --git a/tex/context/interface/mkiv/i-mixedcolumns.xml b/tex/context/interface/mkiv/i-mixedcolumns.xml index 4e1ab9625..701375237 100644 --- a/tex/context/interface/mkiv/i-mixedcolumns.xml +++ b/tex/context/interface/mkiv/i-mixedcolumns.xml @@ -131,4 +131,12 @@ --> - \ No newline at end of file + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-note.xml b/tex/context/interface/mkiv/i-note.xml index 03e53a0e3..ee1ac5a31 100644 --- a/tex/context/interface/mkiv/i-note.xml +++ b/tex/context/interface/mkiv/i-note.xml @@ -413,6 +413,14 @@ + + + + + + + + @@ -708,4 +716,47 @@ --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-pagegrid.xml b/tex/context/interface/mkiv/i-pagegrid.xml index f25e72f72..8b2cd86b9 100644 --- a/tex/context/interface/mkiv/i-pagegrid.xml +++ b/tex/context/interface/mkiv/i-pagegrid.xml @@ -277,7 +277,29 @@ - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-pagenumber.xml b/tex/context/interface/mkiv/i-pagenumber.xml index 4c262db4b..91c0d8f59 100644 --- a/tex/context/interface/mkiv/i-pagenumber.xml +++ b/tex/context/interface/mkiv/i-pagenumber.xml @@ -4,6 +4,22 @@ + + + + + + + + + + + + + + + + @@ -14,19 +30,7 @@ - - - - - - - - - - - - - + @@ -40,9 +44,7 @@ - - - + diff --git a/tex/context/interface/mkiv/i-paragraphs.xml b/tex/context/interface/mkiv/i-paragraphs.xml index 0d8ae3d2e..e2fc9116e 100644 --- a/tex/context/interface/mkiv/i-paragraphs.xml +++ b/tex/context/interface/mkiv/i-paragraphs.xml @@ -79,6 +79,7 @@ + diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf index 3822e876e..9fa13268b 100644 Binary files a/tex/context/interface/mkiv/i-readme.pdf and b/tex/context/interface/mkiv/i-readme.pdf differ diff --git a/tex/context/interface/mkiv/i-register.xml b/tex/context/interface/mkiv/i-register.xml index 7ba3a0f7c..e5ddfd821 100644 --- a/tex/context/interface/mkiv/i-register.xml +++ b/tex/context/interface/mkiv/i-register.xml @@ -4,6 +4,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -18,174 +190,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -195,173 +200,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -369,9 +208,7 @@ - - - + @@ -381,9 +218,7 @@ - - - + @@ -478,9 +313,7 @@ - - - + @@ -489,63 +322,25 @@ + - - - - - + + diff --git a/tex/context/interface/mkiv/i-section.xml b/tex/context/interface/mkiv/i-section.xml index b4229d5fd..0ec20a804 100644 --- a/tex/context/interface/mkiv/i-section.xml +++ b/tex/context/interface/mkiv/i-section.xml @@ -246,6 +246,10 @@ + + + + @@ -319,6 +323,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-simplecolumns.xml b/tex/context/interface/mkiv/i-simplecolumns.xml new file mode 100644 index 000000000..caefa9fbb --- /dev/null +++ b/tex/context/interface/mkiv/i-simplecolumns.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tex/context/interface/mkiv/i-symbol.xml b/tex/context/interface/mkiv/i-symbol.xml index 498684cad..64a6f27dd 100644 --- a/tex/context/interface/mkiv/i-symbol.xml +++ b/tex/context/interface/mkiv/i-symbol.xml @@ -147,4 +147,15 @@ - \ No newline at end of file + + + + + + + + + + + + diff --git a/tex/context/interface/mkiv/i-texts.xml b/tex/context/interface/mkiv/i-texts.xml index f0f515fbc..f13d88021 100644 --- a/tex/context/interface/mkiv/i-texts.xml +++ b/tex/context/interface/mkiv/i-texts.xml @@ -4,97 +4,68 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -105,197 +76,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - + + - - - - - - - - + + - - - - - - - - + + - - - - - - - - + + - - - - - - - - + + diff --git a/tex/context/interface/mkiv/i-vspace.xml b/tex/context/interface/mkiv/i-vspace.xml index 5e970d317..e79e4e736 100644 --- a/tex/context/interface/mkiv/i-vspace.xml +++ b/tex/context/interface/mkiv/i-vspace.xml @@ -140,4 +140,10 @@ + + + + + + diff --git a/tex/context/modules/mkiv/m-scite.mkiv b/tex/context/modules/mkiv/m-scite.mkiv index 9182fa2ec..4fb7ea029 100644 --- a/tex/context/modules/mkiv/m-scite.mkiv +++ b/tex/context/modules/mkiv/m-scite.mkiv @@ -289,6 +289,7 @@ visualizers.register("cld", visualizer) visualizers.register("tex", visualizer) visualizers.register("lua", visualizer) visualizers.register("mps", visualizer) +visualizers.register("mp", visualizer) visualizers.register("pdf", visualizer) visualizers.register("xml", visualizer) visualizers.register("bibtex",visualizer) @@ -306,7 +307,7 @@ visualizers.register("json", visualizer) \definetyping[LUA] [option=lua] \definetyping[BTX] [option=bibtex] \definetyping[MPS] [option=mps] -\definetyping[MP] [option=mps] +\definetyping[MP] [option=mp] \definetyping[PDF] [option=pdf] \definetyping[CPP] [option=web] \definetyping[WEB] [option=web] diff --git a/tex/context/modules/mkiv/s-fonts-system.lua b/tex/context/modules/mkiv/s-fonts-system.lua index dc0f2e6a3..8e55184e0 100644 --- a/tex/context/modules/mkiv/s-fonts-system.lua +++ b/tex/context/modules/mkiv/s-fonts-system.lua @@ -123,7 +123,7 @@ function moduledata.fonts.system.showinstalledglyphnames(specification) local names = table.setmetatableindex("table") local f_u = formatters["%04X"] for i=1,#paths do - local list = dir.glob(paths[i].."/fonts/o*/**.tmc") + local list = dir.glob(paths[i].."/fonts/o*/**." .. utilities.lua.suffixes.tmc) for i=1,#list do files[list[i]] = true end diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 65c823a66..c43b1d8da 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 : 07/24/19 11:17:48 +-- merge date : 07/31/19 18:05:38 do -- begin closure to overcome local limits and interference @@ -3396,6 +3396,13 @@ local template=[[ %s return function(%s) return %s end ]] +local pattern=Cs(Cc('"')*( + (1-S('"\\\n\r'))^1+P('"')/'\\"'+P('\\')/'\\\\'+P('\n')/'\\n'+P('\r')/'\\r' +)^0*Cc('"')) +patterns.escapedquotes=pattern +function string.escapedquotes(s) + return lpegmatch(pattern,s) +end local preamble="" local environment={ global=global or _G, @@ -3422,6 +3429,7 @@ local environment={ formattedfloat=number.formattedfloat, stripzero=patterns.stripzero, stripzeros=patterns.stripzeros, + escapedquotes=string.escapedquotes, FORMAT=string.f9, } local arguments={ "a1" } @@ -3479,7 +3487,7 @@ local format_q=function() end local format_Q=function() n=n+1 - return format("format('%%q',tostring(a%s))",n) + return format("escapedquotes(tostring(a%s))",n) end local format_i=function(f) n=n+1 @@ -11502,7 +11510,7 @@ readers.vmtx=function(f,fontdata,specification) local topsidebearing=0 for i=0,nofmetrics-1 do local glyph=glyphs[i] - vheight=readshort(f) + vheight=readushort(f) topsidebearing=readshort(f) if vheight~=0 and vheight~=vdefault then glyph.vheight=vheight @@ -11587,9 +11595,12 @@ local sequence={ { 3,1,4 }, { 3,10,12 }, { 0,3,4 }, + { 0,3,12 }, { 0,1,4 }, + { 0,1,12 }, { 0,0,6 }, { 3,0,6 }, + { 3,0,4 }, { 0,5,14 }, { 0,4,12 }, { 3,10,13 }, @@ -11859,24 +11870,33 @@ formatreaders[14]=function(f,fontdata,offset) end end local function checkcmap(f,fontdata,records,platform,encoding,format) - local data=records[platform] - if not data then + local pdata=records[platform] + if not pdata then if trace_cmap_details then report_cmap("skipped, %s, p=%i e=%i f=%i","no platform",platform,encoding,format) end return 0 end - data=data[encoding] - if not data then + local edata=pdata[encoding] + if not edata then if trace_cmap_details then report_cmap("skipped, %s, p=%i e=%i f=%i","no encoding",platform,encoding,format) end return 0 end - data=data[format] - if not data then + local fdata=edata[format] + if not fdata then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","no format",platform,encoding,format) + end + return 0 + elseif type(fdata)~="number" then + if trace_cmap_details then + report_cmap("skipped, %s, p=%i e=%i f=%i","already done",platform,encoding,format) + end return 0 end + edata[format]=true local reader=formatreaders[format] if not reader then if trace_cmap_details then @@ -11884,8 +11904,8 @@ local function checkcmap(f,fontdata,records,platform,encoding,format) end return 0 end - local n=reader(f,fontdata,data) or 0 - if trace_cmap then + local n=reader(f,fontdata,fdata) or 0 + if trace_cmap_details or trace_cmap then local p=platforms[platform] local e=encodings[p] report_cmap("checked, platform %i (%s), encoding %i (%s), format %i, new unicodes %i", -- cgit v1.2.3