%D \module %D [ file=mult-aux, %D version=2010.08.2, %D title=\CONTEXT\ Multilingual Macros, %D subtitle=helpers, %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. %D A generalization of \MKIV-like inheritance. Just something to play %D with (interface might change). The code here evolved in an email %D exchange between me and Wolgang Schuster. \writestatus{loading}{ConTeXt Multilingual Macros / Helpers} \registerctxluafile{mult-aux}{1.001} \unprotect %D \starttyping %D \unprotect %D \def\????aa{@@@@aa} %D %D \installparameterhandler \????aa {whatever} %D \installsetuphandler \????aa {whatever} %D \installdefinehandler \????aa {whatever} \????aa % #3 == defaultroot %D \installfontandcolorhandler\????aa {whatever} %D %D % \installcommandhandler \????aa {whatever} \????aa %D \protect %D %D % \whateverparameter \c!test %D % \whateverparameterhash \c!test %D % \namedwhateverparameter \mycurrentwhatever \c!test %D % \dosetwhateverstyleandcolor \c!style \c!color %D % \everydefinewhatever (sets \currentwhatever) %D % \everypresetwhatever (can be used to reset parameters as we can redefine) %D % \everysetupwhatever (sets \currentwhatever) %D %D \starttext %D \definewhatever[first] \definewhatever[second][first] %D test: \def\currentwhatever{first} \whateverparameter{method} \par %D \setupwhatever [method=unset] test: \def\currentwhatever{first} \whateverparameter{method} \par %D \setupwhatever[first] [method=first] test: \def\currentwhatever{first} \whateverparameter{method} \par %D test: \def\currentwhatever{second} \whateverparameter{method} \par %D \setupwhatever[second][method=second] test: \def\currentwhatever{second} \whateverparameter{method} \par %D \stoptext %D \stoptyping % problem: every* could clash % % There can be less {} in the following definitions if we assume \??aa and \c!somecs % % todo: \def\detokenized...parameter#1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2\endcsname}} % always root % % it might be more efficient to do this at the lua and % % watch the push/pop and predefinition of current .. this is needed for nested % definitions and overloaded defines using the predefined one % todo: add (relaxed) postsetup and postdefine hooks, just after the everys % Start of experimental code: especially tables can have many assignments % and although most time is spent in the typesetting anyway, we can squeeze % out a little bit. Of course having 500 rows of 50 columns each with some % setting does not happen that often. One should keep in mind that in the % average document having some 500 assignments is no exception but there we're % talking of neglectable runtime for them. Of course in the definitions below % there is no real gain, only in the generated \setup* commands. Another % situation with many assignments is \XML\ where we can pass attributes % and normally don't do testing of them making sense. % % \testfeatureonce{100000}{\getparameters[bla][a=111,b=222,c=333]}% 1.669s % \testfeatureonce{100000}{\get_parameters{bla} [a=111,b=222,c=333]}% 1.529s % \testfeatureonce{100000}{\def\current_parameter_namespace{bla}\get_parameters_indeed[a=111,b=222,c=333]}% 1.466s % % \get_parameter {...} [...] % \def\current_parameter_namespace{...} \get_parameter_indeed[...] \def\get_parameters#1[#2% {\if\noexpand#2]% \expandafter\gobbleoneargument \else \def\current_parameter_namespace{#1}% \expandafter\get_parameters_indeed \fi#2} % \def\get_parameters#1% we can assume that the test already happened % {\def\current_parameter_namespace{#1}% % \get_parameters_indeed} \def\get_parameters_indeed#1]% namespace already set {\get_parameters_item#1,],\@relax@} \def\get_parameters_item#1,#2% #2 takes space before , {\if,#1,% dirty trick for testing #1=empty \expandafter\get_parameters_item \else\if]#1% \doubleexpandafter\gobbleoneargument \else \get_parameters_assign#1==\empty\@relax@ \doubleexpandafter\get_parameters_item \fi\fi#2} \def\get_parameters_error#1#2#3% {\showassignerror{#2}{\the\inputlineno\space(#1)}} \def\get_parameters_assign#1=#2=#3#4\@relax@ {\ifx\empty#1\empty \expandafter\get_parameters_error \else\ifx#3\empty \doubleexpandafter\get_parameters_error \else \doubleexpandafter\dosetvalue \fi\fi \current_parameter_namespace{#1}{#2}} % End of experimental code. \unexpanded\def\doinstallparameterhandler#1#2#3#4#5#6#7#8#9% inlining \csname*\endcsname is more efficient (#3 and #6 only) {\ifx#2\relax\let#2\empty\fi % it is hardly faster but produces less expansion tracing %\def#3##1{\csname#4{#1#2}{##1}\endcsname}% \def#3##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}% \def#4##1##2{\ifcsname##1:##2\endcsname##1:##2\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% \def#5##1##2{\ifx##1\relax\s!empty\else#4{##1}{##2}\fi}% is {} needed around ##1 ? %\def#6##1##2{\csname#4{#1##1}{##2}\endcsname}% \def#6##1##2{\csname\ifcsname#1##1:##2\endcsname#1##1:##2\else\expandafter#5\csname#1##1:\s!parent\endcsname{##2}\fi\endcsname}% \def#7##1{\detokenize\expandafter\expandafter\expandafter{\csname#1#2:##1\endcsname}}% always root, no backtrack \def#8##1{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\s!empty\fi\endcsname}% \def#9##1{\csname#1#2:##1\endcsname}} \unexpanded\def\installparameterhandler#1#2% {\normalexpanded {\doinstallparameterhandler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname do#2parameter\endcsname \expandafter\noexpand\csname do#2parentparameter\endcsname \expandafter\noexpand\csname named#2parameter\endcsname \expandafter\noexpand\csname detokenized#2parameter\endcsname \expandafter\noexpand\csname strict#2parameter\endcsname % checked \expandafter\noexpand\csname direct#2parameter\endcsname}} % unchecked \unexpanded\def\doinstallrootparameterhandler#1#2#3% {\def#2##1{\detokenize\expandafter\expandafter\expandafter{\csname#1:##1\endcsname}}% always root \def#3##1{\csname\ifcsname#1:##1\endcsname#1:##1\else\s!empty\fi\endcsname}} \unexpanded\def\installrootparameterhandler#1#2% {\normalexpanded {\doinstallrootparameterhandler {\noexpand#1}% \??aa \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname \expandafter\noexpand\csname root#2parameter\endcsname}} \unexpanded\def\doinstallparameterhashhandler#1#2#3#4#5#6#7#8#9% {\ifx#2\relax\let#2\empty\fi \def#3##1{#4{#1#2}{##1}:}% \def#4##1##2{\ifcsname##1:##2\endcsname##1\else\expandafter#5\csname##1:\s!parent\endcsname{##2}\fi}% \def#5##1##2{\ifx##1\relax\else#4{##1}{##2}\fi}% is {} needed around ##1 ? \def#6{#1#2:}% \def#7##1{#1##1:}% \def#8{\ifx#2\empty\else\ifcsname#1#2:\s!parent\endcsname\else\expandafter\let\csname#1#2:\s!parent\endcsname#1\fi\fi}% \unexpanded\def#9##1{\expandafter\edef\csname#1##1:\s!parent\endcsname{#1#2}}} \unexpanded\def\installparameterhashhandler#1#2% {\normalexpanded {\doinstallparameterhashhandler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameterhash\endcsname \expandafter\noexpand\csname do#2parameterhash\endcsname \expandafter\noexpand\csname do#2parentparameterhash\endcsname \expandafter\noexpand\csname current#2hash\endcsname \expandafter\noexpand\csname named#2hash\endcsname \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname chaintocurrent#2\endcsname}} \unexpanded\def\doinstallparametersethandler#1#2#3#4#5% we can speed this up for english {\ifx#2\relax\let#2\empty\fi \unexpanded\def#3{\dosetvalue{#1#2:}}% ##1 {##2} (braces are mandate) \unexpanded\def#4{\doletvalue{#1#2:}}% ##1 ##2 \unexpanded\def#5{\doletvalue{#1#2:}\empty}}% ##1 \startinterface english \unexpanded\def\doinstallparametersethandler#1#2#3#4#5% {\ifx#2\relax\let#2\empty\fi \unexpanded\def#3##1{\expandafter\def\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) \unexpanded\def#4##1{\expandafter\let\csname#1#2:##1\endcsname}% ##1 ##2 \unexpanded\def#5##1{\expandafter\let\csname#1#2:##1\endcsname\empty}}% ##1 \stopinterface \unexpanded\def\installparametersethandler#1#2% {\normalexpanded {\doinstallparametersethandler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname set#2parameter\endcsname \expandafter\noexpand\csname let#2parameter\endcsname \expandafter\noexpand\csname reset#2parameter\endcsname}} \let\dousecurrentstyleparameter\relax \let\dousecurrentcolorparameter\relax \let\currentstyleparameter\empty \let\currentcolorparameter\empty \unexpanded\def\doinstallstyleandcolorhandler#1#2#3#4% {\unexpanded\def#2##1##2% style color {\edef\currentstyleparameter{#1{##1}}% this name is public \edef\currentcolorparameter{#1{##2}}% this name is public \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}% \unexpanded\def#3##1% style {\edef\currentstyleparameter{#1{##1}}% this name is public \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi}% \unexpanded\def#4##1% color {\edef\currentcolorparameter{#1{##1}}% this name is public \ifx\currentcolorparameter\empty\else\dousecurrentcolorparameter\fi}} \unexpanded\def\installstyleandcolorhandler#1#2% {\normalexpanded {\doinstallstyleandcolorhandler \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname use#2styleandcolor\endcsname % maybe an alias use#2styleandcolorparameters \expandafter\noexpand\csname use#2styleparameter\endcsname \expandafter\noexpand\csname use#2colorparameter\endcsname}} \let\definehandlerparent\empty \unexpanded\def\doinstalldefinehandler#1#2#3#4#5#6#7#8% {\ifx#4\relax\let#4\empty\fi \unexpanded\def#2{\dotripleempty#5}% \newtoks#6% \newtoks#7% \def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child] {\let\saveddefinewhatever#4% \edef#4{##1}% \the#6% predefine \ifthirdargument \edef#8{##2}% % \getparameters[#1#4:][\s!parent=#1##2,##3]% \get_parameters{#1#4:}[\s!parent=#1##2,##3]% \else\ifsecondargument \doifassignmentelse{##2} {\let#8\empty % \getparameters[#1#4:][\s!parent=#3,##2]} \get_parameters{#1#4:}[\s!parent=#3,##2]} {\edef#8{##2}% % \getparameters[#1#4:][\s!parent=#1##2]}% \get_parameters{#1#4:}[\s!parent=#1##2]}% \else \let#8\empty % \getparameters[#1#4:][\s!parent=#3]% \get_parameters{#1#4:}[\s!parent=#3]% \fi\fi \the#7% \let#4\saveddefinewhatever}} \unexpanded\def\installdefinehandler#1#2#3% {\normalexpanded {\doinstalldefinehandler {\noexpand#1}% \??aa \expandafter\noexpand\csname define#2\endcsname {\noexpand#3}% root \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname d@define#2\endcsname % sort of public \expandafter\noexpand\csname everypreset#2\endcsname \expandafter\noexpand\csname everydefine#2\endcsname \expandafter\noexpand\csname current#2parent\endcsname}} \unexpanded\def\doinstallsetuphandler#1#2#3#4#5#6% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% % \unexpanded\def#6{\getparameters[#1#3:]}% no every ! don't change it \unexpanded\def#6{\get_parameters{#1#3:}}% no every ! don't change it \newtoks#5% \def#4[##1][##2]% maybe helper {\let\savedsetupwhatever#3% \ifsecondargument \def\docommand####1% we will have a simple one as well {\edef#3{####1}% % \getparameters[#1#3:][##2]% \get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]\docommand \else \let#3\empty % \getparameters[#1:][##1]% \get_parameters{#1:}[##1]% \the#5% \fi \let#3\savedsetupwhatever}} \unexpanded\def\installsetuphandler#1#2% {\normalexpanded {\doinstallsetuphandler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname d@setup#2\endcsname % sort of public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname}} \unexpanded\def\doinstallswitchsetuphandler#1#2#3#4#5#6% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% % \unexpanded\def#6{\getparameters[#1#3:]}% \unexpanded\def#6{\get_parameters{#1#3:}}% \newtoks#5% \def#4[##1][##2]% maybe helper {\ifsecondargument % no commalist here \let\savedsetupwhatever#3% \edef#3{##1}% % \getparameters[#1#3:][##2]% \get_parameters{#1#3:}[##2]% \the#5% \let#3\savedsetupwhatever \else\iffirstargument \doifassignmentelse{##1} {\let\savedsetupwhatever#3% \let#3\empty % \getparameters[#1:][##1]% \get_parameters{#1:}[##1]% \the#5% \let#3\savedsetupwhatever} {\edef#3{##1}% this will catch reset \the#5}% \else \let#3\empty \the#5% \fi\fi}} \unexpanded\def\installswitchsetuphandler#1#2% {\normalexpanded {\doinstallswitchsetuphandler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname d@setup#2\endcsname \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname}} \unexpanded\def\doinstallautosetuphandler#1#2#3#4#5#6% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dotripleempty#4}% % \unexpanded\def#6{\getparameters[#1#3:]}% \unexpanded\def#6{\get_parameters{#1#3:}}% \newtoks#5% \def#4[##1][##2][##3]% {\let\savedsetupwhatever#3% \ifthirdargument \def\docommand####1% {\edef#3{####1}% % \getparameters[#1#3:][\s!parent=#1##2,##3]% \get_parameters{#1#3:}[\s!parent=#1##2,##3]% \the#5}% \processcommalist[##1]\docommand \else\ifsecondargument \def\docommand####1% {\edef#3{####1}% % \getparameters[#1#3:][##2]% \get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]\docommand \else \let#3\empty % \getparameters[#1:][##1]% \get_parameters{#1:}[##1]% \the#5% \fi\fi \let#3\savedsetupwhatever}} \unexpanded\def\installautosetuphandler#1#2% {\normalexpanded {\doinstallautosetuphandler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname d@setup#2\endcsname % sort of public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname}} \unexpanded\def\installbasicparameterhandler#1#2% {\installparameterhandler {#1}{#2}% \installparameterhashhandler{#1}{#2}% \installparametersethandler {#1}{#2}% \installrootparameterhandler{#1}{#2}} \unexpanded\def\installcommandhandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installswitchcommandhandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installswitchsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installautocommandhandler#1#2#3% automatically defined cloned setups {\installbasicparameterhandler{#1}{#2}% \installdefinehandler {#1}{#2}{#3}% \installautosetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installsimplecommandhandler#1#2#3% no define (experiment) - use \check*parent when defining {\installbasicparameterhandler{#1}{#2}% \installsetuphandler {#1}{#2}% \installstyleandcolorhandler {#1}{#2}} \unexpanded\def\installnamespace#1% {\setvalue{????#1}{@@@@#1}} % \enabletrackers[interfaces.namespaces,context.flush] % % \definenamespace % [xy] % [type=module, % comment=test module, % version=1, % name=test, % style=yes, % command=yes, % setup=list, % set=yes, % parent=xy] % % \unprotect % \getparameters % [\????xy] % [text=] % \protect % % \definetest[one] % % \starttext % % “\testparameter{text}” % % \setuptest[text=foo] % % “\testparameter{text}” % % \setuptest[one][text=bar] % % “\testparameter{text}” % % \stoptext \unexpanded\def\definenamespace {\dodoubleargument\dodefinenamespace} \def\dodefinenamespace[#1][#2]% namespace settings {\ctxlua{interfaces.namespaces.define(\!!bs#1\!!es,\!!bs#2\!!es)}} \def\listnamespaces {\ctxlua{interfaces.namespaces.list()}} %D Helper: %D %D \starttyping %D \showparentchain{@@am}{left} %D \stoptyping \def\doshowparentchain#1% {#1 => % \ifcsname#1:\s!parent\endcsname \expandafter\doshowparentchain\csname#1:\s!parent\endcsname \fi} \def\showparentchain#1#2% {\writestatus\m!system{chain: [ \doshowparentchain{#1#2}]}} \protect