%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 % todo: save settings % low level interface \registerctxluafile{page-lin}{1.001} \definesystemattribute[line-number] \chardef\linenumberattribute \dogetattributeid{line-number} \definesystemattribute[line-reference] \chardef\linereferenceattribute \dogetattributeid{line-reference} \appendtoksonce \attribute\linenumberattribute \attributeunsetvalue \to \everyforgetall \appendtoksonce \attribute\displaymathattribute\plusone \to \everybeforedisplayformula \newcount\linenumber \newbox \linenumberscratchbox \newcount\linenumberchunk \newcount\linerefcounter \newconditional\tracelinenumbering \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 dir % \def\mkskiplinenumber #1#2#3#4#6#5{} % \def\mkleftlinenumber #1#2#3#4#5#6{\hbox{\llap{#2\quad\hskip#3\scaledpoint}}} % \def\mkrightlinenumber#1#2#3#4#5#6{\hbox{\rlap{\hskip#4\scaledpoint\hskip#3\scaledpoint\quad#2}}} \let\makenumber\gobblesixarguments \newconditional\boxcontentneedsprocessing \def\mkdoprocesspagecontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone} \def\mkdoprocessboxcontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone} \def\mkdoprocesscolumncontents#1{\mkaddtextlinenumbers{#1}\currentcolumn\nofcolumns} \def\mklinenumberparameters {continue = "\linenumberparameter\c!continue", start = \linenumberparameter\c!start, step = \linenumberparameter\c!step, method = "\linenumberparameter\c!method", tag = "\currentlinenumbering"} \def\mklinenumberupdateparameters {continue = "\linenumberparameter\c!continue"} \def\mkdefinetextlinenumbering {\setxvalue{ln:c:\currentlinenumbering}{\number\ctxlua{tex.sprint(nodes.lines.boxed.register({\mklinenumberparameters}))}}} \def\mkupdatetextlinenumbering {\ctxlua{nodes.lines.boxed.setup(\getvalue{ln:c:\currentlinenumbering},{\mklinenumberupdateparameters})}} \def\mkstarttextlinenumbering#1#2% always when assignment {\globallet\mkprocesspagecontents \mkdoprocesspagecontents \globallet\mkprocesscolumncontents\mkdoprocesscolumncontents \global\settrue\boxcontentneedsprocessing % see core-rul.mkiv \edef\currentlinenumbering{#1}% \ifcase#2\relax \mkupdatetextlinenumbering % continue \or \mkdefinetextlinenumbering % only when assignment \fi \attribute\linenumberattribute\getvalue{ln:c:\currentlinenumbering}\relax} \def\mksetuptextlinenumbering {\ifcsname ln:c:\currentlinenumbering\endcsname \ctxlua{nodes.lines.boxed.setup(\getvalue{ln:c:\currentlinenumbering},{\mklinenumberparameters})}% \fi} \def\mkstoptextlinenumbering {\attribute\linenumberattribute\attributeunsetvalue} % we could make this a bit more efficient by putting the end reference % in the same table as the start one but why make things complex ... \let\dofinishlinereference\dofinishfullreference \def\mksomelinereference#1#2#3% {\dontleavehmode\begingroup \global\advance\linerefcounter\plusone \attribute\linereferenceattribute\linerefcounter #3% % for the moment we use a simple system i.e. no prefixes etc .. todo: store as number \expanded{\dodosetreference{line}{#2}{conversion=\linenumberparameter\c!conversion}{\the\linerefcounter}}% kind labels userdata text \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, 6=begin, 7=end \chardef\linenumberalignment = 5 % 0=middle, 1=left, 2=right, 5=auto \newevery \beforeeverylinenumbering \relax \newevery \aftereverylinenumbering \relax \newevery \everylinenumber \relax \newdimen\linenumberwidth \newdimen\linenumberdistance \unexpanded\def\definelinenumbering {\dosingleempty\dodefinelinenumbering} \def\dodefinelinenumbering[#1]% {\edef\currentlinenumbering{#1}% \mkdefinetextlinenumbering} \unexpanded\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} \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}} \setuplinenumbering [\c!conversion=\v!numbers, \c!start=1, \c!step=1, \c!method=\v!first, \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] \definelinenumbering \unexpanded\def\startlinenumbering {\dodoubleempty\dostartlinenumbering} % no intermediate changes in values, define a class, otherwise each range % would need a number % 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:l:\v!begin \endcsname \plussix \expandafter\chardef\csname\??rn:l:\v!end \endcsname \plusseven \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}% \doifassignmentelse{#2} {\getparameters[\??rn\currentlinenumbering][#2]} {\doifnumberelse{#2}% downward compatible {\setvalue{\??rn#1\c!start}{#2}}% {\doif{#2}\v!continue {\getparameters[\??rn\currentlinenumbering][\c!continue=\v!yes]% \chardef\linenumbermode\zerocount}}}% \else\iffirstargument \doifnumberelse{#1}% downward compatible {\let\currentlinenumbering\empty \setvalue{\??rn\c!start}{#1}}% {\doifelse{#1}\v!continue {\let\currentlinenumbering\empty \getparameters[\??rn\currentlinenumbering][\c!continue=\v!yes]% \chardef\linenumbermode\zerocount} {\def\currentlinenumbering{#1}}}% \fi\fi \doif{\linenumberparameter\c!continue}\v!yes {\chardef\linenumbermode\zerocount}% \numberinglinestrue \the\beforeeverylinenumbering \mkstarttextlinenumbering\currentlinenumbering\linenumbermode} \unexpanded\def\stoplinenumbering {\mkstoptextlinenumbering \the\aftereverylinenumbering \endgroup} % number placement \let\mkskiplinenumber \gobblesixarguments \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 \or \expandafter\mkdotextlinenumber \or \expandafter\mkdobeginlinenumber \or \expandafter\mkdoendlinenumber \fi} \def\mkrightlinenumber {\ifcase\linenumberlocation \expandafter\mkdorightlinenumber \or \expandafter\mkdorightlinenumber \or \expandafter\mkdorightlinenumber \or \expandafter\mkdoouterlinenumber \or \expandafter\mkdoinnerlinenumber \or \expandafter\mkdotextlinenumber \or \expandafter\mkdoendlinenumber \or \expandafter\mkdobeginlinenumber \fi} \def\mkaddtextlinenumbers#1#2#3% box col max {\bgroup \chardef\linenumberbox #1\relax \chardef\linenumbercolumn #2\relax \chardef\linenumberlastcolumn#3\relax \fullrestoreglobalbodyfont \def\skipnumber{\hbox{}}% \let\makenumber\maketextlinenumber \mkprocesstextlinenumbers\linenumberbox \egroup} \def\maketextlinenumber#1% {\edef\currentlinenumbering{#1}% \chardef\linenumberlocation \executeifdefined{\??rn:l:\linenumberparameter\c!location}\plusone % left \chardef\linenumberalignment\executeifdefined{\??rn:a:\linenumberparameter\c!align }\plusfive % auto \ifcase\linenumberlastcolumn\relax \let\domakenumber\mkskiplinenumber \or % one column \ifcase\linenumberlocation \let\domakenumber\mkskiplinenumber % hm \or \let\domakenumber\mkleftlinenumber \or \let\domakenumber\mkrightlinenumber \or % inner \let\domakenumber\mkdoinnerlinenumber \or % outer \let\domakenumber\mkdoouterlinenumber \or % text \let\domakenumber\mkdotextlinenumber \or \let\domakenumber\mkdobeginlinenumber \or \let\domakenumber\mkdoendlinenumber \fi \else\ifcase\linenumbercolumn\relax \let\domakenumber\mkskiplinenumber \or \let\domakenumber\mkleftlinenumber \ifcase\linenumberlocation\or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plustwo \else \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plusone % todo \or \chardef\linenumberlocation\plusone % todo \fi \else \let\domakenumber\mkrightlinenumber \ifcase\linenumberlocation\or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plusone \or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plustwo \or \chardef\linenumberlocation\plustwo % todo \or \chardef\linenumberlocation\plustwo % todo \fi \fi\fi \domakenumber{#1}} \def\mkdotextlinenumber #1#2#3#4#5#6% beware, one needs so compensate for this in the width ! {\hbox{\dosomelinenumber{#1}{2}{#2}{#5}\hskip#3\scaledpoint}} \def\mkdotextlinenumber #1#2#3#4#5#6% beware, one needs so compensate for this in the width ! {\hbox{\dosomelinenumber{#1}{2}{#2}{#5}\hskip#3\scaledpoint}} \def\mkdoleftlinenumber #1#2#3#4#5#6% {\naturalhbox to \zeropoint {\ifcase\istltdir#6\else \hskip-#4\scaledpoint \fi \llap{\dosomelinenumber{#1}{2}{#2}{#5}\kern#3\scaledpoint}}} \def\mkdorightlinenumber#1#2#3#4#5#6% {\naturalhbox to \zeropoint {\ifcase\istltdir#6\else \hskip-#4\scaledpoint \fi \rlap{\hskip#4\scaledpoint\hskip#3\scaledpoint\dosomelinenumber{#1}{1}{#2}{#5}}}} \def\mkdobeginlinenumber #1#2#3#4#5#6% {\ifcase\istltdir#6\relax \chardef\linenumberlocation\plusone \expandafter\mkdoleftlinenumber \else \chardef\linenumberlocation\plustwo \expandafter\mkdorightlinenumber \fi{#1}{#2}{#3}{#4}{#5}{#6}} \def\mkdoendlinenumber#1#2#3#4#5#6% {\ifcase\istltdir#6\relax \chardef\linenumberlocation\plustwo \expandafter\mkdorightlinenumber \else \chardef\linenumberlocation\plusone \expandafter\mkdoleftlinenumber \fi{#1}{#2}{#3}{#4}{#5}{#6}} \def\dosomelinenumber#1#2#3#4% tag 1=left|2=right linenumber leftskip {\begingroup \def\currentlinenumbering{#1}% \def\linenumber{#3}% unsafe \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}} \unexpanded\def\startline[#1]{\mkstartlinereference{#1}} \unexpanded\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\currentreferencelinenumber{\ctxlua{jobreferences.filter("linenumber")}} \def\doifelsesamelinereference#1#2#3% {\doifreferencefoundelse{lr:b:#1} {\edef\fline{\currentreferencelinenumber}% \doifreferencefoundelse{lr:e:#1} {\edef\tline{\currentreferencelinenumber}% %[\fline,\tline] \ifx\fline\tline#2\else#3\fi} {\unknownreference{#1}#2}} {\unknownreference{#1}#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]}}} \def\inlinerange[#1]% {\doifelsesamelinereference{#1} {\in[lr:b:#1]} {\in[lr:b:#1]--\in[lr:e:#1]}} \protect \endinput