%D \module %D [ file=page-lin, %D version=2007.11.29, %D title=\CONTEXT\ Core Macros, %D subtitle=Line Numbering, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA / Hans Hagen \& Ton Otten}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % generic or not ... maybe not bother too much and simplify to mkiv only \writestatus{loading}{Context Core Macros / Line Numbering} \unprotect % low level interface \defineattribute[line-number] \defineattribute[line-reference] \registerctxluafile{page-lin}{1.001} % \ctxluafileload{page-lin}{1.001} \appendtoksonce\doresetattribute{line-number}\to\everyforgetall \appendtoksonce\dosetattribute{display-math}{1}\to\everybeforedisplayformula \newbox \linenumberscratchbox \newcount\linenumberchunk \newcount\linerefcounter \newconditional\tracelinenumbering \def\mkaddtextlinenumbers#1#2#3% box col max {\bgroup \def\skipnumber{\hbox{}}% \ifcase#3\relax \let\makenumber\mkskiplinenumber \or \let\makenumber\mkleftlinenumber \else\ifcase#2\relax \let\makenumber\mkskiplinenumber \or \let\makenumber\mkleftlinenumber \else \let\makenumber\mkrightlinenumber \fi\fi \mkprocesstextlinenumbers{#1}% \egroup} \def\mkprocesstextlinenumbers#1% {\setbox\linenumberscratchbox\vbox{\forgetall\offinterlineskip\ctxlua{nodes.lines.boxed.stage_one(\number#1)}}% \ctxlua{nodes.lines.boxed.stage_two(\number#1,\number\linenumberscratchbox)}}% can move to lua code % id nr shift width leftskip \def\mkskiplinenumber #1#2#3#4#5{} \def\mkleftlinenumber #1#2#3#4#5{\hbox{\llap{#2\quad\hskip#3\scaledpoint}}} \def\mkrightlinenumber#1#2#3#4#5{\hbox{\rlap{\hskip#4\scaledpoint\hskip#3\scaledpoint\quad#2}}} \def\makenumber#1#2{\hbox{\llap{#1\quad\hskip#2\scaledpoint}}\endgraf}% \def\mkdoprocesspagecontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone} \def\mkdoprocessboxcontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone} \def\mkdoprocesscolumncontents#1{\mkaddtextlinenumbers{#1}\currentcolumn\nofcolumns} \def\mkcurrentstart{0} \def\mkcurrentstep {1} \def\mkdefinetextlinenumbering#1% {\begingroup \scratchcounter\ctxlua{tex.sprint(nodes.lines.boxed.register({start=\mkcurrentstart,step=\mkcurrentstep,tag="#1"}))}% \setxvalue{ln:c:#1}{\number\scratchcounter}% \endgroup} \def\mkstarttextlinenumbering#1#2% {\globallet\mkprocesspagecontents \mkdoprocesspagecontents \globallet\mkprocesscolumncontents\mkdoprocesscolumncontents \ifcase#2\relax % continue \or \mkdefinetextlinenumbering{#1}% restart \fi \dosetattribute{line-number}{\getvalue{ln:c:#1}}} \def\mksetuptextlinenumbering#1% {\ctxlua{nodes.lines.boxed.setup(\getvalue{ln:c:#1},{start=\mkcurrentstart,step=\mkcurrentstep,tag="#1"})}} \def\mkstoptextlinenumbering {\doresetattribute{line-number}} \def\mksomelinereference#1#2#3% {\dontleavehmode\begingroup \global\advance\linerefcounter\plusone \dosetattribute{line-reference}\linerefcounter #3\rawtextreference\s!lin{#2}{\noexpand\ctxlua{tex.sprint(nodes.lines.number(\the\linerefcounter))}}% \endgroup} \def\mkstartlinereference#1{\mksomelinereference{#1}{lr:b:#1}{}\ignorespaces} \def\mkstoplinereference #1{\removeunwantedspaces\mksomelinereference{#1}{lr:e:#1}{}} \def\mklinestartreference#1[#2]{\in{#1}[lr:b:#2]} % not interfaced \def\mklinestopreference #1[#2]{\in{#1}[lr:e:#2]} % not interfaced % high level interface \newif\ifnumberinglines \newif\iftypesettinglines \let\currentlinenumbering\empty \chardef\linenumbermode = 1 % 0=continue, 1=restart \chardef\linenumberlocation = 1 % 0=middle, 1=left, 2=right, 3=inner, 4=outer, 5=text \chardef\linenumberalignment = 5 % 0=middle, 1=left, 2=right, 5=auto \newevery \beforeeverylinenumbering \relax \newevery \aftereverylinenumbering \relax \newevery \everylinenumber \relax \newdimen\linenumberwidth \newdimen\linenumberdistance \def\definelinenumbering {\dosingleempty\dodefinelinenumbering} \def\dodefinelinenumbering[#1]% {\def\currentlinenumbering{#1}% \mkdefinetextlinenumbering\currentlinenumbering} \def\setuplinenumbering {\dodoubleempty\dosetuplinenumbering} \def\dosetuplinenumbering[#1][#2]% {\ifsecondargument \def\currentlinenumbering{#1}% \getparameters[\??rn#1][#2]% \else \let\currentlinenumbering\empty \getparameters[\??rn][#1]% \fi \mksetuptextlinenumbering\currentlinenumbering} \def\linenumberparameter#1% {\csname\??rn\ifcsname\??rn\currentlinenumbering#1\endcsname\currentlinenumbering\fi#1\endcsname} \def\linenumberattributes {\doattributes{\??rn\ifcsname\??rn\currentlinenumbering\c!style\endcsname\currentlinenumbering\fi}} \definelinenumbering \setuplinenumbering [\c!conversion=\v!numbers, \c!start=1, \c!step=1, \c!continue=v!no, \c!location=\v!left, \c!style=, \c!color=, \c!width=2em, \c!left=, \c!right=, \c!command=, \c!distance=\zeropoint, \c!align=\v!auto] \def\startlinenumbering {\dodoubleempty\dostartlinenumbering} % no intermediate changes in values, define a class, otherwise each range % would need a number \def\mkcurrentstart{\linenumberparameter\c!start} \def\mkcurrentstep {\linenumberparameter\c!step } % todo: text \expandafter\chardef\csname\??rn:l:\v!middle \endcsname \zerocount \expandafter\chardef\csname\??rn:l:\v!left \endcsname \plusone \expandafter\chardef\csname\??rn:l:\v!margin \endcsname \plusone \expandafter\chardef\csname\??rn:l:\v!inmargin\endcsname \plusone \expandafter\chardef\csname\??rn:l:\v!inleft \endcsname \plusone \expandafter\chardef\csname\??rn:l:\v!right \endcsname \plustwo \expandafter\chardef\csname\??rn:l:\v!inright \endcsname \plustwo \expandafter\chardef\csname\??rn:l:\v!inner \endcsname \plusthree \expandafter\chardef\csname\??rn:l:\v!outer \endcsname \plusfour \expandafter\chardef\csname\??rn:l:\v!text \endcsname \plusfive \expandafter\chardef\csname\??rn:a:\v!middle \endcsname \zerocount \expandafter\chardef\csname\??rn:a:\v!right \endcsname \plusone \expandafter\chardef\csname\??rn:a:\v!flushleft \endcsname \plusone \expandafter\chardef\csname\??rn:a:\v!left \endcsname \plustwo \expandafter\chardef\csname\??rn:a:\v!flushright\endcsname \plustwo \expandafter\chardef\csname\??rn:a:\v!auto \endcsname \plusfive \def\dostartlinenumbering[#1][#2]% todo: c!continue {\begingroup \chardef\linenumbermode\plusone \ifsecondargument \def\currentlinenumbering{#1}% \doifnumberelse{#2}% downward compatible {\setvalue{\??rn#1\c!start}{#2}}% {\doif{#2}\v!continue{\chardef\linenumbermode\zerocount}}% \else\iffirstargument \doifnumberelse{#1}% downward compatible {\let\currentlinenumbering\empty \setvalue{\??rn\c!start}{#1}}% {\doifelse{#1}\v!continue {\let\currentlinenumbering\empty \chardef\linenumbermode\zerocount} {\def\currentlinenumbering{#1}}}% \fi\fi \doifelse{\linenumberparameter\c!continue}\v!yes {\chardef\linenumbermode\zerocount}% \numberinglinestrue \the\beforeeverylinenumbering \mkstarttextlinenumbering\currentlinenumbering\linenumbermode} \def\stoplinenumbering {\mkstoptextlinenumbering \the\aftereverylinenumbering \endgroup} % number placement \let\mkskiplinenumber \gobblefivearguments \def\mkdoinnerlinenumber{\doifoddpageelse\mkdoleftlinenumber\mkdorightlinenumber} \def\mkdoouterlinenumber{\doifoddpageelse\mkdorightlinenumber\mkdoleftlinenumber} \def\mkleftlinenumber {\ifcase\linenumberlocation \expandafter\mkdoleftlinenumber \or \expandafter\mkdoleftlinenumber \or \expandafter\mkdoleftlinenumber \or \expandafter\mkdoinnerlinenumber \or \expandafter\mkdoouterlinenumber \fi} \def\mkrightlinenumber {\ifcase\linenumberlocation \expandafter\mkdorightlinenumber \or \expandafter\mkdorightlinenumber \or \expandafter\mkdorightlinenumber \or \expandafter\mkdoouterlinenumber \or \expandafter\mkdoinnerlinenumber \fi} \def\mkaddtextlinenumbers#1#2#3% box col max {\bgroup \def\skipnumber{\hbox{}}% \ifcase#3\relax \let\makenumber\mkskiplinenumber \or \let\makenumber\mkleftlinenumber \else\ifcase#2\relax \let\makenumber\mkskiplinenumber \or \let\makenumber\mkdoleftlinenumber \ifcase\linenumberlocation\or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plusone \fi \else \let\makenumber\mkdorightlinenumber \ifcase\linenumberlocation\or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plustwo \fi \fi\fi \mkprocesstextlinenumbers{#1}% \egroup} \def\mkdoleftlinenumber #1#2#3#4#5% {\hbox{\llap{\dosomelinenumber{#1}{2}{#2}{#5}\hskip#3\scaledpoint}}} \def\mkdorightlinenumber#1#2#3#4#5% {\hbox{\rlap{\hskip#4\scaledpoint\hskip#3\scaledpoint\dosomelinenumber{#1}{1}{#2}{#5}}}} \def\dosomelinenumber#1#2#3#4% tag 1=left|2=right linenumber leftskip {\begingroup \def\currentlinenumbering{#1}% \chardef\linenumberlocation \executeifdefined{\??rn:l:\linenumberparameter\c!location}\plusone % left \chardef\linenumberalignment\executeifdefined{\??rn:a:\linenumberparameter\c!align }\plusfive % auto \doifelse{\linenumberparameter\c!width}\v!margin {\linenumberwidth\leftmarginwidth} {\linenumberwidth\linenumberparameter\c!width}% \linenumberdistance\linenumberparameter\c!distance\relax \ifcase#2\relax\or\hskip\linenumberdistance\fi\relax \ifnum\linenumberlocation=\plusfive \scratchdimen\dimexpr#4\scaledpoint-\linenumberdistance\relax \chardef\linenumberlocation\plusone \else \scratchdimen\zeropoint \fi \ifcase\linenumberalignment \chardef\linenumberlocation\zerocount % middle \or \chardef\linenumberlocation\plusone % left \or \chardef\linenumberlocation\plustwo % right \fi \ifconditional\tracelinenumbering\ruledhbox\else\hbox\fi to \linenumberwidth {\ifcase\linenumberlocation \hss % middle \or % left \or \hss % right \or \doifoddpageelse\relax\hss % inner \or \doifoddpageelse\hss\relax % outer \fi \linenumberattributes\c!style\c!color {\linenumberparameter\c!command {\linenumberparameter\c!left \convertnumber{\linenumberparameter\c!conversion}{#3}% \linenumberparameter\c!right}}% \ifcase\linenumberlocation \hss % middle \or \hss % left \or % right \or \doifoddpageelse\hss\relax % inner \or \doifoddpageelse\relax\hss % outer \fi}% \ifcase#2\relax\or\or\hskip\linenumberdistance\fi\relax \hskip-\scratchdimen \the\everylinenumber \endgroup} % left right inner outer % align: \alignedline\@@rnalign\v!right{\box0\hskip\@@rndistance} % referencing \def\someline [#1]{\mkstartlinereference{#1}\mkstoplinereference{#1}} \def\startline[#1]{\mkstartlinereference{#1}} \def\stopline [#1]{\mkstoplinereference {#1}} \def\mkshowstartlinereference#1% {\ifconditional\tracelinenumbering \setbox\scratchbox\hbox{\llap {\vrule\!!width\onepoint\!!depth\strutdp\!!height.8\strutht\raise.85\strutht\hbox{\llap{\tt\txx#1}}}}% \smashbox\scratchbox\box\scratchbox \fi} \def\mkshowstoplinereference#1% {\ifconditional\tracelinenumbering \setbox\scratchbox\hbox{\rlap {\raise.85\strutht\hbox{\rlap{\tt\txx#1}}\vrule\!!width\onepoint\!!depth\strutdp\!!height.8\strutht}}% \smashbox\scratchbox\box\scratchbox \fi} \def\mkstartlinereference#1{\mksomelinereference{#1}{lr:b:#1}{\mkshowstartlinereference{#1}}\ignorespaces} \def\mkstoplinereference #1{\removeunwantedspaces\mksomelinereference{#1}{lr:e:#1}{\mkshowstoplinereference{#1}}} % eventually we will do this in lua \def\doifelsesamelinereference#1#2#3% {\doifreferencefoundelse{lr:b:#1} {\let\fline\currenttextreference \doifreferencefoundelse{lr:e:#1} {\let\tline\currenttextreference \ifx\fline\tline#2\else#3\fi} {#2}} {#2}} \def\inline#1[#2]% {\doifelsenothing{#1} {\doifelsesamelinereference{#2} {\in{\leftlabeltext\v!line}{\rightlabeltext\v!line}[lr:b:#2]} {\in{\leftlabeltext\v!lines}{}[lr:b:#2]--\in{}{\rightlabeltext\v!lines}[lr:e:#2]}} {\doifelsesamelinereference{#2} {\in{#1}[lr:b:#2]} {\in{#1}[lr:b:#2]--\in[lr:e:#2]}}} \protect \endinput \iffalse % \iftrue \appendtoks\ctxlua{nodes.lines.flowed.prepare()}\to\everyshipout \appendtoks\ctxlua{nodes.lines.flowed.cleanup()}\to\everybye \def\mkstarttextlinenumbering#1#2% {\ctxlua{nodes.lines.flowed.prepare(#1)}% \dosetattribute{line-number}{#1}} \def\mkstoptextlinenumbering {\doresetattribute{line-number}} \def\mkmaketextlinenumber#1#2% {\hbox \bgroup \ifcase#2\relax % \or \llap{#1\quad\hskip#2\scaledpoint}% \else \rlap{\hskip\textwidth\quad#1\hskip#2\scaledpoint}% \fi \egroup} \ctxlua{ nodes.lines.scratchbox = \number\linenumberscratchbox ; % callback.register('vpack_filter', nodes.lines.flowed.apply) callback.register('post_linebreak_filter', nodes.lines.flowed.apply) } \fi