%D \module
%D   [       file=core-tbl,
%D        version=1998.11.03,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Text Flow Tabulation,
%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. Non||commercial use is 
%C granted. 

\writestatus{loading}{Context Core Macros / Tabulation}

\unprotect

% |p2|p3| 2:3
% spanning 

% In-text tabbing environment
%
% \starttabulate[| separated template] % eg [|l|p|] or [|l|p|p|]
%   \NC ... \NC ... \NC\NR
% \stoptabulate
%
% with: two pass auto width calculation when no p-width
% specified, even with multiple p's, see examples.

%  TaBlE compatible specifications:
%
%  l  align column/paragraph left
%  r  align column/paragraph right
%  c  align column/paragraph center
%  p  p(dimen) of automatisch als alleen p
%  w  column width
%  f  font#1
%  B  bold
%  I  italic
%  S  slanted
%  T  type
%  R  roman
%  m  math
%  M  display math
%  h  hook (inner level or par lines)
%  b  before (may be command#1)
%  a  after
%  i  i<n> skip left of column
%  j  i<n> skip right of column
%  k  i<n> skip around column

%  Still to be done

% nesting, push en pop gebruiken 

%  N      math numbers (best hook into existing digits mechanism)
%  n      numbers (best hook into existing digits mechanism)
%  Q      math numbers (best hook into existing digits mechanism)
%  q      numbers (best hook into existing digits mechanism)
%  ~      \hskip.5em
%  |      check

%  10     evt auto stack; dan wel andere signal dan void nodig

%  present but not yet 100% ok
%
%  \FL    top hrule
%  \ML    mid hrule (with auto split)
%  \LL    bottom hrule
%  \HL 

%  \VL    as soon as needed
%  color  as soon as needed

%  \EQ \RQ \HQ  equal  (raw, hook)
%  \NC \RC \HC  normal (raw, hook)
%
%  \NR 

% tricky: align scans ahead, over # and expands ones before 
% while doing  

\newtoks\tabulatepreamble
\newtoks\tabulatebefore
\newtoks\tabulateafter
\newtoks\tabulatebmath
\newtoks\tabulateemath
\newtoks\tabulatefont
\newtoks\tabulatesettings

\newtoks\tabulatedummy

\newcounter\nofautotabulate
\newif     \ifautotabulate
\newbox    \tabulatebox
\newcounter\tabulatecolumns
\newif     \ifsplittabulate \splittabulatetrue
\newdimen  \tabulatepwidth
\newdimen  \tabulatewidth
\newdimen  \tabulateunit
\newif     \iftabulateequal

\def\noftabcolumns{10} % quick and dirty stack

\def\@@tabbox@@ {@@tabbox@}
\def\@@tabhook@@{@@tabhook@}

\dorecurse\noftabcolumns
  {\@EA\newbox\csname\@@tabbox@@\recurselevel\endcsname}

\def\checktabulatehook%
  {\ifnum\tabulatetype<2        
     \let\tabulatehook\relax
   \fi}

\def\dodosettabulatepreamble#1#2%
  {\ifdim\tabulatewidth=\!!zeropoint\relax
     \ifcase\tabulatemodus\relax
       \let\preamblebox\empty
     \else
       \def\preamblebox{\autotabulatetrue}%
     \fi
   \else
     \ifcase\tabulatemodus\relax
       \edef\preamblebox{\hbox to \the\tabulatewidth}%
     \else
       \edef\preamblebox{\hsize\the\tabulatewidth}%
     \fi
   \fi 
  % 0 = NC column next   EQ equal column 
  % 1 = RC column raw    RQ equal column raw   
  % 2 = HC column hook   HQ equal column hook 
   \@EA\appendtoks                 \@EA&\@EA\hskip\pretabskip##&\to\!!toksa
   \@EA\appendtoks\@EA\xdef\@EA\tabulatecolumn\@EA{\tabulatecolumns}\to\!!toksa
   \@EA\appendtoks                                  \preamblebox\to\!!toksa
       \appendtoks                       \bgroup\bbskip\bgroup#1\to\!!toksa
       \appendtoks                            \checktabulatehook\to\!!toksa
       \appendtoks\ifnum\tabulatetype=1 \else                   \to\!!toksa
   \@EA\appendtoks                            \the\tabulatebmath\to\!!toksa
   \@EA\appendtoks                             \the\tabulatefont\to\!!toksa
   \@EA\appendtoks                         \the\tabulatesettings\to\!!toksa
   \@EA\appendtoks                           \the\tabulatebefore\to\!!toksa
       \appendtoks\fi                                           \to\!!toksa
       \appendtoks                          \bgroup\ignorespaces\to\!!toksa
       \appendtoks                               \tabulatehook##\to\!!toksa
       \appendtoks                         \unskip\unskip\egroup\to\!!toksa
       \appendtoks\ifnum\tabulatetype=1 \else                   \to\!!toksa
   \@EA\appendtoks                            \the\tabulateafter\to\!!toksa
   \@EA\appendtoks                            \the\tabulateemath\to\!!toksa
       \appendtoks\fi                                           \to\!!toksa
       \appendtoks                              #2\egroup\egroup\to\!!toksa
   \@EA\appendtoks                  \@EA&\@EA\hskip\postabskip##\to\!!toksa
   \appendtoks\NC\to\tabulatedummy
   \let\bbskip\empty
   \def\pretabskip{.5\tabulateunit}%
   \def\postabskip{.5\tabulateunit}%
   \let\gettabulateexit\dogettabulateexit
   \tabulatewidth\!!zeropoint}

\def\dosettabulatepreamble%
  {\ifx\next\relax
     \let\nextnext\relax
   \else
     \let\nextnext\settabulatepreamble
     \ifx      l\next
       \chardef\tabulatealign=1
     \else\ifx r\next
       \chardef\tabulatealign=2
     \else\ifx c\next
       \chardef\tabulatealign=3
     \else\ifx p\next
       \let\nextnext\gettabulateparagraph
     \else\ifx w\next
       \let\nextnext\gettabulatewidth
     \else\ifx f\next
       \let\nextnext\gettabulatefont
     \else\ifx B\next
       \tabulatefont{\bf}%
     \else\ifx I\next
       \tabulatefont{\it}%
     \else\ifx S\next
       \tabulatefont{\sl}%
     \else\ifx T\next
       \tabulatefont{\tt}%
     \else\ifx R\next
       \tabulatefont{\rm}%
     \else\ifx m\next
       \tabulatebmath{$}%
       \tabulateemath{$}%
     \else\ifx M\next
       \tabulatebmath{$\displaystyle}%
       \tabulateemath{$}%
     \else\ifx h\next
       \let\nextnext\gettabulatehook
     \else\ifx b\next
       \let\nextnext\gettabulatebefore
     \else\ifx a\next
       \let\nextnext\gettabulateafter
     \else\ifx i\next
       \let\nextnext\gettabulatepreskip
     \else\ifx j\next
       \let\nextnext\gettabulateposskip
     \else\ifx k\next
       \let\nextnext\gettabulatepreposskip
     \else\ifx X\next
       \let\nextnext\gettabulateexit
     \else\ifx e\next
       \appendtoks\global\tabulateequaltrue\to\tabulatesettings
     \else\ifx ~\next
       \appendtoks\fixedspaces\to\tabulatesettings
     \else  
       \message{unknown preamble key [\meaning\next]}%
     \fi\fi \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi \fi\fi\fi\fi\fi
   \fi
   \nextnext}

\def\dogettabulateexit%
  {\let\postabskip\!!zeropoint
   \settabulatepreamble}

\let\gettabulateexit\dogettabulateexit

\def\gettabulatepreskip#1%
  {\doifnumberelse{#1}
     {\dimen0=#1\tabulateunit\let\next\empty}
     {\dimen0=.5\tabulateunit\def\next{#1}}%
   \edef\pretabskip{\the\dimen0}%
  \@EA\settabulatepreamble\next}

\def\gettabulateposskip#1%
  {\doifnumberelse{#1}
     {\dimen0=#1\tabulateunit\let\next\empty}
     {\dimen0=.5\tabulateunit\def\next{#1}}%
   \edef\postabskip{\the\dimen0}%
   \let\gettabulateexit\settabulatepreamble
   \@EA\settabulatepreamble\next}

\def\gettabulatepreposskip#1%
  {\doifnumberelse{#1}
     {\dimen0=#1\tabulateunit\let\next\empty}
     {\dimen0=.5\tabulateunit\def\next{#1}}%
   \edef\pretabskip{\the\dimen0}%
   \edef\postabskip{\the\dimen0}%
   \let\gettabulateexit\settabulatepreamble
   \@EA\settabulatepreamble\next}

\def\gettabulatehook#1%
  {\setvalue{\@@tabhook@@\tabulatecolumns}{#1}%
   \settabulatepreamble}

\def\gettabulatebefore#1%
  {\tabulatebefore{#1}%
   \settabulatepreamble}

\def\gettabulateafter#1%
  {\tabulateafter{#1}%
   \settabulatepreamble}

\def\gettabulatefont#1%
  {\tabulatefont{#1}%
   \settabulatepreamble}

\def\gettabulatewidth%
  {\chardef\tabulatemodus=0
   \doifnextcharelse{(}
     {\chardef\tabulatedimen=0
      \dogettabulatewidth}
     {\chardef\tabulatedimen=0
      \settabulatepreamble}}

\def\gettabulateparagraph%
  {\doifnextcharelse{(}
     {\chardef\tabulatemodus=1
      \chardef\tabulatedimen=1
      \dogettabulatewidth}
     {\chardef\tabulatemodus=2
      \chardef\tabulatedimen=0
      \settabulatepreamble}}

\def\dogettabulatewidth(#1)%
  {\tabulatewidth=#1\relax
   \ifnum\tabulatedimen=1
     \global\advance\tabulatepwidth\tabulatewidth
   \fi
   \settabulatepreamble}

\def\settabulatepreamble%
  {\afterassignment\dosettabulatepreamble\let\next=}

\def\tabulateraggedright {\ifnum\tabulatetype=1 \else\raggedright \fi}
\def\tabulateraggedcenter{\ifnum\tabulatetype=1 \else\raggedcenter\fi}
\def\tabulateraggedleft  {\ifnum\tabulatetype=1 \else\raggedleft  \fi}
\def\tabulatehss         {\ifnum\tabulatetype=1 \else\hss         \fi}

\def\nexttabulate#1|%
  {\chardef\tabulatealign=0
   \chardef\tabulatemodus=0
   \chardef\tabulatedimen=0
   \tabulatebefore{}%
   \tabulateafter{}%
   \tabulatebmath{}%
   \tabulateemath{}%
   \tabulatefont{}%
   \tabulatesettings{}%
   \doglobal\increment\tabulatecolumns
   \settabulatepreamble#1\relax\relax % permits i without n
   \ifcase\tabulatemodus\relax
     \ifcase\tabulatealign\relax
       \dodosettabulatepreamble\empty      \tabulatehss   \or
       \dodosettabulatepreamble\empty      \tabulatehss   \or
       \dodosettabulatepreamble\tabulatehss\empty         \or
       \dodosettabulatepreamble\tabulatehss\tabulatehss   \fi
   \or % fixed width
     \ifcase\tabulatealign\relax
       \dodosettabulatepreamble \bskip                      \eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedleft  }\eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi
   \or % auto width
     \doglobal\increment\nofautotabulate\relax
     \ifcase\tabulatealign\relax
       \dodosettabulatepreamble \bskip                      \eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedright }\eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedleft  }\eskip \or
       \dodosettabulatepreamble{\bskip\tabulateraggedcenter}\eskip \fi
   \fi
   \futurelet\next\donexttabulate}

\def\donexttabulate%
  {\ifx\next\relax\else
     \expandafter\nexttabulate
   \fi}

\def\splitofftabulatebox%
  {\mindermeldingen
   \@EA\setbox\@EA\tabulatebox\@EA\vsplit\csname\@@tabbox@@\tabulatecolumn\endcsname
     to \lineheight
   \setbox\tabulatebox=\vbox{\unvbox\tabulatebox}%
   \setbox\tabulatebox=\hbox to \wd\tabulatebox
     {\hss\dotabulatehook{\box\tabulatebox}\hss}%
   \ht\tabulatebox=\ht\strutbox
   \dp\tabulatebox=\dp\strutbox
   \box\tabulatebox}

\def\dotabulatehook%
  {\getvalue{\@@tabhook@@\tabulatecolumn}}

% \definetabulate
% \redefinetabulate
% \starttabulate[preamble]
% \starttabulate -> \starttabulate[|l|p|]

\def\definetabulate%
  {\dotripleempty\dodefinetabulate}

\def\dodefinetabulate[#1][#2][#3]%
  {\ifthirdargument
     \doifundefined{\??tt#1::\c!eenheid}
       {\copyparameters
          [\??tt#1::][\??tt\e!tabulate::]
          [\c!eenheid,\c!voor,\c!na,\c!binnen,\c!inspringen,EQ]}%
     \copyparameters
       [\??tt#1::#2][\??tt#1::]% 
       [\c!eenheid,\c!voor,\c!na,\c!binnen,\c!inspringen,EQ]%
     \setvalue{\e!start#1::#2}{\dofinalstarttabulate[#1][#2][#3]}%
     \setvalue{\e!start#1}{\bgroup\dosubstarttabulate[#1]}%
   \else\ifsecondargument
     \definetabulate[#1][][#2]%
   \else
     \definetabulate[#1][][|l|p|]%
   \fi\fi}

\def\dosubstarttabulate%
  {\dodoubleempty\dodosubstarttabulate}

\def\dodosubstarttabulate[#1][#2]%
  {\getvalue{\e!start#1::\ifundefined{\e!start#1::#2}\else#2\fi}}

\setvalue{\e!start\e!tabulate}%
  {\dodoubleempty\donormalstarttabulate}

\def\donormalstarttabulate[#1][#2]%
  {\bgroup
   \ifsecondargument
     \getparameters[\??tt\e!tabulate::][#2]%
   \fi
   \iffirstargument
     \def\next{\dofinalstarttabulate[\e!tabulate][][#1]}% 
   \else
     \def\next{\dofinalstarttabulate[\e!tabulate][][|l|p|]}% 
   \fi
   \next}

\def\dofinalstarttabulate[#1][#2][#3]% identifier sub preamble 
  {\edef\currenttabulate{#1::#2}%
   \ifinsidefloat \else
     \witruimte
     \getvalue{\??tt\currenttabulate\c!voor}%
   \fi
   \bgroup
   \getvalue{\??tt\currenttabulate\c!binnen}%
   \dimen0=\leftskip
   \advance\dimen0 by \hangindent
   \doifvalue{\??tt\currenttabulate\c!inspringen}{\v!ja}
     {\advance\dimen0 by \parindent}% \voorwit}%
   \edef\tabulateindent{\the\dimen0}%
   \!!toksb{}%
   \def\dorepeat*##1##2%
     {\dorecurse{##1}{\appendtoks##2\to\!!toksb}\do}%
   \def\do%
     {\futurelet\next\dodo}%
   \def\dodo%
     {\ifx\next\relax
        % exit
      \else\ifx*\next
        \let\next\dorepeat
      \else\ifx\bgroup\next
        \let\next\dododo
      \else
        \let\next\dodododo
      \fi\fi\fi
      \next}%
   \def\dododo##1%
     {\appendtoks{##1}\to\!!toksb\do}%
   \def\dodododo##1%
     {\appendtoks##1\to\!!toksb\do}%
   \xdef\tabulatecolumn{0}%
   \do#3\relax
   \processcontent
     {\e!stop#1}% \currenttabulate}
     \tabulatecontent
     {\@EA\processtabulate\@EA[\the\!!toksb]}}

\chardef\tabulatetype=0

% 0 = NC column next   EQ equal column 
% 1 = RC column raw    RQ equal column raw   
% 2 = HC column hook   HQ equal column hook 

\def\tabulateEQ%
  {\getvalue{\??tt\currenttabulate EQ}\global\tabulateequalfalse} 

\def\tabulatenormalcolumn#1%
  {&\iftabulateequal\tabulateEQ\fi&\global\chardef\tabulatetype=#1&}

\def\tabulateequalcolumn#1%
  {&\tabulateEQ&\global\chardef\tabulatetype=#1&}

\def\tabulateautocolumn%
  {\tabulatenormalcolumn0\relax
   \ifnum\tabulatecolumn>\tabulatecolumns\relax
     \expandafter\NR
   \else
     \expandafter\ignorespaces % interferes with the more tricky hooks 
   \fi}

\def\setquicktabulate#1% see \startlegend \startgiven 
  {\let#1=\tabulateautocolumn
   \let\\=\tabulateautocolumn}

\def\processtabulate[|#1|]%
  {\tabulateunit=\getvalue{\??tt\currenttabulate\c!eenheid}%
   \let\pretabskip\!!zeropoint
   \def\postabskip{.5\tabulateunit}%
   \doglobal\newcounter\tabulatecolumns
   \doglobal\newcounter\nofautotabulate
   \doglobal\newcounter\noftabulatelines
   \global\tabulatepwidth=\!!zeropoint
   \global\tabulateequalfalse
   \def\NC{\tabulatenormalcolumn0}%
   \def\RC{\tabulatenormalcolumn1}%
   \def\HC{\tabulatenormalcolumn2}%
   \def\EQ{\tabulateequalcolumn 0}%
   \def\RQ{\tabulateequalcolumn 1}%
   \def\HQ{\tabulateequalcolumn 2}%
   \def\NR% next row 
     {\doglobal\increment\noftabulatelines
      \global\tabulateequalfalse 
      \xdef\tabulatecolumn{0}%
      \unskip\unskip\crcr\flushtabulated}%
   \let\HL\empty
   \let\FL\empty
   \let\ML\empty
   \let\LL\empty
   \global\let\flushtabulated\empty
   \let\savedbar=|\let|\nexttabulate
   \tabskip\!!zeropoint
   \!!toksa{&\hbox to \tabulateindent{}##\strut&##}%
   \tabulatewidth\!!zeropoint
   |#1X|\relax
   \appendtoks&##\to\!!toksa
   \appendtoks\doglobal\increment\tabulatecolumn\to\!!toksa
   \appendtoks\NC\unskip\unskip\crcr\flushtabulated\to\tabulatedummy % no count
   \xdef\tabulatecolumn{0}%
   \def\bskip%
     {\setbox\tabulatebox=\vbox\bgroup
        \global\let\tabulatehook\empty}%
   \def\eskip
     {\egroup
      \global\let\tabulatehook\dotabulatehook}%
   \let|\savedbar
   \global\let\tabulatehook\dotabulatehook
   \doifvalue{\??tt\currenttabulate\c!inspringen}{\v!nee}
     {\forgetparindent}% 
   \ifinsidefloat 
     \let\tabulateindent\!!zeropoint
   \else 
     \setlocalhsize \hsize=\localhsize 
   \fi
   \mindermeldingen
   \forgetall
   \ifnum\nofautotabulate>0
     \setbox0=\ruledvbox
       {\let\tabulateindent\!!zeropoint\@EA\halign\@EA{\the\!!toksa\cr\tabulatecontent\crcr}}%
     \tabulatewidth\hsize
     \advance\tabulatewidth by -\wd0
     \advance\tabulatewidth by -\tabulatepwidth
     \ifnum\nofautotabulate>0
       \divide\tabulatewidth by \nofautotabulate\relax
     \fi
   \fi
   \ifsplittabulate
     \splittopskip\ht\strutbox
     \global\let\flushtabulatedindeed\empty
     \long\def\bbskip%
       {\@EA\ifvoid\csname\@@tabbox@@\tabulatecolumn\endcsname
          \ifx\flushtabulatedindeed\empty\else
            \setbox0\hbox
          \fi
       \fi}%
     \def\bskip%
       {\@EA\ifvoid\csname\@@tabbox@@\tabulatecolumn\endcsname
          \@EA\global\@EA\setbox\csname\@@tabbox@@\tabulatecolumn\endcsname=\vbox
          \bgroup
          \global\let\tabulatehook\empty
          \ifautotabulate\hsize\tabulatewidth\fi
         %\begstrut % interferes with pre-\pars 
          \ignorespaces
          \def\eskip%
            {\egroup
             \global\let\tabulatehook\dotabulatehook
             \splitofftabulatebox}%
        \else
          \let\eskip\empty
          \mindermeldingen
          \global\let\tabulatehook\dotabulatehook
          \expandafter\splitofftabulatebox
        \fi}%
     \gdef\flushtabulated%
       {\noalign % no interference !
          {\global\let\flushtabulatedindeed\empty
           \dorecurse\noftabcolumns
             {\@EA\ifvoid\csname\@@tabbox@@\recurselevel\endcsname\else
                \gdef\flushtabulatedindeed{\the\tabulatedummy}%
              \fi}}%
        \flushtabulatedindeed}%
   \else
    % tabhook op alles ?
     \def\bskip%
       {\vtop\bgroup
          \ifautotabulate\hsize\tabulatewidth\fi
         %\begstrut % interferes with pre-\pars 
          \ignorespaces}%
     \def\eskip%
       {\egroup}%
   \fi
   \let\totalnoftabulatelines\noftabulatelines
   \doglobal\newcounter\noftabulatelines
   \def\HL{\TABLEnoalign
     {\ifnum\noftabulatelines=0                                 \FL
      \else\ifnum\noftabulatelines<\totalnoftabulatelines\relax \ML
      \else                                                     \LL
      \fi\fi}}%
   \def\tablebaselinecorrection
     {\def\dobaselinecorrection
        {\vskip-\prevdepth
         \vskip\dp\strutbox
         \vskip\dp\strutbox}%
      \baselinecorrection}%
   \def\FL{\TABLEnoalign
     {\ifinsidefloat\else
        \doifvaluenothing{\??tt\currenttabulate\c!voor}    
          {\tablebaselinecorrection}%
      \fi
      \hrule \!!height .2pt \!!depth .2pt
      \nobreak
      \vskip\dp\strutbox
      \nobreak}}%
   \def\ML{\TABLEnoalign
     {\vskip\dp\strutbox
      \hrule \!!height .2pt \!!depth .2pt
      \vskip\topskip\allowbreak\vskip-\topskip\vskip-.4pt
      \hrule \!!height .2pt \!!depth .2pt
      \vskip\dp\strutbox}}%
   \def\LL{\TABLEnoalign
     {\nobreak
      \vskip\dp\strutbox
      \nobreak
      \hrule \!!height .2pt \!!depth .2pt
      \ifinsidefloat\else
        \doifvaluenothing{\??tt\currenttabulate\c!na}    
          {\vskip\dp\strutbox
           \vbox{\strut}
           \vskip-\lineheight}%
      \fi}}%
   %\def\FL{\dotoptextrule   {}}%
   %\def\ML{\domiddletextrule{}}%
   %\def\LL{\dobottomtextrule {}}%
   \@EA\halign\@EA{\the\!!toksa\cr\tabulatecontent\crcr}%
   \egroup
   \ifinsidefloat \else
     \getvalue{\??tt\currenttabulate\c!na}%
   \fi
   \egroup}

\def\setuptabulate%
  {\dotripleempty\dosetuptabulate}

\def\dosetuptabulate[#1][#2][#3]%
  {\ifthirdargument
     \getparameters[\??tt#1::#2][#3]%
   \else\ifsecondargument
     \getparameters[\??tt#1::][#2]%
   \else
     \getparameters[\??tt\e!tabulate::][#1]%
   \fi\fi}

\setuptabulate
  [\c!eenheid=1em,
   EQ={:},
   \c!binnen=,
   \c!voor=\blanko,
   \c!na=\blanko,
   \c!inspringen=\v!nee]

\protect

\endinput
