% language=us runpath=texruns:manuals/lowlevel \startcomponent lowlevel-marks \environment lowlevel-style \startdocument [title=marks, color=middlemagenta] \startsection[title=Introduction] Marks are one of the subsystems of \TEX, as are for instance alignments and math as well as inserts which they share some properties with. Both inserts and marks put signals in the list that later on get intercepted and can be used to access stored information. In the case of inserts this is typeset materials, like footnotes, and in the case of marks it's token lists. Inserts are taken into account when breaking pages, and marks show up when a page has been broken and is presented to the output routine. Marks are used for running headers but other applications are possible. In \MKII\ marks are used to keep track of colors, transparencies and more properties that work across page boundaries. It permits picking up at the top of a page from where one left at the bottom of the preceding one. When \MKII\ was written there was only one mark so on top of that a multiple mark mechanism was implemented that filtered specific marks from a collection. Later, \ETEX\ provided mark classes so that mechanism could be simplified. Although it is not that hard to do, this extension to \TEX\ didn't add any further features, so we can assume that there was no real demand for that. \footnote {This is probably true for most \LUATEX\ and \LUAMETATEX\ extensions, maybe example usage create retrospective demand. But one reason for picking up on engine development is that in the \CONTEXT\ perspective we actually had some demands.} But, marks have some nasty limitations, so from the \CONTEXT\ perspective there always was something to wish for. When you hide marks in boxes they will not be seen (the same is true for inserts). You cannot really reset them either. Okay, you can set them to nothing, but even then already present marks are still there. The \LUATEX\ engine has a \type {\clearmarks} primitive but that works global. In \LUAMETATEX\ a proper mark flusher is available. That engine also can work around the deeply nested disappearing marks. In addition, the current state of a mark can be queried and we have some tracing facilities. In \MKIV\ the engine's marks were not used at all and an alternative mechanism was written using \LUA. It actually is one of the older \MKIV\ features. It doesn't have the side effects that native marks have but it comes at the price of more overhead, although that is bearable. In this document we discuss marks but assume that \LUAMETATEX\ is used with \CONTEXT\ \LMTX. There we experiment with using the native marks, complemented by a few \LUA\ mechanisms, but it is to be seen if that will be either a replacement or an alternative. \stopsection \startsection[title=The basics] Although the original \TEX\ primitives are there, the plural \ETEX\ mark commands are to be used. Marks, signals with token lists, are set with: \starttyping[option=TEX] \marks0{This is mark 0} % equivalent to: \mark{This is mark 0} \marks4{This is mark 4} \stoptyping When a page has been split off, you can (normally this only makes sense in the output routine) access marks with: \starttyping[option=TEX] \topmarks 4 \firstmarks4 \botmarks 4 \stoptyping A \quote {top} mark is the last one on the previous page(s), the \quote {first} and \quote {bottom} refer to the current page. A mark is a so called node, something that ends up in the current list and the token list is stored with it. The accessors are just commands and they fetch the token list from a separately managed storage. When you set or access a mark that has not yet been used, the storage is bumped to the right size, so it doesn't make sense to use e.g. \type {\marks 999} when there are no 998 ones too: it not only takes memory, it also makes \TEX\ run over all these mark stores when synchronization happens. The best way to make sure that you are sparse is: \starttyping[option=TEX] \newmarks\MyMark \stoptyping Currently the first 16 marks are skipped so this makes \type {\MyMark} become mark 17. The reason is that we want to make sure that users who experiment with marks have some scratch marks available and don't overload system defined ones. Future versions of \CONTEXT\ might become more restrictive. Marks can be cleared with: \starttyping[option=TEX] \clearmarks 4 \stoptyping which clears the storage that keeps the top, first and bot marks. This happens immediately. You can delay this by putting a signal in the list: \starttyping[option=TEX] \flushmarks 4 \stoptyping This (\LUAMETATEX) feature makes it for instance easy to reset marks that keep track of section (and lower) titles when a new chapter starts. Of course it still means that one has to implement some mechanism that deals with this but \CONTEXT\ always had that. The current, latest assigned, value of a mark is available too: \starttyping[option=TEX] \currentmarks 4 \stoptyping Using this value in for instance headers and footers makes no sense because the last node set can be on a following page. \stopsection \startsection[title=Migration] In the introduction we mentioned that \LUAMETATEX\ has migration built in. In \MKIV\ we have this as option too, but there it is delegated to \LUA. It permits deeply nested inserts (notes) and marks (but we don't use native marks in \MKIV). Migrated marks end up in the postmigrated sublist of a box. In other lowlevel manuals we discuss these pre- and postmigrated sublists. As example we use this definition: \startbuffer \setbox0\vbox\bgroup test \marks 4 {mark 4.1}\par test \marks 4 {mark 4.1}\par test \marks 4 {mark 4.1}\par \egroup \stopbuffer \typebuffer[option=TEX] % {\automigrationmode"FF \getbuffer\showbox0} % {\automigrationmode"00 \getbuffer\showbox0} When we turn migration on (officially the second bit): \starttyping[option=TEX] \automigrationmode"FF \showbox0 \stoptyping we get this: \start \switchtobodyfont[5pt] \starttyping[option=TEX] > \box0= 2:4: \vbox[normal][...], width 483.69687, height 63.43475, depth 0.15576, direction l2r 2:4: .\list 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: ..\glue[par][...] 11.98988pt plus 3.99663pt minus 3.99663pt 2:4: ..\glue[baseline][...] 8.34883pt 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: ..\glue[par][...] 11.98988pt plus 3.99663pt minus 3.99663pt 2:4: ..\glue[baseline][...] 8.34883pt 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: .\postmigrated 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} \stoptyping \stop When we don't migrate, enforced with: \starttyping[option=TEX] \automigrationmode"00 \showbox0 \stoptyping the result is: \start \switchtobodyfont[5pt] \starttyping[option=TEX] > \box0= 2:4: \vbox[normal][...], width 483.69687, height 63.43475, depth 0.15576, direction l2r 2:4: .\list 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} 2:4: ..\glue[par][...] 11.98988pt plus 3.99663pt minus 3.99663pt 2:4: ..\glue[baseline][...] 8.34883pt 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} 2:4: ..\glue[par][...] 11.98988pt plus 3.99663pt minus 3.99663pt 2:4: ..\glue[baseline][...] 8.34883pt 2:4: ..\hbox[line][...], width 483.69687, height 7.48193, depth 0.15576, glue 459.20468fil, direction l2r 2:4: ...\list 2:4: ....\glue[left hang][...] 0.0pt 2:4: ....\glue[left][...] 0.0pt 2:4: ....\glue[parfillleft][...] 0.0pt 2:4: ....\par[newgraf][...], hangafter 1, hsize 483.69687, pretolerance 100, tolerance 200, adjdemerits 10000, linepenalty 10, doublehyphendemerits 10000, finalhyphendemerits 5000, clubpenalty 2000, widowpenalty 2000, brokenpenalty 100, parfillskip 0.0pt plus 1.0fil, hyphenationmode 499519 2:4: ....\glue[indent][...] 0.0pt 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000065 e 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000073 s 2:4: ....\glyph[32768][...], language (n=1,l=2,r=3), hyphenationmode "79F3F, options "80, font <8: DejaVuSerif @ 11.0pt>, glyph U+000074 t 2:4: ....\glue[space][...] 3.49658pt plus 1.74829pt minus 1.16553pt, font 8 2:4: ....\penalty[line][...] 10000 2:4: ....\glue[parfill][...] 0.0pt plus 1.0fil 2:4: ....\glue[right][...] 0.0pt 2:4: ....\glue[right hang][...] 0.0pt 2:4: ..\mark[4][...] 2:4: ..{mark 4.1} \stoptyping \stop When you say \type {\showmakeup} or in this case \type {\showmakeup[mark]} the marks are visualized: \startlinecorrection \startcombination {\framed{\automigrationmode"FF \showmakeup[mark]\hsize2cm \getbuffer\box0}} {enabled} {\framed{\automigrationmode"00 \showmakeup[mark]\hsize2cm \getbuffer\box0}} {disabled} \stopcombination \stoplinecorrection Here \type {sm} means \quote {set mark} while \type {rm} would indicate a \quote {reset mark}. Of course migrated marks don't show up because these are bound to the box and thereby have become a a specific box property as can be seen in the above trace. \stopsection \startsection[title=Tracing] The \LUAMETATEX\ engine has a dedicated tracing option for marks. The fact that the traditional engine doesn't have this can be seen as indication that this is seldom needed. \starttyping[option=TEX] \tracingmarks1 \tracingonline2 \stoptyping When tracing is set to 1 we get a list of marks for the just split of page: \starttyping 2:7: 2:7: ..{sample 9.1} 2:7: 2:7: ..{sample 10.1} 2:7: 2:7: ..{sample 10.1} 2:7: 2:7: ..top {sample 9.1} 2:7: ..first {sample 10.1} 2:7: ..bot {sample 10.1} \stoptyping When tracing is set to 2 you also get details we get a list of marks of the analysis: \starttyping 1:9: 1:9: ..{sample 5.1} 1:9: 1:9: ..{sample 6.1} 1:9: 1:9: ..{sample 6.1} 1:9: 1:9: ..{sample 7.1} 1:9: 1:9: ..{sample 8.1} 1:9: 1:9: ..{sample 9.1} 1:9: 1:9: ..top {sample 5.1} 1:9: ..first {sample 6.1} 1:9: ..bot {sample 9.1} \stoptyping \stopsection \startsection[title=High level commands] I think that not that many users define their own marks. They are useful for showing section related titles in headers and footers but the implementation of that is hidden. The native mark references are \type {top}, \type {first} and \type {bottom} but in the \CONTEXT\ interface we use different keywords. \starttabulate[|||||] \FL \BC \CONTEXT \BC \TEX \BC column \BC page \NC \NR \ML \NC \type {previous} \NC top \NC last before sync \NC last on previous page \NC \NR %NC \type {next} \NC \NC first after sync \NC \NC \NR \NC \type {top} \NC first \NC first in sync \NC first on page \NC \NR \NC \type {bottom} \NC bot \NC last in sync \NC last on page \NC \NR \NC \type {first} \NC top \NC first not top in sync \NC first on page \NC \NR \NC \type {last} \NC bot \NC last not bottom in sync \NC last on page \NC \NR \ML \NC \type {default} \NS[2][c] the same as \type {first} \NC \NR \NC \type {current} \NS[2][c] the last set value \NC \NR \LL \stoptabulate In order to separate marks in \CONTEXT\ from those in \TEX, the term \quote {marking} is used. In \MKIV\ the regular marks mechanism is of course there but, as mentioned, not used. By using a different namespace we could make the transition from \MKII\ to \MKIV\ (the same is true for some more mechanisms). A marking is defined with \starttyping[option=TEX] \definemarking[MyMark] \stoptyping A defined marking can be set with two equivalent commands: \starttyping[option=TEX] \setmarking[MyMark]{content} \marking [MyMark]{content} \stoptyping The content is not typeset but stored as token list. In the sectioning mechanism that uses markings we don't even store titles, we store a reference to a title. In order to use that (deep down) we hook in a filter command. By default that command does nothing: \starttyping[option=TEX] \setupmarking[MyMark][filtercommand=\firstofoneargument] \stoptyping The token list does {\em not} get expanded by default, unless you set it up: \starttyping[option=TEX] \setupmarking[MyMark][expansion=yes] \stoptyping The current state of a marking can be cleared with: \starttyping[option=TEX] \clearmarking[MyMark] \stoptyping but because that en is not synchronized the real deal is: \starttyping[option=TEX] \resetmarking[MyMark] \stoptyping Be aware that it introduces a node in the list. You can test if a marking is defined with (as usual) a test macro. Contrary to (most) other test macros this one is fully expandable: \starttyping[option=TEX] \doifelsemarking {MyMark} { defined } { undefined } \stoptyping Because there can be a chain involved, we can relate markings. Think of sections below chapters and subsections below sections: \starttyping[option=TEX] \relatemarking[MyMark][YourMark] \stoptyping When a marking is set its relatives are also reset, so setting \type {YourMark} will reset \type {MyMark}. It is this kind of features that made for marks being wrapped into high level commands very early in the \CONTEXT\ development (and one can even argue that this is why a package like \CONTEXT\ exists in the first place). The rest of the (relatively small) repertoire of commands has to do with fetching markings. The general command is \type {\getmarking} that takes two or three arguments: \starttyping[option=TEX] \getmarking[MyMarking][first] \getmarking[MyMarking][page][first] \getmarking[MyMarking][page][first] \getmarking[MyMarking][column:1][first] \stoptyping There are (normally) three marks that can be fetched so we have three commands that do just that: \starttyping[option=TEX] \fetchonemark [MyMarking][which one] \fetchtwomarks[MyMarking] \fetchallmarks[MyMarking] \stoptyping You can setup a \type {separator} key which by default is: \starttyping[option=TEX] \setupmarking[MyMarking][separator=\space\emdash\space] \stoptyping Injection is enabled by default due to this default: \starttyping[option=TEX] \setupmarking[MyMarking][state=start] \stoptyping The following three variants are (what is called) fully expandable: \starttyping[option=TEX] \fetchonemarking [MyMarking][which one] \fetchtwomarkings[MyMarking] \fetchallmarkings[MyMarking] \stoptyping % \resetsynchronizemarking[#1]% % \synchronizemarking[#1][#2][#3]% (#3: options (no longer used)) \stopsection \startsection[title=Pitfalls] The main pitfall is that a (re)setting a mark will inject a node which in vertical mode can interfere with spacing. In for instance section commands we wrap them with the title so there it should work out okay. \stopsection \stopdocument