%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 ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. % generic or not ... maybe not bother too much and simplify to mkiv only % get rid of \mk* (left over from experimental times) % % to be redone (was experiment) .. can be hooked into margin code \writestatus{loading}{ConTeXt Core Macros / Line Numbering} \unprotect % todo: save settings % % low level interface % % we should use normal counters but then we need to sync settings % not yet ok, we need to give the top line a proper height % % \newbox\locallinenumberbox % % \unexpanded\def\startlocallinenumbering % {\setbox\locallinenumberbox\vbox\bgroup % \startlinenumbering} % % \unexpanded\def\stoplocallinenumbering % {\stoplinenumbering % \egroup % \mkdoprocessdeepboxcontents\locallinenumberbox % \unvbox\locallinenumberbox} % some line % % \startlocallinenumbering % some source code 1\par % some source code 2\par % some source code 3\par % \stoplocallinenumbering % % some line \registerctxluafile{page-lin}{1.001} \definesystemattribute[linenumber] [public] \definesystemattribute[linereference][public] \appendtoksonce \attribute\linenumberattribute \attributeunsetvalue \to \everyforgetall \appendtoksonce \attribute\displaymathattribute\plusone \to \everybeforedisplayformula \newcount \linenumber % not used \newbox \linenumberscratchbox \newcount \linenumberchunk \newcount \linerefcounter \newconstant\linenumbernesting \newconditional\tracelinenumbering \def\mkprocesstextlinenumbers#1#2% {\setbox\linenumberscratchbox\vbox {\forgetall \offinterlineskip \ctxlua{nodes.lines.boxed.stage_one(\number#1,\ifcase\linenumbernesting false\else true\fi)}}% #2 \ctxlua{nodes.lines.boxed.stage_two(\number#1,\number\linenumberscratchbox)}}% can move to lua code % id nr shift width leftskip dir \let\makelinenumber\gobblesevenarguments \newconditional\boxcontentneedsprocessing \def\mkdoprocesspagecontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone \zerocount} \def\mkdoprocessboxcontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone \zerocount} \def\mkdoprocessdeepboxcontents#1{\mkaddtextlinenumbers{#1}\plusone \plusone \plusone } \def\mkdoprocesscolumncontents #1{\mkaddtextlinenumbers{#1}\currentcolumn\nofcolumns\zerocount} \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\cldcontext{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{\strc_references_set_named_reference{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 \setnewconstant\linenumbermode \plusone % 0=continue, 1=restart \setnewconstant\linenumberlocation \plusone % 0=middle, 1=left, 2=right, 3=inner, 4=outer, 5=text, 6=begin, 7=end \setnewconstant\linenumberalignment\plusfive % 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} % some day commandhandler \def\linenumberparameter#1% {\csname\??rn\ifcsname\??rn\currentlinenumbering#1\endcsname\currentlinenumbering\fi#1\endcsname} \unexpanded\def\dolinenumberattributes#1#2% {\dousestyleparameter{\linenumberparameter#1}% \dousecolorparameter{\linenumberparameter#2}} \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\let\csname\??rn:l:\v!middle \endcsname \zerocount \expandafter\let\csname\??rn:l:\v!left \endcsname \plusone \expandafter\let\csname\??rn:l:\v!margin \endcsname \plusone \expandafter\let\csname\??rn:l:\v!inmargin \endcsname \plusone \expandafter\let\csname\??rn:l:\v!inleft \endcsname \plusone \expandafter\let\csname\??rn:l:\v!right \endcsname \plustwo \expandafter\let\csname\??rn:l:\v!inright \endcsname \plustwo \expandafter\let\csname\??rn:l:\v!inner \endcsname \plusthree \expandafter\let\csname\??rn:l:\v!outer \endcsname \plusfour \expandafter\let\csname\??rn:l:\v!text \endcsname \plusfive \expandafter\let\csname\??rn:l:\v!begin \endcsname \plussix \expandafter\let\csname\??rn:l:\v!end \endcsname \plusseven \expandafter\let\csname\??rn:a:\v!middle \endcsname \zerocount \expandafter\let\csname\??rn:a:\v!right \endcsname \plusone \expandafter\let\csname\??rn:a:\v!flushleft \endcsname \plusone \expandafter\let\csname\??rn:a:\v!left \endcsname \plustwo \expandafter\let\csname\??rn:a:\v!flushright\endcsname \plustwo \expandafter\let\csname\??rn:a:\v!auto \endcsname \plusfive \def\dostartlinenumbering[#1][#2]% todo: c!continue {\begingroup \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]% \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]% \linenumbermode\zerocount} {\def\currentlinenumbering{#1}}}% \fi\fi \doif{\linenumberparameter\c!continue}\v!yes {\linenumbermode\zerocount}% \numberinglinestrue \the\beforeeverylinenumbering \mkstarttextlinenumbering\currentlinenumbering\linenumbermode} \unexpanded\def\stoplinenumbering {\mkstoptextlinenumbering \the\aftereverylinenumbering \endgroup} % number placement .. will change into (the new) margin code \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} \newconditional\faketextlinenumber \newconstant \linenumberbox \newconstant \linenumbercolumn \newconstant \linenumberlastcolumn \def\mkaddtextlinenumbers#1#2#3#4% box col max nesting {\bgroup \linenumberbox #1\relax \linenumbercolumn #2\relax \linenumberlastcolumn#3\relax \linenumbernesting #4\relax \fullrestoreglobalbodyfont \let\makelinenumber\maketextlinenumber \mkprocesstextlinenumbers\linenumberbox\linenumbernesting \egroup} \def\maketextlinenumber#1#2% {\edef\currentlinenumbering{#1}% \ifcase#2\relax \settrue \faketextlinenumber \else \setfalse\faketextlinenumber \fi \linenumberlocation \executeifdefined{\??rn:l:\linenumberparameter\c!location}\plusone % left \linenumberalignment\executeifdefined{\??rn:a:\linenumberparameter\c!align }\plusfive % auto \ifcase\linenumberlastcolumn\relax \settrue \faketextlinenumber \or % one column \ifcase\linenumberlocation \settrue \faketextlinenumber % hm \or \let\domakelinenumber\mkleftlinenumber \or \let\domakelinenumber\mkrightlinenumber \or % inner \let\domakelinenumber\mkdoinnerlinenumber \or % outer \let\domakelinenumber\mkdoouterlinenumber \or % text \let\domakelinenumber\mkdotextlinenumber \or \let\domakelinenumber\mkdobeginlinenumber \or \let\domakelinenumber\mkdoendlinenumber \fi \else\ifcase\linenumbercolumn\relax \settrue \faketextlinenumber \or \let\domakelinenumber\mkleftlinenumber \ifcase\linenumberlocation\or \linenumberlocation\plusone \or \linenumberlocation\plustwo \else \linenumberlocation\plusone \or \linenumberlocation\plusone \or \linenumberlocation\plusone \or \linenumberlocation\plusone % todo \or \linenumberlocation\plusone % todo \fi \else \let\domakelinenumber\mkrightlinenumber \ifcase\linenumberlocation\or \linenumberlocation\plustwo \or \linenumberlocation\plusone \or \linenumberlocation\plustwo \or \linenumberlocation\plustwo \or \linenumberlocation\plustwo % todo \or \linenumberlocation\plustwo % todo \fi \fi\fi \domakelinenumber{#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 \linenumberlocation\plusone \expandafter\mkdoleftlinenumber \else \linenumberlocation\plustwo \expandafter\mkdorightlinenumber \fi{#1}{#2}{#3}{#4}{#5}{#6}} \def\mkdoendlinenumber#1#2#3#4#5#6% {\ifcase\istltdir#6\relax \linenumberlocation\plustwo \expandafter\mkdorightlinenumber \else \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 \linenumberlocation\plusone \else \scratchdimen\zeropoint \fi \ifcase\linenumberalignment \linenumberlocation\zerocount % middle \or \linenumberlocation\plusone % left \or \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 \ifconditional\faketextlinenumber % we need to reserve space \else \dolinenumberattributes\c!style\c!color \linenumberparameter\c!command {\linenumberparameter\c!left \convertnumber{\linenumberparameter\c!conversion}{#3}% \linenumberparameter\c!right}% \fi \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 \unexpanded\def\someline [#1]{\mkstartlinereference{#1}\mkstoplinereference{#1}} % was just a def \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{structures.references.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} {#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]}}} \def\inlinerange[#1]% {\doifelsesamelinereference{#1} {\in[lr:b:#1]} {\in[lr:b:#1]--\in[lr:e:#1]}} \protect \endinput