attr-ini.mkiv / last modification: 2020-01-30 14:16
%D \module
%D   [       file=attr-ini,
%D        version=2007.06.06,
%D          title=\CONTEXT\ Attribute Macros,
%D       subtitle=Initialization,
%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.

\writestatus{loading}{ConTeXt Attribute Macros / Initialization}

%D Although it's still somewhat experimental, here we introduce code
%D related to attributes. Housekeeping will move completely to \LUA\
%D and \type {\newattribute} will go away.

\unprotect

\registerctxluafile{attr-ini}{}

\installcorenamespace{attributecount}  % the counter representing the attribute (attrdef'd)
\installcorenamespace{attributeid}     % the internal number
\installcorenamespace{attributestack}  % the attribute specific stack
\installcorenamespace{attributepickup}

\unexpanded\def\pushattribute#1%
  {\global\advance\csname\??attributestack\string#1\endcsname\plusone
   \expandafter\xdef\csname\??attributestack\string#1:\number\csname\??attributestack\string#1\endcsname\endcsname{\number\attribute#1}}

\unexpanded\def\popattribute#1%
  {\attribute#1\csname\??attributestack\string#1:\number\csname\??attributestack\string#1\endcsname\endcsname\relax
   \global\advance\csname\??attributestack\string#1\endcsname\minusone}

\unexpanded\def\installattributestack#1%
  {\ifcsname\??attributestack\string#1\endcsname \else
     \expandafter\newcount\csname\??attributestack\string#1\endcsname
   \fi}

\newtoks \t_attr_list_global
\newtoks \t_attr_list_local
\newtoks \t_attr_list_pickup
\newtoks \t_attr_list_nomath

\ifdefined \s!global    \else \def\s!global   {global}    \fi % for metatex % or hard check later
\ifdefined \s!public    \else \def\s!public   {public}    \fi % for metatex % or hard check later
\ifdefined \s!private   \else \def\s!private  {private}   \fi % for metatex % or hard check later
\ifdefined \s!attribute \else \def\s!attribute{attribute} \fi % for metatex % or hard check later
\ifdefined \s!pickup    \else \def\s!pickup   {pickup}    \fi % for metatex % or hard check later
\ifdefined \s!forget    \else \def\s!forget   {forget}    \fi % for metatex % or hard check later

\unexpanded\def\defineattribute      {\dodoubleempty\attr_basics_define}
\unexpanded\def\definesystemattribute{\dodoubleempty\attr_basics_define_system}

\def\attr_basics_define       {\attr_basics_define_indeed\s!public}
\def\attr_basics_define_system{\attr_basics_define_indeed\s!private}

% todo: define global !

% here public means 'visible' so it's not to be confused with 'public' at the lua end

% \def\attr_basics_define_indeed#1[#2][#3]%
%   {\ifcsname\??attributecount#2\endcsname\else
%      \scratchcounter\clf_defineattribute{#2}{#1}\relax
%     %\writestatus\m!system{defining #1 attribute #2 with number \number\scratchcounter}%
%      \expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
%      \expandafter\newconstant \csname\??attributeid#2\endcsname
%      \csname\??attributeid#2\endcsname\scratchcounter
%      % some attributes are always global
%      \doifelseinset\s!global{#3}%
%        {\etoksapp\t_attr_list_global{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
%        {\etoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
%      \doifinset\s!nomath{#3}%
%        {\etoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
%      \doifinset\s!public{#3}%
%        {\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}%
%      \doifinset\s!pickup{#3}%
%        {\expandafter\newconstant\csname\??attributepickup#2\endcsname
%         \csname\??attributepickup#2\endcsname\attributeunsetvalue
%         \etoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}%
%         \ifcsname#2\s!attribute\endcsname
%           \expandafter\edef\csname\s!pickup#2\s!attribute\endcsname
%             {\csname\??attributepickup#2\endcsname\csname\??attributecount#2\endcsname}%
%           \expandafter\edef\csname\s!forget#2\s!attribute\endcsname
%             {\csname\??attributepickup#2\endcsname\attributeunsetvalue}%
%         \fi}%
%    \fi}

\def\attr_basics_define_indeed#1[#2][#3]%
  {\ifcsname\??attributecount#2\endcsname\else
     \scratchcounter\clf_defineattribute{#2}{#1}\relax
    %\writestatus\m!system{defining #1 attribute #2 with number \number\scratchcounter}%
     \global\expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
     \global\expandafter\newconstant \csname\??attributeid#2\endcsname
     \global\csname\??attributeid#2\endcsname\scratchcounter
     % some attributes are always global
     \doifelseinset\s!global{#3}%
       {\xtoksapp\t_attr_list_global{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
       {\xtoksapp\t_attr_list_local {\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
     \doifinset\s!nomath{#3}%
       {\xtoksapp\t_attr_list_nomath{\csname\??attributecount#2\endcsname\attributeunsetvalue}}%
     \doifinset\s!public{#3}%
       {\expandafter\glet\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}%
     \doifinset\s!pickup{#3}%
       {\global\expandafter\newconstant\csname\??attributepickup#2\endcsname
        \global\csname\??attributepickup#2\endcsname\attributeunsetvalue
        \xtoksapp\t_attr_list_pickup{\csname\??attributecount#2\endcsname\csname\??attributepickup#2\endcsname}%
        \ifcsname#2\s!attribute\endcsname
          \expandafter\xdef\csname\s!pickup#2\s!attribute\endcsname
            {\csname\??attributepickup#2\endcsname\csname\??attributecount#2\endcsname}%
          \expandafter\xdef\csname\s!forget#2\s!attribute\endcsname
            {\csname\??attributepickup#2\endcsname\attributeunsetvalue}%
        \fi}%
   \fi}

\unexpanded\def\pickupattributes
  {\the\t_attr_list_pickup\relax}

% \unexpanded\def\pickupattribute#1%
%   {\csname\??attributecount#1\endcsname\csname\??attributepickup#1\endcsname}

% \unexpanded\def\pickupattributelater#1%
%   {\csname\??attributepickup#1\endcsname\csname\??attributecount#1\endcsname}

% \unexpanded\def\newattribute#1%
%   {\attr_basics_define_indeed\s!public[\csstring#1][]%
%    \expandafter\let\expandafter#1\csname\??attributeid\csstring#1\endcsname}

\unexpanded\def\newattribute#1%
  {\attr_basics_define_indeed\s!public[\csstring#1][]%
   \expandafter\glet\expandafter#1\csname\??attributeid\csstring#1\endcsname}

% expandable so we can \edef them for speed

\def\dosetattribute#1#2{\csname\??attributecount#1\endcsname#2\relax}
\def\doresetattribute#1{\csname\??attributecount#1\endcsname\attributeunsetvalue}
\def\dogetattribute  #1{\number\csname\??attributecount#1\endcsname}
\def\dogetattributeid#1{\number\csname\??attributeid#1\endcsname}

\let\dompattribute\gobbletwoarguments

\ifcase\contextlmtxmode
    \unexpanded\def\resetglobalattributes{\the\t_attr_list_global\attribute\zerocount\zerocount}
    \unexpanded\def\resetlocalattributes {\the\t_attr_list_local \attribute\zerocount\zerocount}
\else
    \unexpanded\def\resetglobalattributes{\the\t_attr_list_global\glyphdatafield     \zerocount}
    \unexpanded\def\resetlocalattributes {\the\t_attr_list_local \glyphdatafield     \zerocount}
\fi

\let\resetallattributes\resetlocalattributes

%D Rather special.

\unexpanded\def\savecurrentattributes   #1{\clf_savecurrentattributes   {#1}}
\unexpanded\def\restorecurrentattributes#1{\clf_restorecurrentattributes{#1}}

%D For the moment we put this here. The order of definition matters a bit because
%D performance is better when we put frequently accessed attributes at the front.
%D So, we might move more here.

\definesystemattribute [state]                                  % nomath
\definesystemattribute [color]               [public]           % global
\definesystemattribute [colormodel]          [public,global]
% \definesystemattribute [skip]
% \definesystemattribute [penalty]
\definesystemattribute [transparency]        [public]
\definesystemattribute [reference]           [public]
\definesystemattribute [destination]         [public]
\definesystemattribute [case]                [public]
\definesystemattribute [visual]              [public,global]
\definesystemattribute [viewerlayer]         [public]
\definesystemattribute [background]          [public]
\definesystemattribute [alignbackground]     [public]
\definesystemattribute [colorintent]         [public]
\definesystemattribute [negative]            [public]
\definesystemattribute [effect]              [public]
\definesystemattribute [layoutcomponent]     [public]
\definesystemattribute [internal]            [public]
\definesystemattribute [ruled]               [public]
\definesystemattribute [shifted]             [public]
\definesystemattribute [checkedbreak]        [public]
\definesystemattribute [vboxtohboxseparator] [public]

\unexpanded\def\showattributes{\clf_showattributes}

%D Todo:

% \appendtoks
%     \clf_cleanupattributes
% \to \everyafterpagebreak

\protect \endinput

% for the luatex list:
%
% \attributedef\zeroattribute=0
% \attributedef\someattribute=999
%
% \directlua {
%     local createtoken = newtoken.create
%     function attributenumber(name)
%         local n = createtoken(name).mode - createtoken("zeroattribute").mode
%         return n >= 0 and n or false
%     end
% }
%
% \directlua{print(attributenumber("noneattribute"))}
% \directlua{print(attributenumber("someattribute"))}