%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. % todo: setupxxx and setupxxxs (so a plural for the root setup and % we can consider blocking the root) % todo (e.g for columnsets and registers): \definexxx[parent][1] % %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. % todo: doifelse \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 % \usewhateverstyleandcolor \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}{\mult_interfaces_get_parameters{bla} [a=111,b=222,c=333]}% 1.529s % \testfeatureonce{100000}{\def\m_mult_interfaces_namespace{bla}\mult_interfaces_get_parameters_indeed[a=111,b=222,c=333]}% 1.466s \let\m_mult_interfaces_namespace\empty \def\mult_interfaces_get_parameters#1[#2% {\if\noexpand#2]% \expandafter\gobbleoneargument \else \def\m_mult_interfaces_namespace{#1}% \expandafter\mult_interfaces_get_parameters_indeed \fi#2} \def\mult_interfaces_get_parameters_indeed#1]% namespace already set {\mult_interfaces_get_parameters_item#1,],\_e_o_p_} \def\mult_interfaces_get_parameters_item#1,#2% #2 takes space before , {\if,#1,% dirty trick for testing #1=empty \expandafter\mult_interfaces_get_parameters_item \else\if]#1% \doubleexpandafter\gobbleoneargument \else \mult_interfaces_get_parameters_assign#1==\empty\_e_o_p_ \doubleexpandafter\mult_interfaces_get_parameters_item \fi\fi#2} \def\mult_interfaces_get_parameters_error#1#2#3% {\showassignerror{#2}{\the\inputlineno\space(#1)}} \def\mult_interfaces_get_parameters_assign#1=#2=#3#4\_e_o_p_ {\ifx\empty#1\empty \expandafter\mult_interfaces_get_parameters_error \else\ifx#3\empty \doubleexpandafter\mult_interfaces_get_parameters_error \else \doubleexpandafter\dosetvalue \fi\fi \m_mult_interfaces_namespace{#1}{#2}} \newif\ifassignment \def\mult_check_for_assignment_indeed#1=#2#3\_end_ {\if#2@\assignmentfalse\else\assignmenttrue\fi} \def\mult_check_for_assignment#1% {\expandafter\mult_check_for_assignment_indeed\detokenize{#1}=@@\_end_} % End of experimental code. % the commented detokenized variant that backtracks ... needs testing usage first % % \let\whatever\relax % % \definetest[oeps][bagger=\whatever] % % \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{bagger}}\meaning\hans\par % \def\currenttest{oeps} \edef\hans{\detokenizedtestparameter{reggab}}\meaning\hans\par \def\mult_interfaces_detokenize{\expandafter\expandafter\expandafter\detokenize\expandafter\expandafter\expandafter} \unexpanded\def\mult_interfaces_install_parameter_handler#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\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#7##1{\mult_interfaces_detokenize{\csname#4{#1#2}{##1}\endcsname}}% compact version % \def#7##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}% \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 {\mult_interfaces_install_parameter_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname do#2parameter\endcsname % or : #2_parameter_hash \expandafter\noexpand\csname do#2parentparameter\endcsname % or : #2_parent_parameter_hash \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\mult_interfaces_install_root_parameter_handler#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 {\mult_interfaces_install_root_parameter_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname detokenizedroot#2parameter\endcsname \expandafter\noexpand\csname root#2parameter\endcsname}} \unexpanded\def\mult_interfaces_install_parameter_hash_handler#1#2#3#4#5#6#7#8#9% {\ifx#2\relax\let#2\empty\fi \def#3##1{#1#4{#1#2}{##1}:}% leading #1 was missing .. is this one used? \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}% \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% {\expandafter\let\csname#2namespace\endcsname#1% \normalexpanded {\mult_interfaces_install_parameter_hash_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameterhash\endcsname \expandafter\noexpand\csname do#2parameterhash\endcsname % or : #2_parameter_hash \expandafter\noexpand\csname do#2parentparameterhash\endcsname % or : #2_parent_parameter_hash \expandafter\noexpand\csname current#2hash\endcsname \expandafter\noexpand\csname named#2hash\endcsname \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname chaintocurrent#2\endcsname}} % In \MKIV\ we can probably use the english variant for all other % languages too. % todo: inline the \do*value \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% {\ifx#2\relax\let#2\empty\fi \unexpanded\def#3{\dosetvalue {#1#2:}}% ##1 {##2} (braces are mandate) \unexpanded\def#4{\dosetevalue{#1#2:}}% ##1 {##2} (braces are mandate) \unexpanded\def#5{\doletvalue {#1#2:}}% ##1 ##2 \unexpanded\def#6{\doletvalue {#1#2:}\empty}}% ##1 \startinterface english \unexpanded\def\mult_interfaces_install_parameter_set_handler#1#2#3#4#5#6% {\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\edef\csname#1#2:##1\endcsname}% ##1 {##2} (braces are mandate) \unexpanded\def#5##1{\expandafter \let\csname#1#2:##1\endcsname}% ##1 ##2 \unexpanded\def#6##1{\expandafter \let\csname#1#2:##1\endcsname\empty}}% ##1 \stopinterface \unexpanded\def\installparametersethandler#1#2% {\normalexpanded {\mult_interfaces_install_parameter_set_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname set#2parameter\endcsname \expandafter\noexpand\csname setexpanded#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\mult_interfaces_install_style_and_color_handler#1#2#3#4% {\unexpanded\def#2##1##2% style color {\edef\currentstyleparameter{#1{##1}}% this name is public (can also set color e.g. in underline) \ifx\currentstyleparameter\empty\else\dousecurrentstyleparameter\fi \edef\currentcolorparameter{#1{##2}}% this name is public (so we do this after the style switch) \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 {\mult_interfaces_install_style_and_color_handler \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 \def\mult_check_for_parent#1#2#3#4% {\ifcsname#1#4:\s!parent\endcsname \else \ifx#4\empty \else \writestatus\m!system{error: invalid parent #4 for #3, #4 defined too (best check it)}% \expandafter\edef\csname#1#4:\s!parent\endcsname{#2}% \fi \fi} \unexpanded\def\mult_interfaces_install_define_handler#1#2#3#4#5#6#7#8#9% why is \expanded still needed in clones {\ifx#4\relax\let#4\empty\fi % see \defineregister \unexpanded\def#2{\dotripleempty#5}% \newtoks#6% \newtoks#7% \unexpanded\def#5[##1][##2][##3]% [child][parent][settings] | [child][settings] | [child][parent] | [child] {\let#9#4% \edef#4{##1}% \ifthirdargument \the#6% predefine \edef#8{##2}% \mult_check_for_parent{#1}{#3}#4#8% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% \mult_interfaces_get_parameters{#1#4:}[##3]% \else\ifsecondargument \the#6% predefine \expandafter\mult_check_for_assignment_indeed\detokenize{##2}=@@\_end_ \ifassignment \let#8\empty \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% \mult_interfaces_get_parameters{#1#4:}[##2]% \else \edef#8{##2}% \mult_check_for_parent{#1}{#3}#4#8% \expandafter\edef\csname#1#4:\s!parent\endcsname{#1##2}% \fi \else \the#6% predefine \let#8\empty \expandafter\edef\csname#1#4:\s!parent\endcsname{#3}% \fi\fi \the#7% \let#4#9}} \unexpanded\def\installdefinehandler#1#2#3% {\normalexpanded {\mult_interfaces_install_define_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname define#2\endcsname {\noexpand#3}% root \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname define_#2\endcsname % semi-public \expandafter\noexpand\csname everypreset#2\endcsname \expandafter\noexpand\csname everydefine#2\endcsname \expandafter\noexpand\csname current#2parent\endcsname \expandafter\noexpand\csname saved_defined_#2\endcsname}} \unexpanded\def\mult_interfaces_install_setup_handler#1#2#3#4#5#6#7#8#9% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% no every ! don't change it \newtoks#5% \newtoks#8% \unexpanded\def#4[##1][##2]% maybe helper {\let#7#3% \ifsecondargument \def#9####1% we will have a simple one as well {\edef#3{####1}% \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]#9% \else \let#3\empty \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \fi \let#3#7% \the#8}} \unexpanded\def\installsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname everysetup#2root\endcsname \expandafter\noexpand\csname nested_setup_current#2\endcsname}} \let\doingrootsetupnamed\plusone % \setuplayout[name][key=value] \let\doingrootsetuproot \plustwo % \setuplayout [key=value] \let\doingrootsetnamed \plusthree % \setuplayout[name] \let\doingrootsetroot \plusfour % \setuplayout \unexpanded\def\mult_interfaces_install_switch_setup_handler_a#1#2#3#4#5% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dodoubleempty#4}% \unexpanded\def#5{\mult_interfaces_get_parameters{#1#3:}}} \unexpanded\def\mult_interfaces_install_switch_setup_handler_b#1#2#3#4#5#6#7#8#9% {\newtoks#5% \newconstant#2% \newtoks#8% \newtoks#9% \ifx#6\relax\let#6\empty\fi \unexpanded\def#4[##1][##2]% maybe helper {\ifsecondargument % no commalist here % \setuplayout[whatever][key=value] \let#7#3% \let#6#3% \edef#3{##1}% #2\doingrootsetupnamed \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5% \ifx#3#6\the#8\fi % only switchsetups if previous == current \let#3#7% \else\iffirstargument % \mult_check_for_assignment{##1}% \expandafter\mult_check_for_assignment_indeed\detokenize{##1}=@@\_end_ \ifassignment % \setuplayout[key=value] \let#7#3% \let#6#3% \let#3\empty #2\doingrootsetuproot \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \the#8% switchsetups \let#3#7% \else % \setuplayout[whatever] \let#6#3% % previous becomes current \edef#3{##1}% this will catch reset so one needs to test for it #2\doingrootsetnamed \the#5% % we can check for previous vs current \the#8% switchsetups \fi \else % \setuplayout \let#6#3% % previous becomes current \let#3\empty % current becomes empty #2\doingrootsetroot \the#5% \the#8% switchsetups \fi\fi #2\zerocount % mode is always zero at the end \the#9}} \unexpanded\def\installswitchsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_switch_setup_handler_a {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname setupcurrent#2\endcsname \mult_interfaces_install_switch_setup_handler_b {\noexpand#1}% \??aa \expandafter\noexpand\csname #2setupmode\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname previous#2\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname everyswitch#2\endcsname \expandafter\noexpand\csname everysetup#2root\endcsname}} \unexpanded\def\mult_interfaces_install_auto_setup_handler#1#2#3#4#5#6#7#8#9% {\ifx#3\relax\let#3\empty\fi \unexpanded\def#2{\dotripleempty#4}% \unexpanded\def#6{\mult_interfaces_get_parameters{#1#3:}}% \newtoks#5% \def#4[##1][##2][##3]% {\let#8#3% \ifthirdargument \def#9####1% {\edef#3{####1}% \expandafter\def\csname#1#3:\s!parent\endcsname{#1##2}% \mult_interfaces_get_parameters{#1#3:}[##3]% always sets parent \the#5}% \processcommalist[##1]#9% \else\ifsecondargument \def#9####1% {\edef#3{####1}% #7% checks parent and sets if needed \mult_interfaces_get_parameters{#1#3:}[##2]% \the#5}% \processcommalist[##1]#9% \else \let#3\empty \mult_interfaces_get_parameters{#1:}[##1]% \the#5% \fi\fi \let#3#8}} \unexpanded\def\installautosetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_auto_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname everysetup#2\endcsname \expandafter\noexpand\csname setupcurrent#2\endcsname \expandafter\noexpand\csname check#2parent\endcsname \expandafter\noexpand\csname saved_setup_current#2\endcsname \expandafter\noexpand\csname nested_setup_current#2\endcsname}} \unexpanded\def\installbasicparameterhandler#1#2% {\installparameterhandler {#1}{#2}% \installparameterhashhandler{#1}{#2}% \installparametersethandler {#1}{#2}% \installrootparameterhandler{#1}{#2}} \unexpanded\def\installbasicautosetuphandler#1#2#3% \??self name \??parent (can be \??self) {\installbasicparameterhandler{#1}{#2}% \installautosetuphandler {#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}} %D Many mechanisms have some kind of inheritance in place, and these are %D the speed||critical ones. Therefore there is no reason to stick to %D \type {\@@xxkey} for the sake of performance. For this reason we also %D provide a direct variant. This permits a more consistent treatment of %D namespaces. A \type {\whateverparameter} call is three times slower %D and a \type {\directwhateverparameter} call two times but for some %D 100K expansions we only loose some .1 second which is neglectable %D given the small amount of expansions in real runs. %D We don't need colons for such simple cases. \unexpanded\def\mult_interfaces_install_direct_parameter_handler#1#2#3#4#5% {\def#3##1{\csname\ifcsname#1##1\endcsname#1##1\else\s!empty\fi\endcsname}% \def#4##1{\detokenize\expandafter\expandafter\expandafter{\csname#1##1\endcsname}}% % \def#4##1{\mult_interfaces_detokenize{\csname\ifcsname#1#2:##1\endcsname#1#2:##1\else\expandafter#5\csname#1#2:\s!parent\endcsname{##1}\fi\endcsname}}% \def#5##1{\csname#1##1\endcsname}} \unexpanded\def\installdirectparameterhandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_parameter_handler {\noexpand#1}% \expandafter\noexpand\csname current#2\endcsname \expandafter\noexpand\csname #2parameter\endcsname \expandafter\noexpand\csname detokenized#2parameter\endcsname \expandafter\noexpand\csname direct#2parameter\endcsname}} \unexpanded\def\mult_interfaces_install_direct_setup_handler#1#2#3#4#5% {\unexpanded\def#2{\dosingleempty#3}% \newtoks#5% \def#3[##1]{\mult_interfaces_get_parameters#1[##1]\the#5}% \def#4{\mult_interfaces_get_parameters#1}} \unexpanded\def\installdirectsetuphandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_setup_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname setup#2\endcsname \expandafter\noexpand\csname setup_#2\endcsname % semi-public \expandafter\noexpand\csname setupcurrent#2\endcsname % no \every (we use 'current' for consistency) \expandafter\noexpand\csname everysetup#2\endcsname}} \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% {\unexpanded\def#2{\dosetvalue #1}% \unexpanded\def#3{\dosetevalue#1}% \unexpanded\def#4{\doletvalue #1}% \unexpanded\def#5{\doletvalue #1\empty}}% \startinterface english \unexpanded\def\mult_interfaces_install_direct_parameter_set_handler#1#2#3#4#5% {\unexpanded\def#2##1{\expandafter \def\csname#1##1\endcsname}% \unexpanded\def#3##1{\expandafter\edef\csname#1##1\endcsname}% \unexpanded\def#4##1{\expandafter \let\csname#1##1\endcsname}% \unexpanded\def#5##1{\expandafter \let\csname#1##1\endcsname\empty}}% \stopinterface \unexpanded\def\installdirectparametersethandler#1#2% {\normalexpanded {\mult_interfaces_install_direct_parameter_set_handler {\noexpand#1}% \??aa \expandafter\noexpand\csname set#2parameter\endcsname \expandafter\noexpand\csname setexpanded#2parameter\endcsname \expandafter\noexpand\csname let#2parameter\endcsname \expandafter\noexpand\csname reset#2parameter\endcsname}} \let\installdirectstyleandcolorhandler\installstyleandcolorhandler \unexpanded\def\installdirectcommandhandler#1#2% {\installdirectparameterhandler {#1}{#2}% \installdirectsetuphandler {#1}{#2}% \installdirectparametersethandler {#1}{#2}% \installdirectstyleandcolorhandler{#1}{#2}} \unexpanded\def\installsetuponlycommandhandler#1#2% {\installdirectparameterhandler{#1}{#2}% \installdirectsetuphandler {#1}{#2}% }% maybe \installdirectparametersethandler {#1}{#2}% % Experiment: % \installcorenamespace {one} % \installcorenamespace {two} % % \installcommandhandler \??one {one} \??one % \installcommandhandler \??two {two} \??two % % \defineone[test] \setupone[test][alpha=first] % \definetwo[test] \setuptwo[test][beta=second] % % \protect % % \def\currentone{test} % \def\currenttwo{test} % % \relateparameterhandlers {two} {test} {one} {test} % % yes:\oneparameter{alpha}\par % nop:\oneparameter{beta}\par % yes:\twoparameter{alpha}\par % yes:\twoparameter{beta}\par \unexpanded\def\relateparameterhandlers#1#2#3#4% {from} {instance} {to} {instance} {\expandafter\edef\csname\csname#1namespace\endcsname#2:\s!parent\endcsname{\csname#3namespace\endcsname#4}} %D Here is another experiment: \unexpanded\def\installactionhandler#1% {\normalexpanded {\mult_interfaces_install_action_handler {#1}% \expandafter\noexpand\csname current#1\endcsname \expandafter\noexpand\csname setupcurrent#1\endcsname \expandafter\noexpand\csname #1_action\endcsname}} \unexpanded\def\mult_interfaces_install_action_handler#1#2#3#4% {\unexpanded\expandafter\def\csname#1\endcsname{\dodoubleempty#4}% \unexpanded\def#4[##1][##2]% {\begingroup \ifsecondargument \edef#2{##1}% #3[##2]% \else\iffirstargument \doifassignmentelse{##1} {\let#2\empty #3[##1]}% {\edef#2{##1}}% \else \let#2\empty \fi\fi \directsetup{handler:action:#1}% \endgroup}} % First we had, in tune with the regular system variables: % % \starttyping % \unexpanded\def\installnamespace#1{\setvalue{????#1}{@@@@#1}} % \stoptyping % % The following variant is nicer and in principle faster but that gets % unnoticed unless lots of expansion happens. Also, we can use long tags % but the internal expansion will be relatively small (and unlikely more % than 4 characters). For instance, \??xx used to expand to @@xx but now % becomes for instance 123::. This is one character more but in quite some % cases we had : after such a tag in the old situation. In the new situation % we create more namespaces and don't need that : any more, so we end up % with on the average the same amount of tokens and definitely less when % we consider cases like \??xx:\c!align: which now is just \??somealign and % therefore has length 5 now (instead of 4+1+5+1=10). % % Eventualy we will have a verbose \blablanamespace and the difference between % core and regular can go ... after all, \xxxparameter can already clash between % the two prefix groups .. if users use this mechanism a lot they should use % verbose names anyway (the old two character names were mostly an optimization % as they also expanded to these characters). % todo: register namespaces at lua end for logging and reverse resolve % todo: move this to syst-ini so that we can use it real early \newcount\c_mult_interfaces_n_of_namespaces %def\v_interfaces_prefix_template{\number \c_mult_interfaces_n_of_namespaces>} \def\v_interfaces_prefix_template{\characters\c_mult_interfaces_n_of_namespaces>} \def\v_interfaces_prefix_template % consistently %03i> {\ifnum\c_mult_interfaces_n_of_namespaces<\plusten00\else\ifnum\c_mult_interfaces_n_of_namespaces<\plushundred0\fi\fi \number\c_mult_interfaces_n_of_namespaces>} \def\v_interfaces_prefix_template % consistently %03i> {\number\c_mult_interfaces_n_of_namespaces>} \unexpanded\def\installnamespace#1% for modules and users {\ifcsname ????#1\endcsname \writestatus\m!system{duplicate user namespace '#1'}\wait \else \global\advance\c_mult_interfaces_n_of_namespaces\plusone \expandafter\edef\csname ????#1\endcsname{\v_interfaces_prefix_template}% \fi} \unexpanded\def\installcorenamespace#1% {\ifcsname ??#1\endcsname \writestatus\m!system{duplicate core namespace '#1'}\wait \else \global\advance\c_mult_interfaces_n_of_namespaces\plusone \expandafter\edef\csname ??#1\endcsname{\v_interfaces_prefix_template}% \ctxcommand{registernamespace(\number\c_mult_interfaces_n_of_namespaces,"#1")}% \fi} \def\mult_interfaces_get_parameters_error#1#2#3% redefined {\ctxcommand{showassignerror("#1","#2","#3",\the\inputlineno)}% \waitonfatalerror} % We install two core namespaces here, as we want nice error messages. Maybe % we will reserve the first 9. \installcorenamespace{fontinstanceready} \installcorenamespace{fontinstancebasic} \installcorenamespace{fontinstanceclass} %D The next one is handy for local assignments. \installcorenamespace{dummy} \letvalue\??dummy\empty \def\dummyparameter #1{\csname\??dummy\ifcsname\??dummy#1\endcsname#1\fi\endcsname} \def\directdummyparameter#1{\csname\??dummy#1\endcsname} \unexpanded\def\setdummyparameter #1{\expandafter\def\csname\??dummy#1\endcsname} \unexpanded\def\letdummyparameter #1{\expandafter\let\csname\??dummy#1\endcsname} % \unexpanded\def\getdummyparameters % {\mult_interfaces_get_parameters\??dummy} \unexpanded\def\getdummyparameters[#1% {\if\noexpand#1]% \expandafter\gobbleoneargument \else \let\m_mult_interfaces_namespace\??dummy \expandafter\mult_interfaces_get_parameters_indeed \fi#1} \mult_interfaces_install_style_and_color_handler \directdummyparameter \usedummystyleandcolor \usedummystyleparameter \usedummycolorparameter % Maybe a \definecorenamespace[name][directparameter,directsetup][parent] % but we don't gain much. Actually we might just inline all definitions. % \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 % % This is a user (module) command: \unexpanded\def\definenamespace {\dodoubleargument\mult_interfaces_define_name_space} \def\mult_interfaces_define_name_space[#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 \unexpanded\def\showparentchain#1#2% {\writestatus\m!system{chain: [ \mult_interfaces_show_parent_chain{#1#2}]}} \def\mult_interfaces_show_parent_chain#1% {#1 => % \ifcsname#1:\s!parent\endcsname \expandafter\mult_interfaces_show_parent_chain\csname#1:\s!parent\endcsname \fi} %D Another helper (needs to be applied): \unexpanded\def\doifelsecommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\firstoftwoarguments \else \expandafter\secondoftwoarguments \fi} \unexpanded\def\doifcommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\firstofoneargument \else \expandafter\gobbleoneargument \fi} \unexpanded\def\doifnotcommandhandler#1#2% namespace name {\ifcsname#1#2:\s!parent\endcsname \expandafter\gobbleoneargument \else \expandafter\firstofoneargument \fi} \let\doifcommandhandlerelse\doifelsecommandhandler % another set of (fast) helpers (grep for usage): \def\expandnamespaceparameter#1#2#3% \??xx \getp \c!xx \c!yy {\csname#1\ifcsname#1\expandafter\expandafter\expandafter\mult_aux_expand_namespace_parameter#2#3} \def\mult_aux_expand_namespace_parameter#1#2% \cs \c!yy {#1\endcsname#1\else#2\fi\endcsname} \def\expandnamespacemacro#1#2#3% \??xx \some_edefed_cs \c!yy {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname} \def\expandnamespacevalue#1#2% \??xx {...} \c!yy == optimized \expandcheckedcsname {\csname#1\ifcsname#1\normalexpanded{\noexpand\syst_helpers_expand_checked_value{#2}}} \def\syst_helpers_expand_checked_value#1#2% {#1\endcsname#1\else#2\fi\endcsname} %D Conventions: %D %D \starttyping %D \newcount \c_class_whatever %D \newconditional \c_class_whatever %D \newconstant \c_class_whatever %D \newdimen \d_class_whatever %D \newskip \s_class_whatever %D \newmuskip \s_class_whatever %D \newbox \b_class_whatever %D \newtoks \t_class_whatever %D %D \edef\p_class_whatever{\classparameter\c!whatever} %D \edef\m_class_whatever{whatever} %D \stoptyping \protect