diff options
Diffstat (limited to 'doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex')
-rw-r--r-- | doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex | 1582 |
1 files changed, 566 insertions, 1016 deletions
diff --git a/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex b/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex index ad80e18b9..ca3759926 100644 --- a/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex +++ b/doc/context/sources/general/manuals/luametatex/luametatex-enhancements.tex @@ -1,10 +1,12 @@ % language=us runpath=texruns:manuals/luametatex +% todo: move some to elsewhere (e.g. builders / paragraphs + \environment luametatex-style \startcomponent luametatex-enhancements -\startchapter[reference=enhancements,title={Basic \TEX\ enhancements}] +\startchapter[reference=enhancements,title={Enhancements}] \startsection[title={Introduction}] @@ -545,6 +547,9 @@ You can set attributes of the current paragraph specification node with \prm \startsubsection[title={\prm {directlua}}] +\topicindex{scripting} +\topicindex{lua+direct} + In order to merge \LUA\ code with \TEX\ input, a few new primitives are needed. The primitive \prm {directlua} is used to execute \LUA\ code immediately. The syntax is @@ -659,6 +664,9 @@ in a separate file and load it using \LUA's \type {dofile}: \startsubsection[title={\prm {luafunction}, \prm {luafunctioncall} and \prm {luadef}}] +\topicindex{functions} +\topicindex{lua+functions} + The \prm {directlua} commands involves tokenization of its argument (after picking up an optional name or number specification). The tokenlist is then converted into a string and given to \LUA\ to turn into a function that is @@ -710,6 +718,9 @@ normal usage should not give problems. \startsubsection[title={\prm {luabytecode} and \prm {luabytecodecall}}] +\topicindex{lua+bytecode} +\topicindex{bytecode} + Analogue to the function callers discussed in the previous section we have byte code callers. Again the call variant is unexpandable. @@ -812,9 +823,22 @@ the currently active table, an error is raised. \stopsubsection +\startsubsection[title={\prm {letcharcode}}] + +This primitive can be used to assign a meaning to an active character, as in: + +\starttyping +\def\foo{bar} \letcharcode123=\foo +\stoptyping + +This can be a bit nicer than using the uppercase tricks (using the property of +\prm {uppercase} that it treats active characters special). + +\stopsubsection + \stopsection -\startsection[title={Tokens, commands and strings}] +\startsection[title={Tokens and expansion}] \startsubsection[title={\prm {scantextokens}, \prm {tokenized} and \prm {retokenized}}] @@ -884,222 +908,7 @@ their content first. The \type {x} variant does a global assignment. \stopsubsection -\startsubsection[title={\prm {csstring}, \prm {begincsname} and \prm {lastnamedcs}}] - -These are somewhat special. The \prm {csstring} primitive is like -\prm {string} but it omits the leading escape character. This can be -somewhat more efficient than stripping it afterwards. - -The \prm {begincsname} primitive is like \prm {csname} but doesn't create -a relaxed equivalent when there is no such name. It is equivalent to - -\starttyping -\ifcsname foo\endcsname - \csname foo\endcsname -\fi -\stoptyping - -The advantage is that it saves a lookup (don't expect much speedup) but more -important is that it avoids using the \prm {if} test. The \prm {lastnamedcs} -is one that should be used with care. The above example could be written as: - -\starttyping -\ifcsname foo\endcsname - \lastnamedcs -\fi -\stoptyping - -This is slightly more efficient than constructing the string twice (deep down in -\LUATEX\ this also involves some \UTF8 juggling), but probably more relevant is -that it saves a few tokens and can make code a bit more readable. - -\stopsubsection - -\startsubsection[title={\prm {clearmarks}, \prm {flushmarks}, \prm {currentmarks}}] - -\topicindex {marks} - -The \prm {clearmarks} primitive complements the \ETEX\ mark primitives and clears -a mark class completely, resetting all three connected mark texts to empty. It is -an immediate command (no synchronization node is used). - -\startsyntax -\clearmarks <16-bit number> -\stopsyntax - -The \prm {flushmarks} variant is delayed but puts a (mark) node in the list as -signal (we could have gone for a keyword to \prm {marks} instead). - -\startsyntax -\flushmarks <16-bit number> -\stopsyntax - -In addition to the three mark fetch commands, we also have access to the last set -mark in the given class. - -\startsyntax -\currentmarks <16-bit number> -\stopsyntax - -Marks can be traced with \prm {tracingmarks}. When set to~1 the page builder -shows the set values, and when set to a higher value details about collecting -them are shown. - -\stopsubsection - -\startsubsection[title={\prm {alignmark}, \prm {aligntab}, \prm {aligncontent}, \prm {tabsize} and \prm {everytab}}] - -The primitive \prm {alignmark} duplicates the functionality of \type {#} inside -alignment preambles, while \prm {aligntab} duplicates the functionality of \type -{&}. The \prm {aligncontent} primitive directly refers to an entry so that one -does not get repeated. - -Alignments can be traced with \prm {tracingalignments}. When set to~1 basics -usage is shown, for instance of \prm {noalign} but more interesting is~2 or more: -you then get the preambles reported. - -The \prm {halign} (tested) and \prm {valign} (yet untested) primitives accept a -few keywords in addition to \type {to} and \type {spread}: - -\starttabulate[|l|p|] -\DB keyword \BC explanation \NC \NR -\TB -\NC \type {attr} \NC set the given attribute to the given value \NC \NR -\NC \type {callback} \NC trigger the \type {alignment_filter} callback \NC \NR -\NC \type {discard} \NC discard zero \prm {tabskip}'s \NC \NR -\NC \type {noskips} \NC don't even process zero \prm {tabskip}'s \NC \NR -\NC \type {reverse} \NC reverse the final rows \NC \NR -\LL -\stoptabulate - -In the preamble the \prm {tabsize} primitive can be used to set the width of a -column. By doing so one can avoid using a box in the preamble which, combined -with the sparse tabskip features, is a bit easier on memory when you produce -tables that span hundreds of pages and have a dozen columns. - -The \prm {everytab} complements the \prm {everycr} token register but is sort of -experimental as it might become more selective and powerful some day. - -\stopsubsection - -\startsubsection[title={\prm {letcharcode}}] - -This primitive can be used to assign a meaning to an active character, as in: - -\starttyping -\def\foo{bar} \letcharcode123=\foo -\stoptyping - -This can be a bit nicer than using the uppercase tricks (using the property of -\prm {uppercase} that it treats active characters special). - -\stopsubsection - -\startsubsection[title={\prm {lettonothing} and \prm {glettonothing}}] - -This primitive is equivalent to: - -\starttyping -\protected\def\lettonothing#1{\def#1{}} -\stoptyping - -and although it might feel faster (only measurable with millions of calls) it's -mostly there because it is easier on tracing (less clutter). An advantage over -letting to an empty predefined macro is also that in tracing we keep seeing the -name (relaxing would show the relax equivalent). - -\stopsubsection - -\startsubsection[title={\prm {glet}}] - -This primitive is similar to: - -\starttyping -\protected\def\glet{\global\let} -\stoptyping - -but faster (only measurable with millions of calls) and probably more convenient -(after all we also have \type {\gdef}). - -\stopsubsection - -\startsubsection[title={\prm {defcsname}, \prm {edefcsname}, \prm {gdefcsname} and \prm {xdefcsname}}] - -Although we can implement these primitives easily using macros it makes sense, -given the popularity of \prm {csname} to have these as primitives. It also saves -some \prm {expandafter} usage and it looks a bit better in the source. - -\starttyping -\gdefcsname foo\endcsname{oof} -\stoptyping - -\stopsubsection - -\startsubsection[title={\prm {letcsname} and \prm {gletcsname}}] - -These can also be implemented using macros but again they are natively provided -by the engine for the same reasons: less code and less tracing clutter. - -\starttyping -\gletcsname foo\endcsname \relax -\stoptyping - -\stopsubsection - -\startsubsection[title={\prm {futuredef} and \prm {futurecsname}}] - -This is just the definition variant of \prm {futurelet} and a simple example -shows the difference: - -\startbuffer -\def\whatever{[\next:\meaning\next]} -\futurelet\next\whatever A -\futuredef\next\whatever B -\stopbuffer - -\typebuffer - -\getbuffer - -The next one was more an experiment that then stayed around, just to see what -surprising abuse of this primitive will happen: - -\startbuffer -\def\whateveryes{[YES]} -\def\whatevernop{[NOP]} -\let\whatever\undefined -\futurecsname\whatevernop whatever\endcsname -\futurecsname\whatevernop whateveryes\endcsname -\stopbuffer - -\typebuffer - -When the assembles control sequence is undefined the given one will be expanded, -a weird one, right? I will probably apply it some day in cases where I want less -tracing and a more direct expansion of an assembled name. - -\getbuffer - -Here is a usage example: - -\starttyping -\xdef\Whatever{\futurecsname\whatevernop whatever\endcsname} -\xdef\Whatever{\futurecsname\whateveryes whateveryes\endcsname} -\xdef\Whatever{\ifcsname whatever\endcsname\lastnamedcs\else\whatevernop\fi} -\xdef\Whatever{\ifcsname whateveryes\endcsname\lastnamedcs\else\whatevernop\fi} -\xdef\Whatever{\ifcsname whatever\endcsname\csname whatever\endcsname\else\whatevernop\fi} -\xdef\Whatever{\ifcsname whateveryes\endcsname\csname whateveryes\endcsname\else\whatevernop\fi} -\stoptyping - -The timings for one million times defining each of these definitions are 0.277, -0.313, 0.310, 0.359, 0.352 and 0.573 seconds (on a 2018 Dell 7250 Precision -laptop with mobile E3-1505M v6 processor), so there is a little gain here, but of -course in practice no one will notice that because not that many such macros are -defined (or used). - -\stopsubsection - -\startsubsection[title={\prm {expanded}, \prm {localcontrol}, \prm +\startsubsection[title={\prm {expanded}, \prm {expandedafter}, \prm {localcontrol}, \prm {localcontrolled}, \prm {beginlocalcontrol} and \prm {endlocalcontrol}}] \topicindex {expansion} @@ -1154,6 +963,9 @@ These local control primitives are a bit tricky and error message can be confusing. Future versions might have a bit better recovery but in practice it works as expected. +An \prm {expandedafter} primitive is also provided as an variant on \prm +{expandafter} that takes a token list instead of a single token. + \stopsubsection \startsubsection[title={\prm {semiprotected}, \prm {semiexpanded}, \prm {expand} and @@ -1202,54 +1014,106 @@ protect mechanism we have in \MKII. \stopsubsection -\startsubsection[title={\prm {norelax}}] +\startsubsection[title={Going ahead with \prm {expandafterpars} and \prm {expandafterspaces}}] -There are a few cases where the \TEX\ scanned skips over spaces and \prm {relax} as -well as quits on a \prm {relax} in which case it gets pushed back. An example is -given below: +\topicindex{expansion+after} + +Here are again some convenience primitives that simplify coding, remove the need +to show off with multi|-|step macros and are nicely expandable. They fit in the +repertoire of additional primitives that make macro code look somewhat easier. +Here are a few examples: \startbuffer -\edef\TestA{\ifnum1=1\relax Y\else N\fi} \meaningasis\TestA -\edef\TestB{\ifnum1=1\norelax Y\else N\fi} \meaningasis\TestB +\def\foo{!!} [\expandafterpars \foo \par test] +\def\foo{!!} [\expandafterspaces\foo test] + +\def\foo{!!} \def\oof{\foo} [{\oof} test] +\def\foo{!!} \def\oof{\expandafterspaces\foo} [{\oof}test] \stopbuffer \typebuffer -The second line also contains a sentinel but this time we use \prm {norelax} -which will not be pushed back. So, this feature is just a trick to get rid of (in -itself reasonable) side effects. +These are typically used when building high level interfaces so not many users +will see them in document sources. -\startlines\getbuffer \stoplines +\startlines +\getbuffer +\stoplines \stopsubsection -\startsubsection[title={\prm {ignorepars}}] +\startsubsection[title={\prm {afterassigned}}] -This primitive is like \prm {ignorespaces} but also skips paragraph ending -commands (normally \prm {par} and empty lines). +\topicindex{assignments+after} + +This primitive is a multiple token variant of \prm {afterassignment} and it takes +a token list. It might look better in some cases than multiple single token +\quote {calls}. \stopsubsection -\startsubsection[title={\prm {futureexpand}, \prm {futureexpandis}, \prm {futureexpandisap}}] +\startsubsection[title={\prm {detokenized}}] -These commands are used as: +\topicindex{serializing} -\starttyping -\futureexpand\sometoken\whenfound\whennotfound -\stoptyping +The \prm {string} primitive serializes what comes next, a control sequence or +something more primitive string representation or just the (\UTF) character so it +does look at what it sees next in some detail. This can give confusing results +when the next token is for instance a new line. The \prm {detokenized} is less +picky and just serializes the token, so in the next examples an empty lines is +what we normally expect it to become: a serialized par token. -When there is no match and a space was gobbled a space will be put back. The -\type {is} variant doesn't do that while the \type {isap} even skips \type -{\pars}, These characters stand for \quote {ignorespaces} and \quote -{ignorespacesandpars}. +\def\oof{s\expandafter\foo\string} +\def\ofo{d\expandafter\foo\detokenized} +\def\foo#1{:[#1]} + +\startbuffer +\oof test +\ofo test +\oof \relax +\ofo \relax +\oof \par +\ofo \par + +\oof + +\ofo + +done +\stopbuffer + +\typebuffer + +We need the empty lines and \quote {done} to make sure we see the effect: + +{\tttf \getbuffer} \stopsubsection -\startsubsection[title={\prm {afterassigned}}] +\startsubsection[title={\prm {expandtoken} and \prm {expandcstoken}}] -This primitive is a multiple token variant of \prm {afterassignment} and it takes -a token list. It might look better in some cases than multiple single token -\quote {calls}. +\topicindex{expansion+tokens} + +These two are not really needed but can make code look less weird (and +impressive) because there are no catcode changes involved. The next example +illustrates what they do: + +\startbuffer +\edef\foo{\expandtoken 12 123 } \meaning\foo +\edef\oof{\bgroup \egroup} \meaning\oof +\edef\oof{\expandcstoken \bgroup\expandcstoken \egroup} \meaning\oof +\edef\oof{\expandcstoken \foo } \meaning\oof +\stopbuffer + +\typebuffer + +So \prm {expandtoken} expects two arguments: a catcode and a character number. +The \prm {expandcstoken} will only look at control sequences representing a +character. + +\startlines +\getbuffer +\stoplines \stopsubsection @@ -1259,6 +1123,8 @@ a token list. It might look better in some cases than multiple single token \startsubsection[title={\prm {endsimplegroup}}] +\topicindex{grouping+ending} + This feature might look somewhat weird so just ignore that it is there. It is one of these features that might never make it in a engine when discussed in committee but it comes in handy in \CONTEXT, so: @@ -1288,6 +1154,8 @@ when it has been changed in the group. \startsubsection[title={\prm {aftergrouped}}] +\topicindex{grouping+after} + There is a new experimental feature that can inject multiple tokens to after the group ends. An example demonstrate its use: @@ -1326,6 +1194,8 @@ This gives: \startsubsection[title={\prm {atendofgroup} and \prm {atendofgrouped}}] +\topicindex{grouping+ending} + These are variants of \prm {aftergroup} and \prm {aftergrouped} but they happen {\em before} the groups is closed. It is one of these primitives that is not really needed but that can make code (and tracing) cleaner, which is one of the @@ -1339,6 +1209,8 @@ objectives (at least for \CONTEXT). \startsubsection[title={\prm{ifabsnum} and \prm {ifabsdim}}] +\topicindex{conditions} + There are two tests that we took from \PDFTEX: \startbuffer @@ -1536,12 +1408,12 @@ nested balanced \quote {lists}, as in: \startsubsection[title={\prm {ifarguments}, \prm {ifparameters} and \prm {ifparameter}}] -These are part of the extended macro argument parsing features. The \type -{\ifarguments} condition is like an \type {\ifcase} where the number is the +These are part of the extended macro argument parsing features. The \prm +{ifarguments} condition is like an \prm {ifcase} where the number is the picked up number of arguments. The number reflects the {\em last} count, so -successive macro expansions will adapt the value. The \type {\ifparameters} -counts till the first empty parameter and the \type {\ifparameter} (singular) -takes a parameter reference (like \type {#2}) and again is an \type {\ifcase} +successive macro expansions will adapt the value. The \prm {ifparameters} +counts till the first empty parameter and the \prm {ifparameter} (singular) +takes a parameter reference (like \type {#2}) and again is an \prm {ifcase} where zero means a bad reference, one a non|-|empty argument and two an empty one. A typical usage is: @@ -1559,6 +1431,7 @@ No expansion of arguments takes place here but you can use a test like this: \iftok{#2}{}\else two\fi} \stoptyping + \stopsubsection \startsubsection[title={\prm {ifcondition}}] @@ -1706,359 +1579,6 @@ be queried with \typ {tex.getflagvalues}. \stopsection -\startsection[title={Boxes, rules and leaders}] - -\startsubsection[title={\prm {outputbox}}] - -\topicindex {output} - -This integer parameter allows you to alter the number of the box that will be -used to store the page sent to the output routine. Its default value is 255, and -the acceptable range is from 0 to 65535. - -\startsyntax -\outputbox = 12345 -\stopsyntax - -\stopsubsection - -\startsubsection[title={\prm {hrule}, \prm {vrule}, \prm {nohrule} and \prm {novrule}}] - -\topicindex {rules} - -Both rule drawing commands take an optional \type {xoffset} and \type {yoffset} -parameter. The displacement is virtual and not taken into account when the -dimensions are calculated. A rule is specified in the usual way: - -\obeydepth - -\startbuffer -\blue \vrule - height 2ex depth 1ex width 10cm -\relax -\stopbuffer - -\startlinecorrection -\getbuffer -\stoplinecorrection - -There is however a catch. The keyword scanners in \LUAMETATEX\ are implemented -slightly different. When \TEX\ scans a keyword it will (case insensitive) scan -for a whole keyword. So, it scans for \type {height} and when it doesn't find it -it will scan for \type {depth} etc. When it does find a keyword in this case it -expects a dimension next. When that criterium is not met it will issue an error -message. - -In order to avoid look ahead failures like that it is recommended to end the -specification with \type {\relax}. A glue specification is an other example where -a \type {\relax} makes sense when look ahead issues are expected and actually -there in traditional scanning the order of keywords can also matter. In any case, -when no valid keyword is seen the characters scanned so far are pushed back in -the input. - -The main reason for using an adapted scanner is that we always permit repetition -(consistency) and accept an arbitrary order. Because we have more keywords to -process the scanner quits at a partial failure. This prevents some push back and -also gives an earlier warning. Interesting is that some \CONTEXT\ users ran into -error messages due to a missing \type {\relax} and found out that their style has -a potential flaw with respect to look ahead. One can be lucky for years. - -Back to rules, there are some extra keywords, two deal with an offset, and four -provide margins. The margins are a bit special because \type {left} and \type -{top} are the same as are \type {right} and \type {bottom}. They influence the -edges and these depend on it being a horizontal or vertical rule. - -\obeydepth - -\startbuffer -\blue \vrule - height 2.0ex depth 1.0ex width 10cm -\relax -\white \vrule - height 1.0ex depth 0.5ex width 9cm - xoffset -9.5cm yoffset .25ex -\relax -\blue \vrule - height .5ex depth 0.25ex width 8cm - xoffset -18cm yoffset .375ex top 1pt -\relax -\stopbuffer - -\startlinecorrection -\getbuffer -\stoplinecorrection - -Two new primitives were introduced: \prm {nohrule} and \prm {novrule}. These can -be used to reserve space. This is often more efficient than creating an empty box -with fake dimensions. Of course this assumes that the backend implements them -being invisible but still taking space. - -\stopsubsection - -\startsubsection[title={\prm {vsplit}}] - -\topicindex {splitting} - -The \prm {vsplit} primitive has to be followed by a specification of the required -height. As alternative for the \type {to} keyword you can use \type {upto} to get -a split of the given size but result has the natural dimensions then. - -\starttyping -\vsplit 123 to 10cm % final box has the required height -\vsplit 123 upto 10cm % final box has its natural height -\stoptyping - -\stopsubsection - -\startsubsection[title={\prm {boxxoffset}, \prm {boxyoffset}, \prm {boxxmove}, \prm {boxymove}, -\prm{boxorientation} and \prm{boxgeometry}}] - -This repertoire of primitives can be used to do relative positioning. The offsets -are virtual while the moves adapt the dimensions. The orientation bitset can be -used to rotate the box over 90, 180 and 270 degrees. It also influences the -corner, midpoint or baseline. - -{\em There is information in the \CONTEXT\ low level manuals and in due time I -will add a few examples here. This feature needs support in the backend when used -(as in \CONTEXT) so it might influence performance.} - -\stopsubsection - -\startsubsection[title={\prm {boxtotal}}] - -The \prm {boxtotal} primitive returns the sum of the height and depth and is less -useful as setter: it just sets the height and depth to half of the given value. - -\stopsubsection - -\startsubsection[title={\prm {boxshift}}] - -In traditional \TEX\ a box has height, depth, width and a shift where the later -relates to \prm {raise}, \prm {lower}, \prm {moveleft} and \prm {moveright}. This -primitive can be used to query and set this property. - -\startbuffer -\setbox0\hbox{test test test} -\setbox2\hbox{test test test} \boxshift2 -10pt -\ruledhbox{x \raise10pt\box0\ x} -\ruledhbox{x \box2\ x} -\stopbuffer - -\typebuffer - -\stopsubsection - -\startsubsection[title={\prm {boxanchor}, \prm {boxanchors}, \prm {boxsource} and \prm {boxtarget}}] - -{\em These are experimental.} - -\stopsubsection - -\startsubsection[title={\prm {boxfreeze}, \prm {boxadapt} and \prm {boxrepack}}] - -This operation will freeze the glue in the given box, something that normally is -delayed and delegated to the backend. - -\startbuffer -\setbox 0 \hbox to 5cm {\hss test} -\setbox 2 \hbox to 5cm {\hss test} -\boxfreeze 2 0 -\ruledhbox{\unhbox 0} -\ruledhbox{\unhbox 2} -\stopbuffer - -\typebuffer - -The second parameter to \prm {boxfreeze} determines recursion. Here we just -freeze the outer level: - -\getbuffer - -Repacking will take the content of an existing box and add or subtract from it: - -\startbuffer -\setbox 0 \hbox {test test test} -\setbox 2 \hbox {\red test test test} \boxrepack0 +.2em -\setbox 4 \hbox {\green test test test} \boxrepack0 -.2em -\ruledhbox{\box0} \vskip-\lineheight -\ruledhbox{\box0} \vskip-\lineheight -\ruledhbox{\box0} -\stopbuffer - -\typebuffer - -\getbuffer - -We can use this primitive to check the natural dimensions: - -\startbuffer -\setbox 0 \hbox spread 10pt {test test test} -\ruledhbox{\box0} (\the\boxrepack0,\the\wd0) -\stopbuffer - -\typebuffer - -\getbuffer - -Adapting will recalculate the dimensions with a scale factor for the glue: - -\startbuffer -\setbox 0 \hbox {test test test} -\setbox 2 \hbox {\red test test test} \boxadapt 0 200 -\setbox 4 \hbox {\blue test test test} \boxadapt 0 -200 -\ruledhbox{\box0} \vskip-\lineheight -\ruledhbox{\box0} \vskip-\lineheight -\ruledhbox{\box0} -\stopbuffer - -\typebuffer - -\getbuffer - -\stopsubsection - -\startsubsection[title={Images and reused box objects},reference=sec:imagesandforms] - -In original \TEX\ image support is dealt with via specials. It's not a native -feature of the engine. All that \TEX\ cares about is dimensions, so in practice -that meant: using a box with known dimensions that wraps a special that instructs -the backend to include an image. The wrapping is needed because a special itself -is a whatsit and as such has no dimensions. - -In \PDFTEX\ a special whatsit for images was introduced and that one {\em has} -dimensions. As a consequence, in several places where the engine deals with the -dimensions of nodes, it now has to check the details of whatsits. By inheriting -code from \PDFTEX, the \LUATEX\ engine also had that property. However, at some -point this approach was abandoned and a more natural trick was used: images (and -box resources) became a special kind of rules, and as rules already have -dimensions, the code could be simplified. - -When direction nodes and (formerly local) par nodes also became first class -nodes, whatsits again became just that: nodes representing whatever you want, but -without dimensions, and therefore they could again be ignored when dimensions -mattered. And, because images were disguised as rules, as mentioned, their -dimensions automatically were taken into account. This separation between front -and backend cleaned up the code base already quite a bit. - -In \LUAMETATEX\ we still have the image specific subtypes for rules, but the -engine never looks at subtypes of rules. That was up to the backend. This means -that image support is not present in \LUAMETATEX. When an image specification was -parsed the special properties, like the filename, or additional attributes, were -stored in the backend and all that \LUATEX\ does is registering a reference to an -image's specification in the rule node. But, having no backend means nothing is -stored, which in turn would make the image inclusion primitives kind of weird. - -Therefore you need to realize that contrary to \LUATEX, {\em in \LUAMETATEX\ -support for images and box reuse is not built in}! However, we can assume that -an implementation uses rules in a similar fashion as \LUATEX\ does. So, you can -still consider images and box reuse to be core concepts. Here we just mention the -primitives that \LUATEX\ provides. They are not available in the engine but can -of course be implemented in \LUA. - -\starttabulate[|l|p|] -\DB command \BC explanation \NC \NR -\TB -\NC \tex {saveboxresource} \NC save the box as an object to be included later \NC \NR -\NC \tex {saveimageresource} \NC save the image as an object to be included later \NC \NR -\NC \tex {useboxresource} \NC include the saved box object here (by index) \NC \NR -\NC \tex {useimageresource} \NC include the saved image object here (by index) \NC \NR -\NC \tex {lastsavedboxresourceindex} \NC the index of the last saved box object \NC \NR -\NC \tex {lastsavedimageresourceindex} \NC the index of the last saved image object \NC \NR -\NC \tex {lastsavedimageresourcepages} \NC the number of pages in the last saved image object \NC \NR -\LL -\stoptabulate - -An implementation probably should accept the usual optional dimension parameters -for \type {\use...resource} in the same format as for rules. With images, these -dimensions are then used instead of the ones given to \tex {useimageresource} but -the original dimensions are not overwritten, so that a \tex {useimageresource} -without dimensions still provides the image with dimensions defined by \tex -{saveimageresource}. These optional parameters are not implemented for \tex -{saveboxresource}. - -\starttyping -\useimageresource width 20mm height 10mm depth 5mm \lastsavedimageresourceindex -\useboxresource width 20mm height 10mm depth 5mm \lastsavedboxresourceindex -\stoptyping - -Examples or optional entries are \type {attr} and \type {resources} that accept a -token list, and the \type {type} key. When set to non|-|zero the \type {/Type} -entry is omitted. A value of 1 or 3 still writes a \type {/BBox}, while 2 or 3 -will write a \type {/Matrix}. But, as said: this is entirely up to the backend. -Generic macro packages (like \type {tikz}) can use these assumed primitives so -one can best provide them. It is probably, for historic reasons, the only more or -less standardized image inclusion interface one can expect to work in all macro -packages. - -\stopsubsection - -\startsubsection[title={\prm {hpack}, \prm {vpack} and \prm {tpack}}] - -These three primitives are the equivalents of \prm {hbox}, \prm {vbox} and -\prm {vtop} but they don't trigger the packaging related callbacks. Of course -one never know if content needs a treatment so using them should be done with -care. Apart from accepting more keywords (and therefore options) the normal -box behave the same as before. The \prm {vcenter} builder also works in text -mode. - -\stopsubsection - -\startsubsection[title={\prm {unhpack}, \prm {unvpack}}] - -These two are somewhat experimental. They ignore the accumulated pre- and -postmigrated material bound to a box. I needed it for some experiment so the -functionality might change when I really need it. - -\stopsubsection - -\startsubsection[title={\prm {gleaders}},reference=sec:gleaders] - -\topicindex {leaders} - -This type of leaders is anchored to the origin of the box to be shipped out. So -they are like normal \prm {leaders} in that they align nicely, except that the -alignment is based on the {\it largest\/} enclosing box instead of the {\it -smallest\/}. The \type {g} stresses this global nature. - -\stopsubsection - -\stopsection - -\startsection[title={Languages}] - -\startsubsection[title={\prm {hyphenationmin}}] - -\topicindex {languages} -\topicindex {hyphenation} - -This primitive can be used to set the minimal word length, so setting it to a value -of~$5$ means that only words of 6 characters and more will be hyphenated, of course -within the constraints of the \prm {lefthyphenmin} and \prm {righthyphenmin} -values (as stored in the glyph node). This primitive accepts a number and stores -the value with the language. - -\stopsubsection - -\startsubsection[title={\prm {boundary}, \prm {noboundary}, \prm {protrusionboundary} and \prm {wordboundary}}] - -The \prm {noboundary} command is used to inject a whatsit node but now injects a normal -node with type \nod {boundary} and subtype~0. In addition you can say: - -\starttyping -x\boundary 123\relax y -\stoptyping - -This has the same effect but the subtype is now~1 and the value~123 is stored. -The traditional ligature builder still sees this as a cancel boundary directive -but at the \LUA\ end you can implement different behaviour. The added benefit of -passing this value is a side effect of the generalization. The subtypes~2 and~3 -are used to control protrusion and word boundaries in hyphenation and have -related primitives. - -\stopsubsection - -\stopsection - \startsection[title={Control and debugging}] \startsubsection[title={Tracing}] @@ -2074,17 +1594,12 @@ and for nodes that have sublists (like discretionaries) these are also shown. Al that could have been delegated to \LUA\ but it felt wrong to not made that a core engine feature. -When bit~1 of \prm {tracinglevels} is set the current level is prepended to -tracing lines in the log and when bit~2 is set the input level is prepended. You -can set both bits and get both numbers prepended. In \CONTEXT\ we default to -the value~3, so you get prefixes like \type {3:4:} followed by a space. +The \prm {tracingpenalties} parameter triggers the line break routine to report +the applied interline penalties to the output. When \prm {tracingcommands} is larger than 3 the mode switch will be not be prefixed to the \type {{command}} but get its own \type {[line]}. -When \prm {tracinglevels} variable is set to 3 the group and input level are -shown, a value of 1 or 2 shows only one of them (in \CONTEXT\ we default to 3). - When \prm {tracinghyphenation} is set to 1 duplicate patterns are reported (in \CONTEXT\ we default to that) and higher values will also show details about the \LUA\ hyphenation (exception) feedback loop discussed elsewhere. @@ -2093,6 +1608,40 @@ When set to 1 the \prm {tracingmath} variable triggers the reporting of the mode (inline or display) an mlist is processed. Other new tracing commands are discussed where the mechanisms that they relate to are introduced. +The \prm {tracingnodes} variable makes that when a node list is reported the node +numbers are also shown. This is only useful when you have callbacks that access +nodes. + +\starttabulate[|l|p|] +\DB value \BC effect \NC \NR +\TB +\NC 1 \NC show node numbers in lists \NC \NR +\NC 2 \NC also show numbers of attribute nodes \NC \NR +\NC 3 \NC also show glue spec node numbers \NC \NR +\LL +\stoptabulate + +When the \prm {shownodedetails} variable is set to a value larger than zero and a +node is shown (in a list) then more details will be revealed. This can be rather +verbose because in \LUAMETATEX\ node carry more properties than in traditional +\TEX\ and \LUATEX. A value larger than one will also show details of attributes +that are bound to nodes. + +The \prm {tracinglevels} variable is a bitset and offers the following features: + +\starttabulate[|l|p|] +\DB value \BC effect \NC \NR +\TB +\NC 1 \NC show group level \NC \NR +\NC 2 \NC show input level \NC \NR +\NC 4 \NC show catcode regime \NC \NR +\LL +\stoptabulate + +So a value of~7 shows them all. In \CONTEXT\ we set this variable to~3 which +gives a rather verbose log when tracing is on but in the end its'not that bad +because using some of the newer programming related primitive can save tracing. + Because in \LUATEX\ the saving and restoring of locally redefined macros and set variables is optimized a bit in order to prevent redundant stack usage, there will be less tracing visible. @@ -2120,13 +1669,13 @@ alternative). \startsubsection[title={\prm {lastnodetype}, \prm {lastnodesubtype}, \prm {currentiftype}}] -The \ETEX\ command \type {\lastnodetype} returns the node codes as used in the +The \ETEX\ command \prm {lastnodetype} returns the node codes as used in the engine. You can query the numbers at the \LUA\ end if you need the actual values. The parameter \type {\internalcodesmode} is no longer provided as compatibility switch because \LUATEX\ has more cq. some different nodes and it makes no sense -to be incompatible with the \LUA\ end of the engine. The same is true for \type -{\currentiftype}, as we have more conditionals and also use a different order. -The \type {\lastnodesubtype} is a bonus and again reports the codes used +to be incompatible with the \LUA\ end of the engine. The same is true for \prm +{currentiftype}, as we have more conditionals and also use a different order. +The \prm {lastnodesubtype} is a bonus and again reports the codes used internally. During development these might occasionally change, but eventually they will be stable. @@ -2141,473 +1690,258 @@ assigned to a user boundary node. This means that we also have a \prm \stopsubsection -\stopsection - -\startsection[title={Files}] +\startsubsection[title=Nodes] -\startsubsection[title={File syntax}] +\topicindex {nodes} -\topicindex {files+names} +The \ETEX\ primitive \prm {lastnodetype} is not honest in reporting the +internal numbers as it uses its own values. But you can set \type +{\internalcodesmode} to a non|-|zero value to get the real id's instead. In +addition there is \prm {lastnodesubtype}. -\LUAMETATEX\ will accept a braced argument as a file name: +Another last one is \prm {lastnamedcs} which holds the last match but this one +should be used with care because one never knows if in the meantime something +else \quote {last} has been seen. -\starttyping -\input {plain} -\openin 0 {plain} -\stoptyping +\stopsubsection -This allows for embedded spaces, without the need for double quotes. Macro -expansion takes place inside the argument. Keep in mind that as side effect of -delegating \IO\ to \LUA\ the \tex {openin} primitive is not provided by the -engine and has to be implemented by the macro package. This also means that the -limit on the number of open files is not enforced by the engine. +\stopsection -The \prm {tracingfonts} primitive that has been inherited from \PDFTEX\ has -been adapted to support variants in reporting the font. The reason for this -extension is that a csname not always makes sense. The zero case is the default. +\startsection[title=Scanning] -\starttabulate[|l|l|] -\DB value \BC reported \NC \NR -\TB -\NC \type{0} \NC \type{\foo xyz} \NC \NR -\NC \type{1} \NC \type{\foo (bar)} \NC \NR -\NC \type{2} \NC \type{<bar> xyz} \NC \NR -\NC \type{3} \NC \type{<bar @ ..pt> xyz} \NC \NR -\NC \type{4} \NC \type{<id>} \NC \NR -\NC \type{5} \NC \type{<id: bar>} \NC \NR -\NC \type{6} \NC \type{<id: bar @ ..pt> xyz} \NC \NR -\LL -\stoptabulate +\startsubsection[title=Keywords] -\stopsubsection +\topicindex {keywords} +\topicindex {scanning+keywords} -\startsubsection[title={Writing to file}] +Some primitives accept one or more keywords and \LUAMETATEX\ adds some more. In +order to deal with this efficiently the keyword scanner has been optimized, where +even the context was taken into account. As a result the scanner was quite a bit +faster. This kind of optimization was a graduate process the eventually ended up +in what we have now. In traditional \TEX\ (and also \LUATEX) the order of +keywords is sometimes mixed and sometimes prescribed. In most cases only one +occurrence is permitted. So, for instance, this is valid in \LUATEX: -\topicindex {files+writing} +\starttyping +\hbox attr 123 456 attr 123 456 spread 10cm { } +\hrule width 10cm depth 3mm +\hskip 3pt plus 2pt minus 1pt +\stoptyping -Writing to a file in \TEX\ has two forms: delayed and immediate. Delayed writing -means that the to be written text is anchored in the node list and flushed by the -backend. As all \IO\ is delegated to \LUA, this also means that it has to deal -with distinction. In \LUATEX\ the number of open files was already bumped to 127, -but in \LUAMETATEX\ it depends on the macro package. The special meaning of -channel 18 was already dropped in \LUATEX\ because we have \type {os.execute}. +The \type {attr} comes before the \type {spread}, rules can have multiple mixed +dimension specifiers, and in glue the optional \type {minus} part always comes +last. The last two commands are famous for look ahead side effects which is why +macro packages will end them with something not keyword, like \type {\relax}, +when needed. -\stopsubsection +In \LUAMETATEX\ the following is okay. Watch the few more keywords in box and +rule specifications. -\stopsection +\starttyping +\hbox reverse to 10cm attr 123 456 orientation 4 xoffset 10pt spread 10cm { } +\hrule xoffset 10pt width 10cm depth 3mm +\hskip 3pt minus 1pt plus 2pt +\stoptyping -\startsection[title={Math}] +Here the order is not prescribed and, as demonstrated with the box specifier, for +instance dimensions (specified by \type {to} or \type {spread} can be overloaded +by later settings. In case you wonder if that breaks compatibility: in some way +it does but bad or sloppy keyword usage breaks a run anyway. For instance \type +{minuscule} results in \type {minus} with no dimension being seen. So, in the end +the user should not noticed it and when a user does, the macro package already +had an issue that had to be fixed. -\topicindex {math} +\stopsubsection -We will cover math extensions in its own chapter because not only the font -subsystem and spacing model have been enhanced (thereby introducing many new -primitives) but also because some more control has been added to existing -functionality. Much of this relates to the different approaches of traditional -\TEX\ fonts and \OPENTYPE\ math. +\startsubsection[title={\prm {norelax}}] -\stopsection +\topicindex{relaxing} -\startsection[title={Fonts}] +There are a few cases where the \TEX\ scanned skips over spaces and \prm {relax} as +well as quits on a \prm {relax} in which case it gets pushed back. An example is +given below: -\topicindex {fonts} +\startbuffer +\edef\TestA{\ifnum1=1\relax Y\else N\fi} \meaningasis\TestA +\edef\TestB{\ifnum1=1\norelax Y\else N\fi} \meaningasis\TestB +\stopbuffer -Like math, we will cover fonts extensions in its own chapter. Here we stick to -mentioning that loading fonts is different in \LUAMETATEX. As in \LUATEX\ we have -the extra primitives \type {\fontid} and \type {\setfontid}, \type {\noligs} and -\type {\nokerns}, and \type {\nospaces}. The other new primitives in \LUATEX\ -have been dropped. +\typebuffer -\stopsection +The second line also contains a sentinel but this time we use \prm {norelax} +which will not be pushed back. So, this feature is just a trick to get rid of (in +itself reasonable) side effects. -\startsection[title=Directions] +\startlines\getbuffer \stoplines -\topicindex {\OMEGA} -\topicindex {\ALEPH} -\topicindex {directions} +\stopsubsection -\startsubsection[title={Two directions}] +\startsubsection[title={\prm {ignorepars}}] -The directional model in \LUAMETATEX\ is a simplified version the the model used -in \LUATEX. In fact, not much is happening at all: we only register a change in -direction. +This primitive is like \prm {ignorespaces} but also skips paragraph ending +commands (normally \prm {par} and empty lines). \stopsubsection -\startsubsection[title={How it works}] +\startsubsection[title={\prm {futureexpand}, \prm {futureexpandis}, \prm {futureexpandisap}}] -The approach is that we try to make node lists balanced but also try to avoid -some side effects. What happens is quite intuitive if we forget about spaces -(turned into glue) but even there what happens makes sense if you look at it in -detail. However that logic makes in|-|group switching kind of useless when no -properly nested grouping is used: switching from right to left several times -nested, results in spacing ending up after each other due to nested mirroring. Of -course a sane macro package will manage this for the user but here we are -discussing the low level injection of directional information. +\topicindex{expansion+future} -This is what happens: +These commands are used as: \starttyping -\textdirection 1 nur {\textdirection 0 run \textdirection 1 NUR} nur +\futureexpand\sometoken\whenfound\whennotfound \stoptyping -This becomes stepwise: +When there is no match and a space was gobbled a space will be put back. The +\type {is} variant doesn't do that while the \type {isap} even skips \type +{\pars}, These characters stand for \quote {ignorespaces} and \quote +{ignorespacesandpars}. -\startnarrower -\starttyping -injected: [push 1]nur {[push 0]run [push 1]NUR} nur -balanced: [push 1]nur {[push 0]run [pop 0][push 1]NUR[pop 1]} nur[pop 0] -result : run {RUNrun } run -\stoptyping -\stopnarrower +\stopsubsection -And this: +\stopsection -\starttyping -\textdirection 1 nur {nur \textdirection 0 run \textdirection 1 NUR} nur -\stoptyping +\startsection[title=Macros] + +\startsubsection[title={\prm {lettonothing} and \prm {glettonothing}}] -becomes: +This primitive is equivalent to: -\startnarrower \starttyping -injected: [+TRT]nur {nur [+TLT]run [+TRT]NUR} nur -balanced: [+TRT]nur {nur [+TLT]run [-TLT][+TRT]NUR[-TRT]} nur[-TRT] -result : run {run RUNrun } run +\protected\def\lettonothing#1{\def#1{}} \stoptyping -\stopnarrower - -Now, in the following examples watch where we put the braces: - -\startbuffer -\textdirection 1 nur {{\textdirection 0 run} {\textdirection 1 NUR}} nur -\stopbuffer - -\typebuffer -This becomes: - -\startnarrower -\getbuffer -\stopnarrower +and although it might feel faster (only measurable with millions of calls) it's +mostly there because it is easier on tracing (less clutter). An advantage over +letting to an empty predefined macro is also that in tracing we keep seeing the +name (relaxing would show the relax equivalent). -Compare this to: +\stopsubsection -\startbuffer -\textdirection 1 nur {{\textdirection 0 run }{\textdirection 1 NUR}} nur -\stopbuffer +\startsubsection[title={\prm {glet}}] -\typebuffer +This primitive is similar to: -Which renders as: +\starttyping +\protected\def\glet{\global\let} +\stoptyping -\startnarrower -\getbuffer -\stopnarrower +but faster (only measurable with millions of calls) and probably more convenient +(after all we also have \type {\gdef}). -So how do we deal with the next? +\stopsubsection -\startbuffer -\def\ltr{\textdirection 0\relax} -\def\rtl{\textdirection 1\relax} +\startsubsection[title={\prm {defcsname}, \prm {edefcsname}, \prm {gdefcsname} and \prm {xdefcsname}}] -run {\rtl nur {\ltr run \rtl NUR \ltr run \rtl NUR} nur} -run {\ltr run {\rtl nur \ltr RUN \rtl nur \ltr RUN} run} -\stopbuffer +Although we can implement these primitives easily using macros it makes sense, +given the popularity of \prm {csname} to have these as primitives. It also saves +some \prm {expandafter} usage and it looks a bit better in the source. -\typebuffer +\starttyping +\gdefcsname foo\endcsname{oof} +\stoptyping -It gets typeset as: +\stopsubsection -\startnarrower -\startlines -\getbuffer -\stoplines -\stopnarrower +\startsubsection[title={\prm {letcsname} and \prm {gletcsname}}] -We could define the two helpers to look back, pick up a skip, remove it and -inject it after the dir node. But that way we loose the subtype information that -for some applications can be handy to be kept as|-|is. This is why we now have a -variant of \prm {textdirection} which injects the balanced node before the skip. -Instead of the previous definition we can use: +These can also be implemented using macros but again they are natively provided +by the engine for the same reasons: less code and less tracing clutter. -\startbuffer[def] -\def\ltr{\linedirection 0\relax} -\def\rtl{\linedirection 1\relax} -\stopbuffer +\starttyping +\gletcsname foo\endcsname \relax +\stoptyping -\typebuffer[def] +\stopsubsection -and this time: +\startsubsection[title={\prm {csstring}, \prm {begincsname} and \prm {lastnamedcs}}] -\startbuffer[txt] -run {\rtl nur {\ltr run \rtl NUR \ltr run \rtl NUR} nur} -run {\ltr run {\rtl nur \ltr RUN \rtl nur \ltr RUN} run} -\stopbuffer +These are somewhat special. The \prm {csstring} primitive is like +\prm {string} but it omits the leading escape character. This can be +somewhat more efficient than stripping it afterwards. -\typebuffer[txt] +The \prm {begincsname} primitive is like \prm {csname} but doesn't create +a relaxed equivalent when there is no such name. It is equivalent to -comes out as a properly spaced: +\starttyping +\ifcsname foo\endcsname + \csname foo\endcsname +\fi +\stoptyping -\startnarrower -\startlines -\getbuffer[def,txt] -\stoplines -\stopnarrower +The advantage is that it saves a lookup (don't expect much speedup) but more +important is that it avoids using the \prm {if} test. The \prm {lastnamedcs} +is one that should be used with care. The above example could be written as: -Anything more complex that this, like combination of skips and penalties, or -kerns, should be handled in the input or macro package because there is no way we -can predict the expected behaviour. In fact, the \prm {linedirection} is just a -convenience extra which could also have been implemented using node list parsing. +\starttyping +\ifcsname foo\endcsname + \lastnamedcs +\fi +\stoptyping -Directions are complicated by the fact that they often need to work over groups -so a separate grouping related stack is used. A side effect is that there can be -paragraphs with only a local par node followed by direction synchronization -nodes. Paragraphs like that are seen as empty paragraphs and therefore ignored. -Because \type {\noindent} doesn't inject anything but a \type {\indent} injects -an box, paragraphs with only an indent and directions are handles and paragraphs -with content. When indentation is normalized a paragraph with an indentation -skip is seen as content. +This is slightly more efficient than constructing the string twice (deep down in +\LUATEX\ this also involves some \UTF8 juggling), but probably more relevant is +that it saves a few tokens and can make code a bit more readable. \stopsubsection -\startsubsection[title={Normalizing lines}] - -The original \TEX\ machinery was never meant to be opened up. As a consequence a -constructed line can have different layouts. There can be left- and/or right -skips and hanging indentation or parshape can result in a shift and adapted -width. In \LUATEX\ glue got subtypes so we can recognize the left-, right and -parfill skips, but still there is no hundred percent certainty about the shape. - -In \LUAMETATEX\ lines can be normalized. This is optional because we want to -preserve the original (for comparison) and is controlled by \prm -{normalizelinemode}. That variable actually drives some more. An earlier version -provided a few more granular options (for instance: does a leftskip comes before -or after a left hanging indentation) but in the end that was dropped. Because -this normalization only is seen at the \LUA\ end there is no need to go into much -detail here. - -At this moment a line has this pattern: left parfill, left hang, left skip, -indentation, content, right hang, right skip, right parfill. Of course the -indentation and fill skips are not present in every line. - -Control over normalization happens via the mentioned mode variable and here is -what the engine provides right now. We use a bitmap: - -\starttabulate[|l|l|] -\DB value \BC reported \NC \NR -\TB -\NC \type{0x0001} \NC normalize line as described above \NC \NR -\NC \type{0x0002} \NC use a skip for parindent instead of a box \NC \NR -\NC \type{0x0004} \NC swap hangindent in l2r mode \NC \NR -\NC \type{0x0008} \NC swap parshape in l2r mode \NC \NR -\NC \type{0x0010} \NC put breaks after dir in l2r mode \NC \NR -\NC \type{0x0020} \NC remove margin kerns (\PDFTEX\ left-over) \NC \NR -\NC \type{0x0040} \NC if needed clip width and use correction kern \NC \NR -\LL -\stoptabulate +\startsubsection[title={\prm {futuredef} and \prm {futurecsname}}] -Setting the bit enables the related normalization. More features might be added -in future releases. +This is just the definition variant of \prm {futurelet} and a simple example +shows the difference: -% Swapping shapes -% -% Another adaptation to the \ALEPH\ directional model is control over shapes driven -% by \prm {hangindent} and \prm {parshape}. This is controlled by a new parameter -% \prm {shapemode}: -% -% \starttabulate[|c|l|l|] -% \DB value \BC \prm {hangindent} \BC \prm {parshape} \NC \NR -% \TB -% \BC \type{0} \NC normal \NC normal \NC \NR -% \BC \type{1} \NC mirrored \NC normal \NC \NR -% \BC \type{2} \NC normal \NC mirrored \NC \NR -% \BC \type{3} \NC mirrored \NC mirrored \NC \NR -% \LL -% \stoptabulate -% -% The value is reset to zero (like \prm {hangindent} and \prm {parshape}) -% after the paragraph is done with. You can use negative values to prevent -% this. In \in {figure} [fig:shapemode] a few examples are given. -% -% \startplacefigure[reference=fig:shapemode,title={The effect of \type {shapemode}.}] -% \startcombination[2*3] -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \pardirection 0 \textdirection 0 -% \hangindent 40pt \hangafter -3 -% \leftskip10pt \input tufte \par -% \egroup} {TLT: hangindent} -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \pardirection 0 \textdirection 0 -% \parshape 4 0pt .8\hsize 10pt .8\hsize 20pt .8\hsize 0pt \hsize -% \input tufte \par -% \egroup} {TLT: parshape} -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \pardirection 1 \textdirection 1 -% \hangindent 40pt \hangafter -3 -% \leftskip10pt \input tufte \par -% \egroup} {TRT: hangindent mode 0} -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \pardirection 1 \textdirection 1 -% \parshape 4 0pt .8\hsize 10pt .8\hsize 20pt .8\hsize 0pt \hsize -% \input tufte \par -% \egroup} {TRT: parshape mode 0} -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \shapemode=3 -% \pardirection 1 \textdirection 1 -% \hangindent 40pt \hangafter -3 -% \leftskip10pt \input tufte \par -% \egroup} {TRT: hangindent mode 1 & 3} -% {\ruledvbox \bgroup \setuptolerance[verytolerant] -% \hsize .45\textwidth \switchtobodyfont[6pt] -% \shapemode=3 -% \pardirection 1 \textdirection 1 -% \parshape 4 0pt .8\hsize 10pt .8\hsize 20pt .8\hsize 0pt \hsize -% \input tufte \par -% \egroup} {TRT: parshape mode 2 & 3} -% \stopcombination -% \stopplacefigure -% -% We have \type {\pardirection}, \type {\textdirection}, \type {\mathdirection} and -% \type {\linedirection} that is like \type {\textdirection} but with some -% additional (inline) glue checking. +\startbuffer +\def\whatever{[\next:\meaning\next]} +\futurelet\next\whatever A +\futuredef\next\whatever B +\stopbuffer -% Controlling glue with \prm {breakafterdirmode} -% -% Glue after a dir node is ignored in the linebreak decision but you can bypass that -% by setting \prm {breakafterdirmode} to~\type {1}. The following table shows the -% difference. Watch your spaces. -% -% \def\ShowSome#1{% -% \BC \type{#1} -% \NC \breakafterdirmode\zerocount\hsize\zeropoint#1 -% \NC -% \NC \breakafterdirmode\plusone\hsize\zeropoint#1 -% \NC -% \NC \NR -% } -% -% \starttabulate[|l|Tp(1pt)|w(5em)|Tp(1pt)|w(5em)|] -% \DB -% \BC \type{0} -% \NC -% \BC \type{1} -% \NC -% \NC \NR -% \TB -% \ShowSome{pre {\textdirection 0 xxx} post} -% \ShowSome{pre {\textdirection 0 xxx }post} -% \ShowSome{pre{ \textdirection 0 xxx} post} -% \ShowSome{pre{ \textdirection 0 xxx }post} -% \ShowSome{pre { \textdirection 0 xxx } post} -% \ShowSome{pre {\textdirection 0\relax\space xxx} post} -% \LL -% \stoptabulate - -\stopsubsection - -\startsubsection[title=Orientations] - -As mentioned, the difference with \LUATEX\ is that we only have numeric -directions and that there are only two: left|-|to|-|right (\type {0}) and -right|-|to|-|left (\type {1}). The direction of a box is set with \type -{direction}. - -In addition to that boxes can now have an \type {orientation} keyword followed by -optional \type {xoffset} and|/|or \type {yoffset} keywords. The offsets don't -have consequences for the dimensions. The alternatives \type {xmove} and \type -{ymove} on the contrary are reflected in the dimensions. Just play with them. The -offsets and moves only are accepted when there is also an orientation, so no time -is wasted on testing for these rarely used keywords. There are related primitives -\type {\box...} that set these properties. - -As these are experimental it will not be explained here (yet). They are covered -in the descriptions of the development of \LUAMETATEX: articles and|/|or -documents in the \CONTEXT\ distribution. For now it is enough to know that the -orientation can be up, down, left or right (rotated) and that it has some -anchoring variants. Combined with the offsets this permits macro writers to -provide solutions for top|-|down and bottom|-|up writing directions, something -that is rather macro package specific and used for scripts that need -manipulations anyway. The \quote {old} vertical directions were never okay and -therefore not used. - -There are a couple of properties in boxes that you can set and query but that -only really take effect when the backend supports them. When usage on \CONTEXT\ -shows that is't okay, they will become official, so we just mention them: \type -{\boxdirection}, \type {\boxattr}, \type {\boxorientation}, \type {\boxxoffset}, -\type {\boxyoffset}, \type {\boxxmove}, \type {\boxymove} and \type {\boxtotal}. - -{\em This is still somewhat experimental and will be documented in more detail -when I've used it more in \CONTEXT\ and the specification is frozen. This might -take some time (and user input).} +\typebuffer -\stopsubsection +\getbuffer -\stopsection +The next one was more an experiment that then stayed around, just to see what +surprising abuse of this primitive will happen: -\startsection[title=Keywords] +\startbuffer +\def\whateveryes{[YES]} +\def\whatevernop{[NOP]} +\let\whatever\undefined +\futurecsname\whatevernop whatever\endcsname +\futurecsname\whatevernop whateveryes\endcsname +\stopbuffer -Some primitives accept one or more keywords and \LUAMETATEX\ adds some more. In -order to deal with this efficiently the keyword scanner has been optimized, where -even the context was taken into account. As a result the scanner was quite a bit -faster. This kind of optimization was a graduate process the eventually ended up -in what we have now. In traditional \TEX\ (and also \LUATEX) the order of -keywords is sometimes mixed and sometimes prescribed. In most cases only one -occurrence is permitted. So, for instance, this is valid in \LUATEX: +\typebuffer -\starttyping -\hbox attr 123 456 attr 123 456 spread 10cm { } -\hrule width 10cm depth 3mm -\hskip 3pt plus 2pt minus 1pt -\stoptyping +When the assembles control sequence is undefined the given one will be expanded, +a weird one, right? I will probably apply it some day in cases where I want less +tracing and a more direct expansion of an assembled name. -The \type {attr} comes before the \type {spread}, rules can have multiple mixed -dimension specifiers, and in glue the optional \type {minus} part always comes -last. The last two commands are famous for look ahead side effects which is why -macro packages will end them with something not keyword, like \type {\relax}, -when needed. +\getbuffer -In \LUAMETATEX\ the following is okay. Watch the few more keywords in box and -rule specifications. +Here is a usage example: \starttyping -\hbox reverse to 10cm attr 123 456 orientation 4 xoffset 10pt spread 10cm { } -\hrule xoffset 10pt width 10cm depth 3mm -\hskip 3pt minus 1pt plus 2pt +\xdef\Whatever{\futurecsname\whatevernop whatever\endcsname} +\xdef\Whatever{\futurecsname\whateveryes whateveryes\endcsname} +\xdef\Whatever{\ifcsname whatever\endcsname\lastnamedcs\else\whatevernop\fi} +\xdef\Whatever{\ifcsname whateveryes\endcsname\lastnamedcs\else\whatevernop\fi} +\xdef\Whatever{\ifcsname whatever\endcsname\csname whatever\endcsname\else\whatevernop\fi} +\xdef\Whatever{\ifcsname whateveryes\endcsname\csname whateveryes\endcsname\else\whatevernop\fi} \stoptyping -Here the order is not prescribed and, as demonstrated with the box specifier, for -instance dimensions (specified by \type {to} or \type {spread} can be overloaded -by later settings. In case you wonder if that breaks compatibility: in some way -it does but bad or sloppy keyword usage breaks a run anyway. For instance \type -{minuscule} results in \type {minus} with no dimension being seen. So, in the end -the user should not noticed it and when a user does, the macro package already -had an issue that had to be fixed. - -\stopsection - -\startsection[title=Expressions and \prm {numericscale}] - -The \type {*expr} parsers now accept \type {:} as operator for integer division -(the \type {/} operators does rounding. This can be used for division compatible -with \type {\divide}. I'm still wondering if adding a couple of bit operators -makes sense (for integers). +The timings for one million times defining each of these definitions are 0.277, +0.313, 0.310, 0.359, 0.352 and 0.573 seconds (on a 2018 Dell 7250 Precision +laptop with mobile E3-1505M v6 processor), so there is a little gain here, but of +course in practice no one will notice that because not that many such macros are +defined (or used). -The \prm{numericscale} parser is kind of special (and might evolve). For now it -converts a following number in a scale value as often used in \TEX, where 1000 -means scaling by~1.0. The trick is in the presence of a digit (or comma): 1.234 -becomes 1234 but 1234 stays 1234 and from this you can deduce that 12.34 becomes -123400. Internally \TEX\ calculates with integers, but this permits the macro -package to provide an efficient mix. +\stopsubsection -\stopsection +\startsubsection[title=Arguments] -\startsection[title=Macro arguments] +\topicindex {macros+arguments} Again this is experimental and (used and) discussed in document that come with the \CONTEXT\ distribution. When defining a macro you can do this: @@ -2663,7 +1997,8 @@ what this does: Of course complex combinations can be confusing because after all \TEX\ is parsing for (multi|-|token) delimiters and will happily gobble the whole file if -you are not careful. You can quit scanning if you want: +you are not careful. You can quit scanning with \prm {ignorearguments} if you +want: \starttyping \mymacro 123\ignorearguments @@ -2683,9 +2018,66 @@ on performance this has been compensated by some more efficiency in the macro parser and engine in general and of course you can gain back some by using these features. -\stopsection +\stopsubsection + +\startsubsection[title={\prm {parametermark}}] + +The meaning of primitive \prm {parametermark} is equivalent to \type {#} in a macro +definition, just like \prm {alignmark} is in an alignment. It can be used to circumvent +catcode issues. The normal \quotation {duplicate them when nesting} rules apply. + +\startbuffer +\def\foo\parametermark1% + {\def\oof\parametermark\parametermark1% + {[\parametermark1:\parametermark\parametermark1]}} +\stopbuffer + +\typebuffer \getbuffer + +Here \type {\foo{X}\oof{Y}} gives: \foo{X}\oof{Y}. + +\stopsubsection + +\startsubsection[title={\prm {lastarguments} and \prm {parametercount}}] -\startsection[title=Overload protection] +\topicindex{arguments+numberof} + +There are two state variables that refer to the number of read arguments. An +example can show the difference: + +\startbuffer +\tolerant\def\foo[#1]#*[#2]{[\the\lastarguments,\the\parametercount]} + +\foo[1][2] +\foo[1] +\foo + +x: \foo[1][2] +x: \foo[1] +x: \foo +\stopbuffer + +\typebuffer + +What you get actually depends on the macro package. When for instance \prm +{everypar} has some value that results in a macro being expanded, the numbers +reported can refer to the most recent macro because serializing the number can +result in entering horizontal mode. + +\startlines +\getbuffer +\stoplines + +The \prm {lastarguments} returns the most recent global state variable as with +any \type {\last...} primitives. Because it actually looks at the parameter stack +of the currently expanded macro \prm {parametercount} is more reliable but also +less efficient. + +\stopsubsection + +\startsubsection[title=Overload protection] + +\topicindex {macros+overloading} There is an experimental overload protection mechanism that we will test for a while before declaring it stable. The reason for that is that we need to adapt @@ -2803,9 +2195,51 @@ There is an extra prefix \prm {untraced} that will suppress the meaning when tracing so that the macro looks more like a primitive. It is still somewhat experimental so what gets displayed might change. +The \prm {letfrozen}, \prm {unletfrozen}, \prm {letprotected} and \prm +{unletprotected} primitives do as their names advertise. Of course the \prm +{overloadmode} must be set so that it is permitted. + +\stopsubsection + +\startsubsection[title={Swapping meaning}] + +\topicindex {macros+swapping} + +The \prm {swapcsvalues} will swap the values of two control sequences of the same +type. This is a somewhat tricky features because it can interfere with grouping. + +\startbuffer +\scratchcounterone 1 \scratchcountertwo 2 +(\the\scratchcounterone,\the\scratchcountertwo) +\swapcsvalues \scratchcounterone \scratchcountertwo +(\the\scratchcounterone,\the\scratchcountertwo) +\swapcsvalues \scratchcounterone \scratchcountertwo +(\the\scratchcounterone,\the\scratchcountertwo) + +\scratchcounterone 3 \scratchcountertwo 4 +(\the\scratchcounterone,\the\scratchcountertwo) +\bgroup +\swapcsvalues \scratchcounterone \scratchcountertwo +(\the\scratchcounterone,\the\scratchcountertwo) +\egroup +(\the\scratchcounterone,\the\scratchcountertwo) +\stopbuffer + +\typebuffer + +We get similar results: + +\startlines +\getbuffer +\stoplines + +\stopsubsection + \stopsection -\startsection[title={Constants with \prm{integerdef}, \prm {dimensiondef}, +\startsection[title=Quantities] + +\startsubsection[title={Constants with \prm{integerdef}, \prm {dimensiondef}, \prm {gluespecdef} and \prm {mugluespecdef}}] It is rather common to store constant values in a register or character @@ -2834,9 +2268,9 @@ Experiments with constant strings made the engine source more complex than I wanted so that features was rejected. Of course we can use the prefixes mentioned in a previous section. -\stopsection +\stopsubsection -\startsection[title={Getting internal indices with \prm {indexofcharacter} and \prm {indexofregister}}] +\startsubsection[title={Getting internal indices with \prm {indexofcharacter} and \prm {indexofregister}}] When you have defined a register with one of the \tex {...def} primitives but for some reasons needs to know the register index you can query that: @@ -2871,9 +2305,9 @@ A similar primitive gives us the (normally \UNICODE) value of a character: The result is equivalent to \type {\number `A} but avoids the back quote: \inlinebuffer. -\stopsection +\stopsubsection -\startsection[title={Serialization with \prm {todimension}, \prm {toscaled}, \prm {tohexadecimal} and \prm {tointeger}}] +\startsubsection[title={Serialization with \prm {todimension}, \prm {toscaled}, \prm {tohexadecimal} and \prm {tointeger}}] These serializers take a verbose or symbolic quantity: @@ -2893,9 +2327,11 @@ when a value is stored in a macro. Using \type {\the} could fail there while: is often overkill and gives more noise in a trace. -\stopsection +\stopsubsection -\startsection[title={Serialization with \prm {thewithoutunit}, \prm {tosparsedimension} and \prm {tosparsescaled}}] +\startsubsection[title={Serialization with \prm {thewithoutunit}, \prm {tosparsedimension} and \prm {tosparsescaled}}] + +\topicindex {units} By default \TEX\ lets \type {1pt} come out as \type {1.0pt} which is why we also have two sparse variants: @@ -2916,9 +2352,33 @@ This time trailing zeros (and a trailing period) will be dropped: The \prm {thewithoutunit} primitive is like \prm {the} on a dimension but it omits the unit. +\stopsubsection + \stopsection -\startsection[title=Expressions with \prm {numexpression}, \prm {dimexpression}] +\startsection[title=Expressions] + +\startsubsection[title={Rounding and scaling}] + +\topicindex {expressions+traditional} + +The \type {*expr} parsers now accept \type {:} as operator for integer division +(the \type {/} operators does rounding. This can be used for division compatible +with \type {\divide}. I'm still wondering if adding a couple of bit operators +makes sense (for integers). + +The \prm{numericscale} parser is kind of special (and might evolve). For now it +converts a following number in a scale value as often used in \TEX, where 1000 +means scaling by~1.0. The trick is in the presence of a digit (or comma): 1.234 +becomes 1234 but 1234 stays 1234 and from this you can deduce that 12.34 becomes +123400. Internally \TEX\ calculates with integers, but this permits the macro +package to provide an efficient mix. + +\stopsubsection + +\startsubsection[title={Enhanced expressions}] + +\topicindex {expressions+enhanced} The \ETEX\ expression primitives are handy but have some limitations. Although the parsers have been rewritten in \LUAMETATEX\ and somewhat more efficient the @@ -3000,18 +2460,108 @@ The if|-|test shown before can be done using the new primitives \prm {ifdimexpression} and \prm {ifnumexpression} which are boolean tests with zero being \type {false}. +\stopsubsection + \stopsection -\startsection[title=Nodes] +\startsection[title=Loops] -The \ETEX\ primitive \type {\lastnodetype} is not honest in reporting the -internal numbers as it uses its own values. But you can set \type -{\internalcodesmode} to a non|-|zero value to get the real id's instead. In -addition there is \type {\lastnodesubtype}. +\topicindex {loops} -Another last one is \type {\lastnamedcs} which holds the last match but this one -should be used with care because one never knows if in the meantime something -else \quote {last} has been seen. +There is actually not that much to tell about the three loop primitives \prm +{expandedloop}, \prm {unexpandedloop} and \prm {localcontrolledloop}. They are +used like: + +\startbuffer +\unexpandedloop 1 10 1 { + [!] +} +\stopbuffer + +\typebuffer + +This will give 10 snippets. + +\getbuffer + +So what will the next give? + +\startbuffer +\edef\TestA{\unexpandedloop 1 10 1 {!}}\meaning\TestA +\edef\TestB{\expandedloop 1 10 1 {!}}\meaning\TestB +\stopbuffer + +\typebuffer + +We see no difference in results between the two loops: + +\startlines \tt +\getbuffer +\stoplines + +But the the next variant shows that they do: + +\startbuffer +\edef\TestA{\unexpandedloop 1 10 1 {\the\currentloopiterator}}\meaning\TestA +\edef\TestB{\expandedloop 1 10 1 {\the\currentloopiterator}}\meaning\TestB +\stopbuffer + +\typebuffer + +The unexpanded variants sort of delays: + +\startlines \tt +\getbuffer +\stoplines + +You can nest loops and query the nesting level: + +\startbuffer +\expandedloop 1 10 1 {% + \ifodd\currentloopiterator\else + [\expandedloop 1 \currentloopiterator 1 {% + \the\currentloopnesting + }] + \fi +} +\stopbuffer + +\typebuffer + +Here we use the two numeric state primitives \prm {currentloopiterator} and \prm +{currentloopnesting}. This results in: + +\getbuffer + +The \prm {quitloop} primitive makes it possible to prematurely exit a loop (at +the next step), although of course in the next case one can just adapt the final +iterator value instead. Here we step by 2: + +\startbuffer +\expandedloop 1 20 2 {% + \ifnum\currentloopiterator>10 + \quitloop + \else + [!] + \fi +} +\stopbuffer + +\typebuffer + +This results in: + +\getbuffer + +The \prm {lastloopiterator} primitive keeps the last iterator value and is a global +one as all \type {\last...} primitives. The loops also work with negative values. + +A special case is \prm {localcontrolledloop} which fits into the repertoire of +local control primitives. In that case the loop body gets expanded in a nested +main loop which can come in handy in tricky cases where full expansion is mixed +with for instance assignments but of course users should then be aware of +out|-|of|-|order side effects when you push back something in the input. Consider +it a playground. \stopsection |