%D \module
%D   [       file=core-tbl,
%D        version=1998.11.03,
%D          title=\CONTEXT\ Table Macros,
%D       subtitle=Text Flow Tabulation,
%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.


% \starttabulate[|TCT{maincolor}|c|c|c|p|]
%
% maybe have a color style for header lines

\writestatus{loading}{ConTeXt Table Macros / Tabulation}

\unprotect

% These are set at the lua end by parser:

\newinteger\c_tabl_tabulate_nofcolumns
\newinteger\c_tabl_tabulate_has_rule_spec_first
\newinteger\c_tabl_tabulate_has_rule_spec_last

\registerctxluafile{tabl-tbl}{autosuffix} % experiment

%D I can probably reimplement this using a \LUATEX\ combination but it does not pay
%D of in development time. If I need something else I will write it from scratch
%D anyway. This module looks a bit complex which is a consequence of it dealing with
%D paragraphs being split over pages and that there are several passes over the data
%D set. We can probably do some cleanup (combine/split).
%D
%D Caching the preamble does not save much (compared to other bits and pieces of
%D \CONTEXT). There are not that many ways to deal with preambles and this is just
%D one of them. The keys are somewhat similar to those of the \TABLE\ package.

% |p2|p3| 2:3 -> spanning (maybe)
%
% 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
%  A  {alignmentoptions}
%  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
%  d  digits (~)
%
%  C  [LMRT] {color} % T is text color
%
%  |  {color,n}
%
%  s  setups
%
%  g  g{char} align at char
%  .  align at .
%  ,  align at ,
%
%  Still to be done
%
%  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
%
%  nesting
%
%  10     evt auto stack; dan wel andere signal dan void nodig
%
%  present but not yet 100% ok
%
%  \TL [width,color]   bottom hrule
%  \FL [width,color]   first hrule
%  \ML [width,color]   mid hrule (with auto split)
%  \LL [width,color]   bottom hrule
%  \BL [width,color]   last hrule
%
%  \HL [width,color]   top rule
%  \VL [width,color]
%
%  \CC \CL \CM \CR color
%
%  \EQ \RQ \HQ     equal  (raw, hook)
%  \NC \RC \HC     normal (raw, hook)
%
%  \NR  checked break
%  \NB  no break
%
%  \HR : rule with lineheight
%
%  \autotabulaterule : with lineheight, not first/last
%  \autotabulateline : spaced, not first/last
%  \tabulaterule     : with lineheight
%  \tabulateline     : spaced
%
% tricky: align scans ahead, over # and expands ones before
% while doing
%
% new:
%
% \starttabulate[|cg{.}|cg{,}|cg{,}|]
% \NC period     \NC comma      \NC comma   \NC\NR
% \NG 100.000,00 \NG 100.000,00 \NG 100,00  \NC\NR
% \NG 10.000,00  \NG 10.000,00  \NG 1000,00 \NC\NR
% \NG 100,00     \NG 100,00     \NG 10,00   \NC\NR
% \NG 10         \NG 10         \NG 0,00    \NC\NR
% \stoptabulate
%
% \starttabulate[|c.|c,|c,|]
% \NC period     \NC comma      \NC comma   \NC\NR
% \NG 100.000,00 \NG 100.000,00 \NG 100,00  \NC\NR
% \NG 10.000,00  \NG 10.000,00  \NG 1000,00 \NC\NR
% \NG 100,00     \NG 100,00     \NG 10,00   \NC\NR
% \NG 10         \NG 10         \NG 0,00    \NC\NR
% \stoptabulate

% nice demo (for BG)
%
% \starttabulate[|r|b{$\star$}|ra{\percent}|b{=}|r|]
% \NC 500 \NC \NC 60 \NC \NC 300 \NC \NR
% \NC 500 \NC \NC 55 \NC \NC 275 \NC \NR
% \NC 500 \NC \NC 50 \NC \NC 250 \NC \NR
% \NC 500 \NC \NC 45 \NC \NC 225 \NC \NR
% \NC 500 \NC \NC 40 \NC \NC 200 \NC \NR
% \NC 500 \NC \NC 35 \NC \NC 175 \NC \NR
% \NC 500 \NC \NC 30 \NC \NC 150 \NC \NR
% \NC 500 \NC \NC 25 \NC \NC 125 \NC \NR
% \NC 500 \NC \NC 20 \NC \NC 100 \NC \NR
% \stoptabulate

\newtoks         \t_tabl_tabulate_preamble
\newtoks         \t_tabl_tabulate_before
\newtoks         \t_tabl_tabulate_after
\newtoks         \t_tabl_tabulate_bmath
\newtoks         \t_tabl_tabulate_emath
\newtoks         \t_tabl_tabulate_font
\newtoks         \t_tabl_tabulate_settings
\newtoks         \t_tabl_tabulate_dummy
\newtoks         \t_tabl_tabulate_every_row
\newtoks         \t_tabl_tabulate_every_after_row
\newtoks         \t_tabl_tabulate_every_real_row

\newtoks         \t_tabl_tabulate_initializers_first
\newtoks         \t_tabl_tabulate_initializers_second

\newinteger      \c_tabl_tabulate_nofauto
\newinteger      \c_tabl_tabulate_columns
\newinteger      \c_tabl_tabulate_column
\newinteger      \c_tabl_tabulate_plines_min
\newinteger      \c_tabl_tabulate_plines_max
\newinteger      \c_tabl_tabulate_max_colorcolumn
\newinteger      \c_tabl_tabulate_max_vrulecolumn
\newinteger      \c_tabl_tabulate_repeathead
\newinteger      \c_tabl_tabulate_noflines
\newinteger      \c_tabl_tabulate_totalnoflines
\newinteger      \c_tabl_tabulate_minusnoflines
\newinteger      \c_tabl_tabulate_align
\newinteger      \c_tabl_tabulate_nofrealrows
\newinteger      \c_tabl_tabulate_autocolor

\newconditional  \c_tabl_tabulate_nopbreak
\newconditional  \c_tabl_tabulate_firstflushed
\newconditional  \c_tabl_tabulate_equal
\newconditional  \c_tabl_tabulate_split
\newconditional  \c_tabl_tabulate_automode
\newconditional  \c_tabl_tabulate_handlepbreak
\newconditional  \c_tabl_tabulate_autorulespacing
\newconditional  \c_tabl_tabulate_someamble
\newconditional  \c_tabl_tabulate_tolerant_break
\newconditional  \c_tabl_tabulate_splitoff_whitespace
\newconditional  \c_tabl_tabulate_pwidth_set
\newconditional  \c_tabl_tabulate_reshape
\newconditional  \c_tabl_tabulate_no_blank_in_paragraphs % can become always on
\newconditional  \c_tabl_tabulate_no_interline_space

\c_tabl_tabulate_split                 \conditionaltrue
\c_tabl_tabulate_handlepbreak          \conditionaltrue
\c_tabl_tabulate_autorulespacing       \conditionaltrue
\c_tabl_tabulate_no_blank_in_paragraphs\conditionaltrue

\newdimension    \d_tabl_tabulate_width_p
\newdimension    \d_tabl_tabulate_width_w
\newdimension    \d_tabl_tabulate_width
\newdimension    \d_tabl_tabulate_unit
\newdimension    \d_tabl_tabulate_height_p_max
\newdimension    \d_tabl_tabulate_vrulethickness_default
\newdimension    \d_tabl_tabulate_hrulethickness_default
\newdimension    \d_tabl_tabulate_hruledashsteps_default
\newdimension    \d_tabl_tabulate_vrulethickness
\newdimension    \d_tabl_tabulate_hrulethickness          % not used
\newdimension    \d_tabl_tabulate_vrulethickness_local
\newdimension    \d_tabl_tabulate_hrulethickness_local
\newdimension    \d_tabl_tabulate_hruledashsteps_local
\newdimension    \d_tabl_tabulate_indent
\newdimension    \d_tabl_tabulate_splitoff_betweenskip
\newdimension    \d_tabl_tabulate_margin
\newcount        \c_tabl_tabulate_step

\newgluespec     \s_tabl_tabulate_pre
\newgluespec     \s_tabl_tabulate_post
\newgluespec     \s_tabl_tabulate_first
\newgluespec     \s_tabl_tabulate_last
\newgluespec     \s_tabl_tabulate_separator

\newbox          \b_tabl_tabulate

\newconstant     \c_tabl_tabulate_pass
\newconstant     \c_tabl_tabulate_type
\newconstant     \c_tabl_tabulate_kind % 1=strong  2=equals
\newconstant     \c_tabl_tabulate_splitlinemode    \c_tabl_tabulate_splitlinemode\plustwo % \plusone
\newconstant     \c_tabl_tabulate_colorspan
\newconstant     \c_tabl_tabulate_localcolorspan
\newconstant     \c_tabl_tabulate_modus

%newconditional  \c_tabl_pre_is_set
\newconditional  \c_tabl_post_is_set

\lettonothing    \m_tabl_tabulate_separator_factor  % fraction

\aliasinteger\tabulatesplitlinemode\c_tabl_tabulate_splitlinemode % temp hack, we need an interface

\newtoks         \everytabulatepar           % where used ?
\newtoks         \everytabulate              % public ?

\permanent\protected\def\tolerantTABLEbreaktrue{\c_tabl_tabulate_tolerant_break\conditionaltrue} % used in styles !

\permanent\def\noftabulaterows{\the\c_tabl_tabulate_noflines} % handy for testing if a table is empty

\installcorenamespace{tabulatebox}
\installcorenamespace{tabulatesetup}
\installcorenamespace{tabulatehook}
\installcorenamespace{tabulatesplit}
\installcorenamespace{tabulateseparator}
\installcorenamespace{tabulatecolor}
\installcorenamespace{tabulateheader}
\installcorenamespace{tabulatealigning}
\installcorenamespace{tabulatepreamble}
\installcorenamespace{tabulatevrule}

\installcorenamespace{tabulatehead}
\installcorenamespace{tabulatefoot}
\installcorenamespace{tabulatenext}

\prependtoks
    \global\c_tabl_tabulate_nofrealrows\zerocount
\to \t_tabl_tabulate_initializers_first

\prependtoks
    \global\c_tabl_tabulate_nofrealrows\zerocount
\to \t_tabl_tabulate_initializers_second

\prependtoks
    \global\advanceby\c_tabl_tabulate_nofrealrows\plusone
\to \t_tabl_tabulate_every_real_row

\permanent\def\b_tabl_tabulate_current#1%
  {\csname\??tabulatebox\number#1\endcsname} % beware, a synonym

\def\tabl_tabulate_initialize_boxes#1%
  {\scratchcounter#1\relax
   \tabl_tabulate_initialize_boxes_step}

\def\tabl_tabulate_initialize_boxes_step
  {\ifnum\scratchcounter>\zerocount
     \tabl_tabulate_initialize_box\scratchcounter
     \advanceby\scratchcounter\minusone
     \expandafter\tabl_tabulate_initialize_boxes_step
   \fi}

\def\tabl_tabulate_initialize_box#1% also used elsewhere
  {\ifcsname\??tabulatebox\number#1\endcsname
     \tabl_tabulate_initialize_box_yes
   \else
     \tabl_tabulate_initialize_box_nop#1%
   \fi}

\def\tabl_tabulate_initialize_box_yes  {\global\setbox\lastnamedcs\emptybox}
\def\tabl_tabulate_initialize_box_nop#1{\expandafter\newbox\csname\??tabulatebox\number#1\endcsname}

\tabl_tabulate_initialize_boxes{16} % not really needed

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

% [|lg{.}|] => \NG 12.34 \NC % old
% [|lG{.}|] => \NG 12.34 \NC % new

% The tracer is gone as if interfered and I never used it anyway. After all,
% we can use \showmakleup[vpenalty].

\def\tabl_tabulate_nobreak_inject
  {\noalign{\tabl_tabulate_break_no}}

\protected\def\tabl_tabulate_hook_check
  {\ifnum\c_tabl_tabulate_type<\plustwo
     \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop
   \else
     \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
   \fi}

\protected\def\tabl_tabulate_setups_check
  {\begincsname\??tabulatesetup\the\c_tabl_tabulate_column\endcsname}

\let\tabl_tabulate_kooh\relax

\protected\def\tabl_tabulate_entry_before{\ignorespaces\tabl_tabulate_hook}
\protected\def\tabl_tabulate_entry_after {\unskip\unskip\ifmmode\else\endgraf\fi\tabl_tabulate_kooh}

\protected\def\tabl_tabulate_shaped_par_begin
  {\dowithnextboxcs\tabl_tabulate_shaped_par_finish\vbox\bgroup}

\def\tabl_tabulate_shaped_par_finish
  {\clf_doreshapeframedbox\nextbox\relax
   \ifvmode\unvbox\else\box\fi\nextbox}

\let\tabl_tabulate_shaped_par_end\egroup

\ifdefined\dotagtabulatecell   \else \aliased\let\dotagtabulatecell  \relax \fi
\ifdefined\dotagtabulatesignal \else \aliased\let\dotagtabulatesignal\relax \fi

\protected\def\tabl_tabulate_check_local_color_first#1#2%
  {\relax}

\protected\def\tabl_tabulate_check_local_color_second#1#2%
  {\relax
   \ifempty\m_tabl_tabulate_color_local
     \xdef\m_tabl_tabulate_color{#1}%
   \else
     \glet\m_tabl_tabulate_color\m_tabl_tabulate_color_local
     \glettonothing\m_tabl_tabulate_color_local
   \fi
   \ifcase\c_tabl_tabulate_localcolorspan
     \global\c_tabl_tabulate_colorspan#2\relax
   \else
     \global\c_tabl_tabulate_colorspan\c_tabl_tabulate_localcolorspan
     \global\c_tabl_tabulate_localcolorspan\zerocount
   \fi}

\protected\def\tabl_tabulate_check_local_vrule_thickness#1%
  {\relax
   \ifcase\d_tabl_tabulate_vrulethickness_local
     \global\d_tabl_tabulate_vrulethickness#1\relax
   \else
     \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_local
     \global\d_tabl_tabulate_vrulethickness_local\zeropoint
   \fi}

\protected\def\tabl_tabulate_check_local_vrule_color_first#1%
  {\relax}

\protected\def\tabl_tabulate_check_local_vrule_color_second#1%
  {\relax
   \ifempty\m_tabl_tabulate_vrule_color_local
     \xdef\m_tabl_tabulate_vrule_color{#1}%
   \else
     \glet\m_tabl_tabulate_vrule_color\m_tabl_tabulate_vrule_color_local
     \glettonothing\m_tabl_tabulate_vrule_color_local
   \fi}

\let\tabl_tabulate_check_local_color      \gobbletwoarguments
\let\tabl_tabulate_check_local_vrule_color\gobbleoneargument

\appendtoks
    \let\tabl_tabulate_check_local_color      \tabl_tabulate_check_local_color_first
    \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \let\tabl_tabulate_check_local_color      \tabl_tabulate_check_local_color_second
    \let\tabl_tabulate_check_local_vrule_color\tabl_tabulate_check_local_vrule_color_second
\to \t_tabl_tabulate_initializers_second

% \protected % we can expand this one
\def\tabl_tabulate_inject_pre_skip#1%
  {\ifdim#1>\zeropoint
     \kern#1\relax % hskip
   \orelse\ifzero\c_tabl_tabulate_column
     \ifconditional\c_tabl_tabulate_autorulespacing
       \ifcase\c_tabl_tabulate_has_rule_spec_first\else
         \kern\s_tabl_tabulate_first\relax % hskip
       \fi
     \fi
   \fi}

% \protected % we can expand this one
\def\tabl_tabulate_inject_post_skip#1#2%
  {\ifdim#1>\zeropoint
     \kern\ifnum\c_tabl_tabulate_columns=\c_tabl_tabulate_nofcolumns#2\else#1\fi\relax
   \orelse\ifnum\c_tabl_tabulate_columns=\c_tabl_tabulate_nofcolumns
     \ifconditional\c_tabl_tabulate_autorulespacing
       \ifcase\c_tabl_tabulate_has_rule_spec_last\else
         \kern\s_tabl_tabulate_last\relax % hskip
       \fi
     \fi
   \fi}

\let\tabl_tabulate_hook_b\donothing
\let\tabl_tabulate_hook_e\donothing
\let\tabl_tabulate_hook_g\donothing
\let\tabl_tabulate_hook_G\donothing

\newconditional\c_tabl_use_size
\newconditional\c_tabl_sparse_skips

\c_tabl_use_size    \conditionaltrue % default per 2022-08-25
\c_tabl_sparse_skips\conditionaltrue % default per 2022-08-25

% \installtexdirective {tabulateusesize}     {\c_tabl_use_size    \conditionaltrue} {\c_tabl_use_size    \conditionalfalse}
% \installtexdirective {tabulatesparseskips} {\c_tabl_sparse_skips\conditionaltrue} {\c_tabl_sparse_skips\conditionalfalse}

\def\tabl_tabulate_tag_start
  {\dostarttaggedchained\t!tabulate\empty\empty\??tabulation}

\def\tabl_tabulate_tag_start_row
  {\dostarttaggednodetail\t!tabulaterow}

\def\tabl_tabulate_tag_start_cell
  {\dostarttaggednodetail\t!tabulatecell
   \dotagtabulatecell}

\def\tabl_tabulate_tag_stop
  {\dostoptagged}

\def\tabl_tabulate_tag_stop_row
  {\dostoptagged}

\def\tabl_tabulate_tag_stop_cell
  {\dostoptagged}

\noaligned\def\tabl_tabulate_disable_tagging
  {\lettonothing\tabl_tabulate_tag_start
   \lettonothing\tabl_tabulate_tag_start_row
   \lettonothing\tabl_tabulate_tag_start_cell
   \lettonothing\tabl_tabulate_tag_stop
   \lettonothing\tabl_tabulate_tag_stop_row
   \lettonothing\tabl_tabulate_tag_stop_cell}

\lettonothing\m_tabl_tabulate_alignment

\def\tabl_tabulate_set_preamble_step#1#2% only makes sense for many tabulates
  {\etoksapp\t_tabl_tabulate_preamble{%
        % begin of between/initial part
        \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness
        \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color
        \tabl_tabulate_check_local_color\constantemptyargument\m_tabl_tabulate_color\constantnumberargument\c_tabl_tabulate_colorspan
        \tabl_tabulate_color_side_right
        % end of between/initial part
        \aligntab
        % begin of left part
        \tabl_tabulate_column_vrule_inject
        \tabl_tabulate_color_side_left
        \tabl_tabulate_inject_pre_skip{\the\dimexpr\s_tabl_tabulate_pre}% get rid of plus
        \aligncontent % \alignmark\alignmark
        % end of left part
        \ifconditional\c_tabl_use_size
          \tabsize\zeropoint
        \fi
        \aligntab
        % begin of main cell
        \tabl_tabulate_color_side_both
        \global\c_tabl_tabulate_colorspan\zerocount
        \global\c_tabl_tabulate_column\constantnumber\c_tabl_tabulate_columns
        \tabl_tabulate_hook_g
        \tabl_tabulate_anchor % new
        \tabl_tabulate_setups_check % unexpandable
        \tabl_tabulate_hook_check   % unexpandable
        \ifzeropt\d_tabl_tabulate_width
            \ifcase\c_tabl_tabulate_modus\else
               \c_tabl_tabulate_automode\conditionaltrue
            \fi
        \else
            \ifcase\c_tabl_tabulate_modus
                \ifconditional\c_tabl_use_size
                    \tabsize % we could remove one level of grouping
                \else
                    \hbox to
                \fi
            \else
                \hsize
            \fi
            \the\d_tabl_tabulate_width
        \fi
        \bgroup
            \tabl_tabulate_bbskip
            \bgroup % we cannot combine the if because a cell may have only one ##
                \tabl_tabulate_hook_b
                \c_tabl_tabulate_align\constantnumber\c_tabl_tabulate_align % needed in tag passing
                \ifempty\m_tabl_tabulate_alignment \else
                    \spac_align_use_now{\m_tabl_tabulate_alignment}%
                \fi
                \noexpand\tabl_tabulate_tag_start_cell
                \noexpand#1%
                \ifconditional\c_tabl_tabulate_reshape
                    \tabl_tabulate_shaped_par_begin
                \fi
                \dotagtabulatesignal % empty cells
                \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else
                    \the\t_tabl_tabulate_bmath % maybe later? can interfere with char 0
                    \the\t_tabl_tabulate_font
                    \the\t_tabl_tabulate_settings
                    \the\t_tabl_tabulate_before
                    \ifempty\m_tabl_tabulate_text_color
                        \expandafter\gobbleoneargument
                    \else
                        \expandafter\colo_helpers_direct_activate
                    \fi\m_tabl_tabulate_text_color
                \noexpand\fi
                % grouping needs to be outside macros (or expandable), nice test
                % example \NC \string \aligntab \NC which will fail otherwise (mk)
                \bgroup
                \tabl_tabulate_hook_G
                \tabl_tabulate_entry_before
                \tabl_tabulate_hook_box_begin % might move
                \aligncontent
                \tabl_tabulate_hook_box_end   % might move
                \tabl_tabulate_entry_after
                \egroup
                \noexpand\ifnum\noexpand\c_tabl_tabulate_type=\plusone\noexpand\else
                    \the\t_tabl_tabulate_after
                    \the\t_tabl_tabulate_emath
                \noexpand\fi
                \ifconditional\c_tabl_tabulate_reshape
                    \tabl_tabulate_shaped_par_end
                \else
                \fi
                \noexpand#2%
                \tabl_tabulate_hook_e
            \egroup
        \egroup
        % end of main cell
        \aligntab
        \ifconditional\c_tabl_use_size
          \tabsize\zeropoint
        \fi
        % begin of right part
        \noexpand\tabl_tabulate_tag_stop_cell
        \tabl_tabulate_inject_post_skip
          {\the\ifconditional\c_tabl_post_is_set\s_tabl_tabulate_post\else\s_tabl_tabulate_last\fi}%
          {\the\s_tabl_tabulate_post}%
        \aligncontent % \alignmark\alignmark
        % end of right part
   }%
   \toksapp\t_tabl_tabulate_dummy{\NC}%
   \s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\relax
   \ifnum\c_tabl_tabulate_columns<{\c_tabl_tabulate_nofcolumns-\plusone}%
     \s_tabl_tabulate_post\s_tabl_tabulate_pre
   \else
     \s_tabl_tabulate_post\zeroskip
   \fi
  %\let\gettabulateexit\dogettabulateexit % still needed ?
   \d_tabl_tabulate_width\zeropoint
   %c_tabl_pre_is_set\conditionalfalse
   \c_tabl_post_is_set\conditionalfalse}

\permanent\protected\def\installtabulatepreambleoption#1#2%
  {\defcsname\??tabulatepreamble\string#1\endcsname{#2}}%

\installtabulatepreambleoption{x}{\c_tabl_tabulate_align\zerocount
                                  \tabl_tabulate_set_preamble} % internal
\installtabulatepreambleoption{l}{\c_tabl_tabulate_align\plusone
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{r}{\c_tabl_tabulate_align\plustwo
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{c}{\c_tabl_tabulate_align\plusthree
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{p}{\tabl_tabulate_set_paragraph}
\installtabulatepreambleoption{s}{\tabl_tabulate_set_setups}
\installtabulatepreambleoption{w}{\tabl_tabulate_set_width}
\installtabulatepreambleoption{f}{\tabl_tabulate_set_font}
\installtabulatepreambleoption{B}{\t_tabl_tabulate_font{\bf}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{I}{\t_tabl_tabulate_font{\it}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{S}{\t_tabl_tabulate_font{\sl}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{T}{\t_tabl_tabulate_font{\tt}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{R}{\t_tabl_tabulate_font{\rm}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{m}{\t_tabl_tabulate_bmath{\normalstartimath}%
                                  \t_tabl_tabulate_emath{\normalstopimath}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{M}{\t_tabl_tabulate_bmath{\normalstartimath\forcedisplaymath}%
                                  \t_tabl_tabulate_emath{\normalstopimath}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{h}{\tabl_tabulate_set_hook}
\installtabulatepreambleoption{b}{\tabl_tabulate_set_before}
\installtabulatepreambleoption{a}{\tabl_tabulate_set_after}
\installtabulatepreambleoption{i}{\tabl_tabulate_set_preskip}
\installtabulatepreambleoption{j}{\tabl_tabulate_set_posskip}
\installtabulatepreambleoption{k}{\tabl_tabulate_set_preposskip}
\installtabulatepreambleoption{e}{\toksapp\t_tabl_tabulate_settings{\global\c_tabl_tabulate_equal\conditionaltrue}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{g}{\tabl_tabulate_set_align}
\installtabulatepreambleoption{G}{\tabl_tabulate_set_align_new}
\installtabulatepreambleoption{.}{\tabl_tabulate_set_align.}
\installtabulatepreambleoption{,}{\tabl_tabulate_set_align,}
\installtabulatepreambleoption{C}{\tabl_tabulate_set_color_span}
\installtabulatepreambleoption{d}{\toksapp\t_tabl_tabulate_settings{\fixedspaces}%
                                  \tabl_tabulate_set_preamble}
\installtabulatepreambleoption{ }{\tabl_tabulate_set_preamble}
\installtabulatepreambleoption{A}{\tabl_tabulate_set_alignment}

%D We no longer deal with \type {~} here but map it onto \type {d} instead. Of
%D course we could prefix a key with \type {\meaning} instead, which works ok (and
%D is needed in order to pseudo expand \type {\next}, but is ugly at the same time.
%D The type {d} stands for digitspace.

%D \starttyping
%D \installtabulatepreambleoption{~}{...} % see 'd'
%D \stoptyping
%D
%D Also, as there is always a key, we no longer do some after assigment or future
%D let but just pick up the key.

\installtabulatepreambleoption\relax
  {} % finished

\def\tabl_tabulate_set_preamble#1%
  {\ifcsname\??tabulatepreamble\string#1\endcsname
     \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
   \else
     \expandafter\tabl_tabulate_set_preamble_nop
   \fi{#1}}

\def\tabl_tabulate_set_preamble_yes#1%
  {\csname\??tabulatepreamble\string#1\expandafter\endcsname}

\def\tabl_tabulate_set_preamble_nop#1%
  {\writestatus{tabulate}{unknown preamble key: #1}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_preskip#1%
  {%\c_tabl_pre_is_set\conditionaltrue
   \doifelsenumber{#1}%
     {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble  }%
     {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}

\def\tabl_tabulate_set_posskip#1%
  {\c_tabl_post_is_set\conditionaltrue
   \doifelsenumber{#1}%
     {\s_tabl_tabulate_post#1\d_tabl_tabulate_unit\tabl_tabulate_set_preamble  }%
     {\s_tabl_tabulate_post.5\d_tabl_tabulate_unit\tabl_tabulate_set_preamble#1}}

\def\tabl_tabulate_set_preposskip#1%
  {%c_tabl_pre_is_set \conditionaltrue
   \c_tabl_post_is_set\conditionaltrue
   \doifelsenumber{#1}%
     {\s_tabl_tabulate_pre#1\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble  }%
     {\s_tabl_tabulate_pre.5\d_tabl_tabulate_unit\s_tabl_tabulate_post\s_tabl_tabulate_pre\tabl_tabulate_set_preamble#1}}

\def\tabl_tabulate_set_setups#1%
  {\defcsname\??tabulatesetup\the\c_tabl_tabulate_columns\endcsname{\setups[#1]}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_hook#1%
  {\defcsname\??tabulatehook\the\c_tabl_tabulate_columns\endcsname{#1}%
   \tabl_tabulate_set_preamble}

% begin of character align plugin

\newconditional\c_tabl_auto_align_mode     % reset later
\newconditional\c_tabl_auto_align_mode_new % reset later

\def\tabl_tabulate_hook_g % partly expanded
  {\ifconditional\c_tabl_auto_align_mode
     \signalcharacteralign\c_tabl_tabulate_column{\c_tabl_tabulate_noflines+\plusone}%
     \typo_charalign_adapt_font
   \fi}

\def\tabl_tabulate_hook_G % partly expanded
  {\ifconditional\c_tabl_auto_align_mode_new
     \typo_charalign_adapt_font
     \attribute\aligncharacterattribute\the\attribute\aligncharacterattribute\relax
   \else
     \attribute\aligncharacterattribute\attributeunsetvalue
   \fi}

\def\tabl_tabulate_set_align#1%
  {\global\c_tabl_auto_align_mode\conditionaltrue
   \setcharacteralign\c_tabl_tabulate_columns{#1}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_align_new#1%
  {\global\c_tabl_auto_align_mode_new\conditionaltrue
   \ifempty{#1}\else\setalignmentcharacter{#1}\fi% todo: check for number or char or ... in lua
   \tabl_tabulate_set_preamble}

% end of character align plugin

\def\tabl_tabulate_set_before#1%
  {\t_tabl_tabulate_before{#1}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_after#1%
  {\t_tabl_tabulate_after{#1}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_font#1%
  {\t_tabl_tabulate_font{#1}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_pickup_width
  {\doifelsenextparenthesis\tabl_tabulate_set_width_indeed\tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_width
  {\c_tabl_tabulate_pwidth_set\conditionalfalse
   \c_tabl_tabulate_modus\zerocount
   \tabl_tabulate_pickup_width}

\def\tabl_tabulate_set_alignment#1%
  {\edef\m_tabl_tabulate_alignment{#1}%
   \spac_align_use_later\m_tabl_tabulate_alignment
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_paragraph
  {\doifelsenextparenthesis
     {\c_tabl_tabulate_modus\plusone
      \c_tabl_tabulate_pwidth_set\conditionaltrue
      \tabl_tabulate_pickup_width}
     {\c_tabl_tabulate_modus\plustwo
      \c_tabl_tabulate_pwidth_set\conditionalfalse
      \tabl_tabulate_set_preamble}}

% \startbuffer
%   \toplinebox{\framed[width=3cm,height=2cm]{tufte}}
% \stopbuffer
% \starttabulate[|p(fixed)|p|]
%   \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR}
% \stoptabulate
% \starttabulate[|p(fit)|p|]
%   \dorecurse{100}{\NC \getbuffer \NC test \par test \par \NC \NR}
% \stoptabulate

% \starttabulate[|w(top,3cm)|w(top,3cm)|]
% \NC test \NC test \par test \NC \NR
% \NC test \NC test \par test \NC \NR
% \stoptabulate
%
% \starttabulate[|w(top,packed,3cm)|w(top,packed,3cm)|]
% \NC test \NC test \par test \NC \NR
% \NC test \NC test \par test \NC \NR
% \stoptabulate
%
% \starttabulate[interlinespace=no,format={|w(bottom,3cm)|w(bottom,3cm)|}]
% \NC test \NC test \par test \NC \NR
% \NC test \NC test \par test \NC \NR
% \stoptabulate
%
% \starttabulate[format={|w(3cm)|w(3cm)|}]
% \NC \vtop{\strut test} \NC \vtop{\strut test\par \strut test} \NC \NR
% \NC \vtop{\strut test} \NC \vtop{\strut test\par \strut test} \NC \NR
% \stoptabulate
%
% \starttabulate[interlinespace=no,format={|w(3cm)|w(3cm)|}]
% \NC \vtop{\strut test} \NC \vtop{\strut test\par \strut test} \NC \NR
% \NC \vtop{\strut test} \NC \vtop{\strut test\par \strut test} \NC \NR
% \stoptabulate
%
% \starttabulate[interlinespace=no,format={|w(3cm)|w(3cm)|}]
% \NC \vbox{\strut test} \NC \vbox{\strut test\par \strut test} \NC \NR
% \NC \vbox{\strut test} \NC \vbox{\strut test\par \strut test} \NC \NR
% \stoptabulate
%
% \starttabulate[interlinespace=no,format={|w(3cm)|w(3cm)|}]
% \NC \vtop{\strut test} \NC \vbox{\strut test\par \strut test} \NC \NR
% \NC \vbox{\strut test} \NC \vtop{\strut test\par \strut test} \NC \NR
% \stoptabulate

\installcorenamespace{tabulatewidth}

\defcsname\??tabulatewidth\v!fit\endcsname
  {\c_tabl_tabulate_modus\plusthree}

\defcsname\??tabulatewidth\v!fixed\endcsname
  {\c_tabl_tabulate_modus\plusthree
   \c_tabl_tabulate_nopbreak\conditionaltrue}

\defcsname\??tabulatewidth\v!packed\endcsname
  {\c_tabl_tabulate_no_interline_space\conditionaltrue}

\defcsname\??tabulatewidth\v!auto\endcsname
  {\c_tabl_tabulate_modus\plusthree\c_tabl_tabulate_reshape\conditionaltrue}

\lettonothing\tabl_tabulate_hook_box
\lettonothing\tabl_tabulate_hook_box_begin
\lettonothing\tabl_tabulate_hook_box_end

\defcsname\??tabulatewidth\v!top\endcsname
  {\def\tabl_tabulate_hook_box_begin{\vtop\bgroup\begstrut}%
   \def\tabl_tabulate_hook_box_end  {\endstrut\egroup}}

\defcsname\??tabulatewidth\v!bottom\endcsname
  {\def\tabl_tabulate_hook_box_begin{\vbox\bgroup\begstrut}%
   \def\tabl_tabulate_hook_box_end  {\endstrut\egroup}}

\def\tabl_tabulate_set_width_step#1%
  {\ifcsname\??tabulatewidth#1\endcsname
     \lastnamedcs
   \else
     \d_tabl_tabulate_width#1\relax
   \fi}

\def\tabl_tabulate_set_width_indeed(#1)%
  {\rawprocesscommacommand[#1]\tabl_tabulate_set_width_step
   \ifconditional\c_tabl_tabulate_pwidth_set
     \global\advanceby\d_tabl_tabulate_width_p\d_tabl_tabulate_width % accumulated parwidth
   \fi
   \tabl_tabulate_set_preamble}

% done

\def\tabl_tabulate_set_raggedright {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedright \fi}
\def\tabl_tabulate_set_raggedcenter{\ifnum\c_tabl_tabulate_type=\plusone \else\raggedcenter\fi}
\def\tabl_tabulate_set_raggedleft  {\ifnum\c_tabl_tabulate_type=\plusone \else\raggedleft  \fi}
\def\tabl_tabulate_set_notragged   {\ifnum\c_tabl_tabulate_type=\plusone \else\notragged   \fi}
\def\tabl_tabulate_set_hss         {\ifnum\c_tabl_tabulate_type=\plusone \else\hss         \fi} % never change this to a fill

\def\tabl_tabulate_bskip_raggedright {\tabl_tabulate_bskip\tabl_tabulate_set_raggedright }
\def\tabl_tabulate_bskip_raggedleft  {\tabl_tabulate_bskip\tabl_tabulate_set_raggedleft  }
\def\tabl_tabulate_bskip_raggedcenter{\tabl_tabulate_bskip\tabl_tabulate_set_raggedcenter}

\def\tabl_tabulate_set_width_normal
  {\ifcase\c_tabl_tabulate_align\relax
     \tabl_tabulate_set_preamble_step\empty                \tabl_tabulate_set_hss \or
     \tabl_tabulate_set_preamble_step\empty                \tabl_tabulate_set_hss \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\empty                 \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_set_hss\tabl_tabulate_set_hss \fi}

\def\tabl_tabulate_set_width_fixed
  {\ifcase\c_tabl_tabulate_align\relax
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip             \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft  \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi}

\def\tabl_tabulate_set_width_auto
  {\global\advanceby\c_tabl_tabulate_nofauto\plusone
   \ifcase\c_tabl_tabulate_align\relax
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip             \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedright \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedleft  \tabl_tabulate_eskip \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bskip_raggedcenter\tabl_tabulate_eskip \fi}

\def\tabl_tabulate_set_width_simple
  {\tabl_tabulate_set_preamble_step\tabl_tabulate_xbskip\tabl_tabulate_xeskip}

\aliased\let\tabl_tabulate_set_width_fixed_split\tabl_tabulate_set_width_fixed
\aliased\let\tabl_tabulate_set_width_auto_split \tabl_tabulate_set_width_auto

% \def\tabl_tabulate_set_color_span#1#2%
%   {\xdef\m_tabl_tabulate_color{#2}%
%    \global\c_tabl_tabulate_colorspan\if#1L\plusone\orelse\if#1M\plustwo\orelse\if#1R\plusthree\else\zerocount\fi\relax
%    \tabl_tabulate_set_preamble}

\installcorenamespace{tabulatecolorspec}

\defcsname\??tabulatecolorspec C\endcsname#1{\xdef\m_tabl_tabulate_color     {#1}\global\c_tabl_tabulate_colorspan\zerocount}
\defcsname\??tabulatecolorspec L\endcsname#1{\xdef\m_tabl_tabulate_color     {#1}\global\c_tabl_tabulate_colorspan\plusone  }
\defcsname\??tabulatecolorspec M\endcsname#1{\xdef\m_tabl_tabulate_color     {#1}\global\c_tabl_tabulate_colorspan\plustwo  }
\defcsname\??tabulatecolorspec R\endcsname#1{\xdef\m_tabl_tabulate_color     {#1}\global\c_tabl_tabulate_colorspan\plusthree}
\defcsname\??tabulatecolorspec T\endcsname#1{\xdef\m_tabl_tabulate_text_color{#1}}

\def\tabl_tabulate_set_color_span#1#2%
  {\csname\??tabulatecolorspec#1\endcsname{#2}%
   \tabl_tabulate_set_preamble}

\def\tabl_tabulate_set_vrule_command#1%
  {\doifelsenumber{#1}
     {\global\d_tabl_tabulate_vrulethickness#1\d_tabl_tabulate_vrulethickness_default}
     {\xdef\m_tabl_tabulate_vrule_color{#1}}}

\permanent\protected\def\tabl_tabulate_set_entry#1#2% rulespec template
  {\c_tabl_tabulate_align\v_tabl_tabulate_align
   \c_tabl_tabulate_modus\zerocount
   \c_tabl_tabulate_pwidth_set\conditionalfalse
   \c_tabl_tabulate_reshape\conditionalfalse
   %c_tabl_pre_is_set\conditionalfalse
   \c_tabl_post_is_set\conditionalfalse
   \t_tabl_tabulate_before\emptytoks
   \t_tabl_tabulate_after\emptytoks
   \t_tabl_tabulate_bmath\emptytoks
   \t_tabl_tabulate_emath\emptytoks
   \t_tabl_tabulate_font\emptytoks
   \t_tabl_tabulate_settings\emptytoks
   \glettonothing\m_tabl_tabulate_alignment
   \glettonothing\m_tabl_tabulate_color
   \glettonothing\m_tabl_tabulate_text_color
   \glettonothing\m_tabl_tabulate_vrule_color
   \glettonothing\tabl_tabulate_hook_box
   \global\c_tabl_tabulate_colorspan\zerocount
   \global\c_tabl_auto_align_mode\conditionalfalse
   \global\c_tabl_auto_align_mode_new\conditionalfalse
   \resetalignmentcharacter
 % \attribute\aligncharacterattribute\attributeunsetvalue
   \global\advanceby\c_tabl_tabulate_columns\plusone
   \letcsname\??tabulatesetup\the\c_tabl_tabulate_columns\endcsname\donothing % here ?
   \ifempty{#1}%
     \global\d_tabl_tabulate_vrulethickness\zeropoint
   \else
     \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default
     % the lmtx raw processor handles {} like the normal one so we need to prune
     \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command
   \fi
   \tabl_tabulate_set_preamble#2\relax\relax % permits i without n
   \ifcase\c_tabl_tabulate_modus\relax
     \tabl_tabulate_set_width_normal
   \or % fixed width
     \tabl_tabulate_set_width_fixed
   \or % auto width
     \tabl_tabulate_set_width_auto
   \or % simple
     \tabl_tabulate_set_width_simple
   \or % fixed width split paragraph
     \tabl_tabulate_set_width_fixed_split
   \or % auto width split paragraph
     \tabl_tabulate_set_width_auto_split
   \fi}

\permanent\protected\def\tabl_tabulate_set_last_entry#1% rulespec
  {\glettonothing\m_tabl_tabulate_color
   \glettonothing\m_tabl_tabulate_vrule_color
   \ifempty{#1}%
     \global\d_tabl_tabulate_vrulethickness\zeropoint
   \else
     \global\d_tabl_tabulate_vrulethickness\d_tabl_tabulate_vrulethickness_default
     \rawprocesscommalist[#1]\tabl_tabulate_set_vrule_command
   \fi
   \etoksapp\t_tabl_tabulate_preamble{%
     \tabl_tabulate_check_local_vrule_thickness\constantdimenargument\d_tabl_tabulate_vrulethickness
     \tabl_tabulate_check_local_vrule_color\constantemptyargument\m_tabl_tabulate_vrule_color
     \tabl_tabulate_column_vrule_inject}}

\aliased\let\settabulateentry    \tabl_tabulate_set_entry      % used at the lua end
\aliased\let\settabulatelastentry\tabl_tabulate_set_last_entry % used at the lua end

\newconditional\c_tabl_tabulate_balanced_split

\settrue\c_tabl_tabulate_balanced_split % default per 2025-11-01

\def\tabl_tabulate_normalize_splitline
  {\ifconditional\c_tabl_tabulate_balanced_split
     \boxyoffset\b_tabl_tabulate-\strutdp
     \ht\b_tabl_tabulate\strutht
     \dp\b_tabl_tabulate\strutdp
   \orelse\ifcase\c_tabl_tabulate_splitlinemode
     % nothing
   \or
     \ht\b_tabl_tabulate\strutht
     \dp\b_tabl_tabulate\strutdp
   \or
     \ifdim\ht\b_tabl_tabulate<\strutht
       \ht\b_tabl_tabulate\strutht
     \fi
     \ifdim\dp\b_tabl_tabulate<\strutdp
       \dp\b_tabl_tabulate\strutdp
     \fi
   \fi}

\def\tabl_tabulate_whitespace
  {\ifdim\d_tabl_tabulate_splitoff_betweenskip>\zeropoint
     \ifconditional\c_tabl_tabulate_balanced_split
       \enablealignskips
       \noalign \s!attr \alignskipattribute\plusone{}% becomes a vskip via callback
     \else
       \vskip\d_tabl_tabulate_splitoff_betweenskip
     \fi
   \fi
   \global\d_tabl_tabulate_splitoff_betweenskip\zeropoint}

\def\tabl_tabulate_check_whitespace
  {\setbox\scratchbox\vpack
     {\splitdiscards
      \unskip
      \ifdim\lastskip>\d_tabl_tabulate_splitoff_betweenskip
        \global\d_tabl_tabulate_splitoff_betweenskip\lastskip
      \fi}}

% see bruce's test file for variant that is template driven, could be an option
% to a tabulate

\installtexdirective
  {tabulate.linenumbers}
  {\def\tabl_tabulate_check_linenumbers{\page_postprocessors_linenumbers_deepbox\b_tabl_tabulate}}
  {\let\tabl_tabulate_check_linenumbers\relax}

\let\tabl_tabulate_check_linenumbers\relax

\def\tabl_tabulate_splitoff_box
  {\dontcomplain
   \ifconditional\c_tabl_tabulate_balanced_split
     \setbox\b_tabl_tabulate\vbalancedbox\b_tabl_tabulate_current\c_tabl_tabulate_column
     \ifdim\d_tabl_tabulate_splitoff_betweenskip<\zeropoint
        % whitespace next to content
     \orelse\ifgluelineinbox\b_tabl_tabulate
        \global\d_tabl_tabulate_splitoff_betweenskip \lineheight % always the same
     \else
        \global\d_tabl_tabulate_splitoff_betweenskip-\lineheight % blocks
     \fi
   \else
     \setbox\b_tabl_tabulate\vsplit\b_tabl_tabulate_current\c_tabl_tabulate_column upto \lineheight % % % global ? % % %
     \ifconditional\c_tabl_tabulate_splitoff_whitespace
       \tabl_tabulate_check_whitespace
     \fi
   \fi
   \tabl_tabulate_color_repeat % needs to end up in a cell
 % \setbox\b_tabl_tabulate\hpack alignsplit to \wd\b_tabl_tabulate
   \setbox\b_tabl_tabulate\hpack to \wd\b_tabl_tabulate
     {\hss
      \tabl_tabulate_hook_yes{\box\b_tabl_tabulate}%
      \hss}%
   \tabl_tabulate_normalize_splitline
   \tabl_tabulate_check_linenumbers
   \box\b_tabl_tabulate}

\protected\def\tabl_tabulate_hook_nop
  {}

\let\tabl_tabulate_hook\tabl_tabulate_hook_nop

\def\tabl_tabulate_hook_yes{\begincsname\??tabulatehook\the\c_tabl_tabulate_column\endcsname}

\newinteger\c_tabl_tabulate_height_p_max_lines

\def\tabl_tabulate_pheight_reset
  {\global\c_tabl_tabulate_plines_min\plusone
   \iftrue
     \global\c_tabl_tabulate_plines_max\c_tabl_tabulate_height_p_max_lines
   \orelse\ifdim\d_tabl_tabulate_height_p_max>\zeropoint
     \getnoflines\d_tabl_tabulate_height_p_max
     \global\c_tabl_tabulate_plines_max\noflines
   \else
     \global\c_tabl_tabulate_plines_max\zerocount
   \fi
   \global\d_tabl_tabulate_height_p_max\zeropoint
   \global\c_tabl_tabulate_height_p_max_lines\zerocount}

% \def\tabl_tabulate_pheight_set
%   {\scratchdimen\ht\b_tabl_tabulate_current\c_tabl_tabulate_column\relax
%    \ifdim\scratchdimen>\d_tabl_tabulate_height_p_max
%      \global\d_tabl_tabulate_height_p_max\scratchdimen
%    \fi
%    \scratchcounter\noflinesinbox\b_tabl_tabulate_current\c_tabl_tabulate_column\relax
%    \ifnum\scratchcounter>\c_tabl_tabulate_height_p_max_lines
%      \global\c_tabl_tabulate_height_p_max_lines\scratchcounter
%    \fi}

%D \starttyping
%D \starttabulate[|p|p|]
%D \NC \showboxes \samplefile{ward}\blank\samplefile{knuth}\blank\samplefile{tufte}
%D \NC \showboxes \samplefile{ward}\blank\samplefile{tufte}\blank\samplefile{knuth}
%D \NC \NR
%D \NC \showboxes \dorecurse{6}{\samplefile{ward}\par}
%D \NC \showboxes \dorecurse{4}{\samplefile{tufte}\par}
%D \NC \NR
%D \stoptabulate
%D \stoptyping

\newdimension\d_tabl_tabulate_spacing_wd

\installtextracker
  {tabulate.spacing}
  {\d_tabl_tabulate_spacing_wd\emwidth}
  {\d_tabl_tabulate_spacing_wd\zeropoint}

\def\tabl_tabulate_pheight_set
  {\scratchdimen\ht\b_tabl_tabulate_current\c_tabl_tabulate_column\relax
   \ifdim\scratchdimen>\d_tabl_tabulate_height_p_max
     \global\d_tabl_tabulate_height_p_max\scratchdimen
   \fi
   \ifconditional\c_tabl_tabulate_balanced_split
     \gluetolinesinbox\b_tabl_tabulate_current\c_tabl_tabulate_column
        \d_tabl_tabulate_spacing_wd \strutht \strutdp
     \balancevsize     \lineheight
     \balancetolerance \plustenthousand
     \balancetopskip   \strutht
     \balancebottomskip\strutdp
     \global\setbox\b_tabl_tabulate_current\c_tabl_tabulate_column
       \vbalance\b_tabl_tabulate_current\c_tabl_tabulate_column
     \relax
   \fi
   \scratchcounter\noflinesinbox\b_tabl_tabulate_current\c_tabl_tabulate_column\relax
   \ifnum\scratchcounter>\c_tabl_tabulate_height_p_max_lines
     \global\c_tabl_tabulate_height_p_max_lines\scratchcounter
   \fi}

% \def\tabl_tabulate_pbreak_inject
%   {\ifconditional\c_tabl_tabulate_handlepbreak
%      \ifconditional\c_tabl_tabulate_nopbreak
%        \tabl_tabulate_nobreak_inject
%      \orelse\ifnum\c_tabl_tabulate_plines_max>\plusone
%        \ifnum\c_tabl_tabulate_plines_min=\plusone
%          \tabl_tabulate_nobreak_inject
%        \fi
%        \global\advanceby\c_tabl_tabulate_plines_min\plusone
%        \ifnum\c_tabl_tabulate_plines_min=\c_tabl_tabulate_plines_max\relax
%          \tabl_tabulate_nobreak_inject
%        \fi
%      \fi
%    \fi}

\def\tabl_tabulate_pbreak_inject
  {\ifconditional\c_tabl_tabulate_handlepbreak
     \ifconditional\c_tabl_tabulate_nopbreak
       \ifnum\c_tabl_tabulate_plines_max=\plusone
         \tabl_tabulate_break_no
       \else
         \tabl_tabulate_break_allow
       \fi
     \orelse\ifnum\c_tabl_tabulate_plines_max>\plusone
       \ifnum\c_tabl_tabulate_plines_min=\plusone
         \directvpenalty\c_tabl_club_penalty
       \fi
       \global\advanceby\c_tabl_tabulate_plines_min\plusone
       \ifnum\c_tabl_tabulate_plines_min=\c_tabl_tabulate_plines_max\relax
         \directvpenalty\c_tabl_widow_penalty
       \fi
     \fi
   \fi}

\def\tabl_tabulate_pbreak_check
  {\noalign\bgroup
     \tabl_tabulate_pbreak_inject
     \ifconditional\c_tabl_tabulate_balanced_split
       \tabl_tabulate_whitespace
     \orelse\ifconditional\c_tabl_tabulate_splitoff_whitespace
       \tabl_tabulate_whitespace
     \fi
   \egroup}

%D \startbuffer
%D \starttabulate[|c|p|p|]
%D \NC \bf Alpha \NC \bf Beta        \NC \bf Gamma          \NC\NR
%D \NC 1         \NC right indeed    \NC definitely wrong   \NC\NR
%D \NC 2         \NC \thinrules[n=3] \NC \thinrules[n=3]    \NC\NR
%D \NC 3         \NC oh yes          \NC simply no          \NC\NR
%D \NC 4         \NC very true       \NC as false as can be \NC\NR
%D \NC 5         \NC \thinrules[n=5] \NC \thinrules[n=5]    \NC\NR
%D \NC 6         \NC \thinrules[n=3] \NC \thinrules[n=4]    \NC\NR
%D \stoptabulate
%D \stopbuffer
%D
%D \typebuffer {\tracetabulatetrue\getbuffer}
%D
%D \startbuffer
%D \starttabulate[|c|p|p|]
%D \NC \bf Alpha \NC \bf Beta        \NC \bf Gamma          \NC\NR
%D \NC 1         \NC right indeed    \NC definitely wrong   \NC\NR
%D \NC 2         \NC oh yes          \NC simply no          \NC\NR
%D \NC 3         \NC very true       \NC as false as can be \NC\NR
%D \NC 4         \NC the whole truth \NC but the truth      \NC\NR
%D \stoptabulate
%D \stopbuffer
%D
%D \typebuffer {\tracetabulatetrue\getbuffer}

%D Because we want to be compatible we use an indirect way to implement the
%D definers. The next examples demonstrate the difference:
%D
%D \starttyping
%D \definetabulate[test][|l|c|r|]
%D \definetabulate[test][two][|r|c|l|]
%D
%D \definetabulation[more][format={|l|c|r|}]
%D \definetabulation[more:two][format={|r|c|l|}]
%D
%D \starttest
%D \NC t \NC t \NC t \NC \NR
%D \NC te \NC te \NC te \NC \NR
%D \NC tes \NC tes \NC tes \NC \NR
%D \NC test \NC test \NC test \NC \NR
%D \stoptest
%D
%D \starttest[two]
%D \NC t \NC t \NC t \NC \NR
%D \NC te \NC te \NC te \NC \NR
%D \NC tes \NC tes \NC tes \NC \NR
%D \NC test \NC test \NC test \NC \NR
%D \stoptest
%D \startmore
%D \NC t \NC t \NC t \NC \NR
%D \NC te \NC te \NC te \NC \NR
%D \NC tes \NC tes \NC tes \NC \NR
%D \NC test \NC test \NC test \NC \NR
%D \stopmore
%D
%D \startmore[two]
%D \NC t \NC t \NC t \NC \NR
%D \NC te \NC te \NC te \NC \NR
%D \NC tes \NC tes \NC tes \NC \NR
%D \NC test \NC test \NC test \NC \NR
%D \stopmore
%D \stoptyping

\installcorenamespace {tabulation}

\installcommandhandler \??tabulation {tabulation} \??tabulation

\setuptabulation
  [\c!unit=1em,
   EQ={:},
   \c!format={|l|p|},
   \c!frame=\v!off,
  %\c!bodyfont=,
   \c!rule=\v!normal,
  %\c!rulecolor=,
   \c!rulethickness=\linewidth,
  %\c!inner=,
   \c!before=\blank,
   \c!after=\blank,
   \c!distance={\v!depth,\v!medium},
   \c!align=\v!normal,
   \c!margin=\!!zeropoint,
   \c!split=\v!auto,
   \c!header=\v!yes,
   \c!dashstep=.1\emwidth,
  %\c!title=,
   \c!indenting=\v!no]

\permanent\tolerant\protected\def\definetabulate[#1]#*[#S#2]#*[#S#3]%
  {\ifarguments
     % ignore
   \or
     % [tag]
     \definetabulation[#1][\c!format={|l|p|},\s!check=]%
   \or
     % [tag] [template]
     \definetabulation[#1][\c!format={#2},\s!check=]%
   \or
     % [tag] [sub] [template]
     \ifcsname\namedtabulationhash{#1}\s!check\endcsname \else
       \definetabulation[#1][\c!format={#3},\s!check=]%
     \fi
     \definetabulation[#1:#2][#1][\c!format={#3},\s!check=]%
   \fi}

\permanent\tolerant\protected\def\setuptabulate[#S#1]#*[#S#2]#*[#S#3]%
  {\ifarguments
     % ignore
   \or
     % [tag]
     \setuptabulation[#1]%
   \or
     % [tag] [settings]
     \setuptabulation[#1][#2]%
   \or
     % [tag] [sub] [settings]
     \setuptabulation[#1:#2][#3]%
   \fi}

\appendtoks
    \enforced\permanent\protected\edefcsname\e!start       \currenttabulation\endcsname{\tabl_start_defined[\currenttabulation]}%
    \enforced\aliased            \letcsname \e!stop        \currenttabulation\endcsname\relax
    \mutable                     \letcsname \??tabulatehead\currenttabulation\endcsname\empty
    \mutable                     \letcsname \??tabulatefoot\currenttabulation\endcsname\empty
\to \everydefinetabulation

\aliased  \let\tabulateparameter\tabulationparameter % will stay for a while
\permanent\def\currenttabulate  {\currenttabulation} % will stay for a while

% Here begins the implementation.

\lettonothing\tabl_tabulate_insert_head
\lettonothing\tabl_tabulate_insert_body
\lettonothing\tabl_tabulate_insert_foot

\def\tabl_tabulate_insert_head_content
  {\noalign{\global\c_tabl_tabulate_someamble\conditionaltrue}%
   \begincsname\??tabulatehead\currenttabulation\endcsname
   \noalign{\global\c_tabl_tabulate_someamble\conditionalfalse}}%

\def\tabl_tabulate_insert_foot_content
  {\noalign{\global\c_tabl_tabulate_someamble\conditionaltrue}%
   \begincsname\??tabulatefoot\currenttabulation\endcsname
   \noalign{\global\c_tabl_tabulate_someamble\conditionalfalse}}%

\def\tabl_tabulate_check_full_content % - needed, else confusion with \c!header
  {\ifcsname\??tabulatehead\currenttabulation\endcsname
     \ifempty{\lastnamedcs}%
       \lettonothing\tabl_tabulate_insert_head
     \else
       \let\tabl_tabulate_insert_head\tabl_tabulate_insert_head_content
     \fi
   \else
     \lettonothing\tabl_tabulate_insert_head
   \fi
   \ifcsname\??tabulatefoot\currenttabulation\endcsname
     \ifempty{\lastnamedcs}%
       \lettonothing\tabl_tabulate_insert_foot
     \else
       \let\tabl_tabulate_insert_foot\tabl_tabulate_insert_foot_content
     \fi
   \else
     \lettonothing\tabl_tabulate_insert_foot
   \fi}

\def\tabl_tabulate_insert_content
  {\tabl_tabulate_insert_head
   \ifcase\c_tabl_tabulate_repeathead \else
     \noalign{\penalty\zerocount}% added 7/5/2014 WS mail
   \fi
   \tabl_tabulate_insert_body
   \tabl_tabulate_insert_foot
   \tabl_tabulate_remove_funny_line}

\def\tabl_tabulate_remove_funny_line
  {\ifhmode
    %\ifinalignment % needs testing
       \strut\crcr
       \noalign{\kern-\lineheight}%
    %\fi
   \fi}

% todo: make footer synonym to tail

\permanent\protected\defcsname\e!start\v!tabulatehead\endcsname{\doifelsenextoptionalcs\tabl_tabulate_start_head_yes\tabl_tabulate_start_head_nop}
\permanent\protected\defcsname\e!start\v!tabulatetail\endcsname{\doifelsenextoptionalcs\tabl_tabulate_start_foot_yes\tabl_tabulate_start_foot_nop}

\lettonothing\m_tabl_tabulate_data

\def\tabl_tabulate_start_head_yes[#1]%
  {\processcontent{\e!stop\v!tabulatehead}\m_tabl_tabulate_data{\letcsname\??tabulatehead#1\endcsname\m_tabl_tabulate_data}}

\def\tabl_tabulate_start_foot_yes[#1]%
  {\processcontent{\e!stop\v!tabulatetail}\m_tabl_tabulate_data{\letcsname\??tabulatefoot#1\endcsname\m_tabl_tabulate_data}}

% \def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[\v!tabulate]}
% \def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[\v!tabulate]}

\def\tabl_tabulate_start_head_nop{\tabl_tabulate_start_head_yes[]}
\def\tabl_tabulate_start_foot_nop{\tabl_tabulate_start_foot_yes[]}

\protected\def\tabl_start_defined[#1]%
  {\bgroup
   \cdef\currenttabulationparent{#1}%
   \let\currenttabulation\currenttabulationparent
   \ifcstok{\tabulationparameter\c!format}\v!none
     % this is special case: we need to define the generic english
     % \starttabulate in other interfaces as well
     \lettabulationparameter\c!format\tabl_default_format
     \expandafter\tabl_start_regular
   \else
     \expandafter\tabl_start_defined_indeed
   \fi}

\tolerant\def\tabl_start_defined_indeed[#S#1]#*[#S#2]%
  {\ifarguments\or
     \ifhastok={#1}%
       \setuptabulation[\currenttabulation][#1]%
     \else
       \cdef\currenttabulation{\currenttabulation:#1}%
     \fi
   \else
     \cdef\currenttabulation{\currenttabulation:#1}%
     \setuptabulation[\currenttabulation][#2]%
   \fi
   \tabl_tabulate_start_building}

% \definetabulate[\v!tabulate][|l|p|] % we need to get rid of this one

\def\tabl_default_format{|l|p|} % actually format is always set

\permanent\protected\defcsname\e!start\v!tabulate\endcsname
  {\bgroup % whole thing
   \lettonothing\currenttabulationparent
   \tabl_start_regular}

\tolerant\protected\def\tabl_start_regular[#S#1]#*[#S#2]% [format] | [settings] | [format] [settings] | [settings] [format]
  {\let\currenttabulation\currenttabulationparent
   \ifempty{#1}%
     \ifhaschar={#2}\relax
       \setupcurrenttabulation[#2]%
     \fi
   \orelse\ifhaschar={#1}\relax
     \ifempty{#2}\else
        \settabulationparameter\c!format{#2}%
     \fi
     \setupcurrenttabulation[#1]%
   \else
     \ifempty{#1}\else
       \settabulationparameter\c!format{#1}%
     \fi
     \ifhaschar={#2}\relax
       \setupcurrenttabulation[#2]%
     \fi
   \fi
   \tabl_tabulate_start_building}

\permanent\letcsname\e!stop\v!tabulate    \endcsname\relax
\permanent\letcsname\e!stop\v!tabulatehead\endcsname\relax
\permanent\letcsname\e!stop\v!tabulatetail\endcsname\relax

\permanent\protected\def\tabl_tabulate_start_ignore % todo when we go frozen
  {\em Nested tabulate is not (yet) supported.\relax
   \expandafter\ignoreupto\csname\ifconditional\c_tabl_generic stoptabulate\else\e!stop\v!tabulate\fi\endcsname}

\appendtoks
    \enforced\letcsname\e!start\v!tabulate\endcsname\tabl_tabulate_start_ignore % only the main one
\to \everytabulate

\defcsname\??tabulatesplit\v!yes   \endcsname{\c_tabl_tabulate_split\conditionaltrue}
\defcsname\??tabulatesplit\v!repeat\endcsname{\c_tabl_tabulate_split\conditionaltrue}
\defcsname\??tabulatesplit\v!no    \endcsname{\c_tabl_tabulate_split\conditionalfalse}
\defcsname\??tabulatesplit\v!auto  \endcsname{\ifinsidefloat\ifinsidesplitfloat\else\c_tabl_tabulate_split\conditionalfalse\fi\fi}

% todo: spacing around tabulate when bodyfont is set

% \let\tabl_tabulate_inside_before   \relax
% \let\tabl_tabulate_inside_after    \relax
% \let\tabl_tabulate_inside_inbetween\relax
%
% \def\tabl_tabulate_outside_before
%   {\whitespace
%    \tabulationparameter\c!before}
%
% \def\tabl_tabulate_outside_after
%   {\tabulationparameter\c!after}

% \showboxes
%
% \startcombination
%     {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
%     {\insidefloattrue \starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
% \stopcombination
%
% \startcombination
%     {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {}
%     {\vbox{\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate}} {}
% \stopcombination
%
% \startcombination
%     {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
%     {\starttabulate[|||] \NC test \NC test \NC \NR \stoptabulate} {}
% \stopcombination

\let\tabl_tabulate_inside_after     \relax
\let\tabl_tabulate_outside_after    \relax
\let\tabl_tabulate_inside_inbetween \relax
\let\tabl_tabulate_outside_inbetween\relax

\protected\def\tabl_tabulate_inside_before
  {\ifhmode\par\fi
   \ifhmode
     \ifinsidesplitfloat
       \let\tabl_tabulate_inside_after\relax
     \else
       \vbox\bgroup
       \let\tabl_tabulate_inside_after\egroup
     \fi
   \else
     \let\tabl_tabulate_inside_after\relax
   \fi}

% \protected\def\tabl_tabulate_outside_before
%   {\ifhmode\par\fi
%    \ifhmode
%      \vbox\bgroup
%      \let\tabl_tabulate_outside_after    \egroup
%      \let\tabl_tabulate_outside_inbetween\relax
%    \orelse\ifinner
%      \let\tabl_tabulate_outside_after    \relax
%      \let\tabl_tabulate_outside_inbetween\relax
%    \else
%      \whitespace
%      \tabulationparameter\c!before
%      \relax
%      \let\tabl_tabulate_outside_after    \tabl_tabulate_outside_after_indeed
%      \let\tabl_tabulate_outside_inbetween\tabl_tabulate_outside_inbetween_indeed
%    \fi}

% \def\tabl_tabulate_outside_after_indeed
%   {\tabulationparameter\c!after}

\def\tabl_tabulate_outside_inbetween_indeed
  {\ifempty{\tabulationparameter\c!after}%
     \vskip\strutdp
     \verticalstrut
     \vskip-\struttotal
   \fi}

\def\tabl_tabulate_inside_inbetween % needs checking
  {\ifempty{\tabulationparameter\c!after}%
     \vskip\strutdp
     \verticalstrut
     \vskip-\struttotal
   \fi}

% This supports \c!n where we have to handle before/after a bit differently:

\definerows
  [\v!tabulate]
  [\c!n=\rowsparameter\c!n,
   \c!order=\v!vertical,
   \c!before=\tabulationparameter\c!before,
   \c!after=\tabulationparameter\c!after]

\setuptabulate
  [\c!n=\zerocount]

\let\tabl_tabulate_outside_stoprows\relax

\protected\def\tabl_tabulate_outside_after_yes
  {\stoprows} % before/after handled in rows

\protected\def\tabl_tabulate_outside_after_nop
  {\tabulationparameter\c!after}

\protected\def\tabl_tabulate_outside_before
  {\ifhmode\par\fi
   \ifhmode
     \vbox\bgroup
     \let\tabl_tabulate_outside_after    \egroup
     \let\tabl_tabulate_outside_inbetween\relax
   \orelse\ifinner
     \let\tabl_tabulate_outside_after    \relax
     \let\tabl_tabulate_outside_inbetween\relax
   \else
     \whitespace
     \relax
     \ifcase\tabulateparameter\c!n\relax
       \tabulationparameter\c!before
       \let\tabl_tabulate_outside_after\tabl_tabulate_outside_after_nop % does \c!after
     \else
       \startrows
         [\v!tabulate]
         [\c!n=\tabulateparameter\c!n,%
          \c!before=\tabulateparameter\c!before,
          \c!after=\tabulateparameter\c!after]%
       \let\tabl_tabulate_outside_after\tabl_tabulate_outside_after_yes
     \fi
     \let\tabl_tabulate_outside_inbetween\tabl_tabulate_outside_inbetween_indeed
   \fi}

\def\tabl_tabulate_outside_after_indeed
  {\tabl_tabulate_outside_stoprows % was an undefined, needs checking
   \tabulationparameter\c!after}

% till here

\newinteger\c_tabl_widow_penalty
\newinteger\c_tabl_club_penalty

\protected\def\tabl_tabulate_start_building
  {\ifinsidefloat
     \tabl_tabulate_inside_before
   \else
     \tabl_tabulate_outside_before
   \fi
   \bgroup % settings
   %
   \t_tabl_tabulate_preamble\emptytoks
   \t_tabl_tabulate_dummy   \emptytoks
   %
   \resetcharacteralign
   %
   \edef\p_distance      {\tabulationparameter\c!distance}%
   \edef\p_align         {\tabulationparameter\c!align}%
   \edef\p_line          {\tabulationparameter\c!rule}%
   \edef\p_rulecolor     {\tabulationparameter\c!rulecolor}%
   \edef\p_rulethickness {\tabulationparameter\c!rulethickness}%
   \edef\p_bodyfont      {\tabulationparameter\c!bodyfont}%
   \edef\p_indenting     {\tabulationparameter\c!indenting}%
   \edef\p_blank         {\tabulationparameter\c!blank}%
   \edef\p_dashstep      {\tabulationparameter\c!dashstep}%
   %
   \ifcstok{\tabulationparameter\c!keeptogether}\v!no
     \c_tabl_tabulate_tolerant_break\conditionaltrue
    %\c_tabl_tabulate_handlepbreak\conditionalfalse
   \else
     \c_tabl_tabulate_tolerant_break\conditionalfalse
    %\c_tabl_tabulate_handlepbreak\conditionaltrue
   \fi
   %
   \ifcstok{\tabulationparameter\c!interlinespace}\v!no
     \c_tabl_tabulate_no_interline_space\conditionaltrue
   \else
     \c_tabl_tabulate_no_interline_space\conditionalfalse
   \fi
   %
   \c_tabl_tabulate_split\conditionaltrue
   \begincsname\??tabulatesplit\tabulationparameter\c!split\endcsname
   %
   \let\m_tabl_tabulate_blank_default\p_blank
   %
   \d_tabl_tabulate_unit{\tabulationparameter\c!unit}%
   \d_tabl_tabulate_margin{\tabulationparameter\c!margin}%
   \let\m_tabl_tabulate_vrule_color_default\p_rulecolor
   \let\m_tabl_tabulate_hrule_color_default\p_rulecolor
   \d_tabl_tabulate_vrulethickness_default\p_rulethickness
   \d_tabl_tabulate_hrulethickness_default\p_rulethickness
   \d_tabl_tabulate_hruledashsteps_default\p_dashstep
   \ifempty\p_bodyfont\else
     \switchtobodyfont[\p_bodyfont]%
   \fi
   \postponenotes % new, to be tested / will be configurable
   % otherwise lines are not broken but overlap in funny ways
   \c_tabl_widow_penalty\widowpenalty
   \c_tabl_club_penalty \clubpenalty
   \widowpenalty   \zerocount
   \clubpenalty    \zerocount
   \brokenpenalty  \zerocount
   \widowpenalties \zerocount
   \clubpenalties  \zerocount
   \brokenpenalties\zerocount
   \expand\everytabulate
   \usesetupsparameter\tabulationparameter
   \tabulationparameter\c!inner % use setups now
   \d_tabl_tabulate_indent{\leftskip+\hangindent\ifx\p_indenting\v!yes+\parindent\fi}%
   \global\c_tabl_tabulate_column\zerocount
   \begingroup
   \catcode\hashasciicode\othercatcode
   \ifconditional\c_tabl_generic
     \expandafter\tabl_tabulate_pickup_generic
   \orelse\ifempty\currenttabulationparent
     \expandafter\tabl_tabulate_pickup_interfaced
   \else
     \expandafter\tabl_tabulate_pickup_specific
   \fi}

\protected\def\tabl_tabulate_pickup_generic
   #L\starttabulate
   #R\stoptabulate
   #1%
  {\endgroup
   \def\tabl_tabulate_insert_body{#1}%
   \tabl_tabulate_process}

\lettonothing\tabl_tabulate_pickup

\protected\def\tabl_tabulate_pickup_indeed#1#2%
  {\protected\def\tabl_tabulate_pickup##L#1##R#2##1% indirect needed because otherwise ##L and ##R expand
     {\endgroup
      \def\tabl_tabulate_insert_body{##1}%
      \tabl_tabulate_process}%
   \tabl_tabulate_pickup}

\protected\def\tabl_tabulate_pickup_interfaced
  {\expanded{\tabl_tabulate_pickup_indeed
      \expandafter\noexpand\csname\e!start\v!tabulate\endcsname
      \expandafter\noexpand\csname\e!stop \v!tabulate\endcsname}}

\protected\def\tabl_tabulate_pickup_specific
  {\expanded{\tabl_tabulate_pickup_indeed
      \expandafter\noexpand\csname\e!start\currenttabulationparent\endcsname
      \expandafter\noexpand\csname\e!stop \currenttabulationparent\endcsname}}

\permanent\protected\def\tabulateEQ
  {\ifconditional\c_tabl_tabulate_firstflushed\else
     \dostarttaggedchained\t!ignore\empty\empty\empty
     \dostarttaggednodetail\t!ignore
     \tabulationparameter{EQ}%
     \dostoptagged
     \dostoptagged
   \fi
   \global\c_tabl_tabulate_equal\conditionalfalse}

% The next ones will be token registers

\let\tabulatenormalpos\relax % hooks, todo
\let\tabulateequalpos \relax % hooks, todo

% color columns

\lettonothing\m_tabl_tabulate_color_previous
\lettonothing\m_tabl_tabulate_color
\lettonothing\m_tabl_tabulate_text_color
\lettonothing\m_tabl_tabulate_color_local
\lettonothing\m_tabl_tabulate_vrule_color
\lettonothing\m_tabl_tabulate_vrule_color_local
\lettonothing\m_tabl_tabulate_vrule_color_default % used local
\lettonothing\m_tabl_tabulate_hrule_color_default % used local
\lettonothing\m_tabl_tabulate_blank_default

\appendtoks
    \glettonothing\m_tabl_tabulate_color_previous
    \glettonothing\m_tabl_tabulate_color
    \glettonothing\m_tabl_tabulate_text_color
    \glettonothing\m_tabl_tabulate_color_local
    \glettonothing\m_tabl_tabulate_vrule_color
    \glettonothing\m_tabl_tabulate_vrule_color_local
    \global\d_tabl_tabulate_vrulethickness_local\zeropoint
\to \t_tabl_tabulate_every_row

\protected\def\tabl_tabulate_color_side_right_second
  {\ifempty\m_tabl_tabulate_color_previous \else
     \tabl_tabulate_color_set\m_tabl_tabulate_color_previous
     \glettonothing\m_tabl_tabulate_color_previous
   \fi}

\protected\def\tabl_tabulate_color_side_left_second
  {\ifempty\m_tabl_tabulate_color \else
     \ifcase\c_tabl_tabulate_colorspan
     \or
       \tabl_tabulate_color_set\m_tabl_tabulate_color
     \or
       \tabl_tabulate_color_set\m_tabl_tabulate_color
     \fi
   \fi}

\protected\def\tabl_tabulate_color_side_both_second
  {\ifempty\m_tabl_tabulate_color \else
     \tabl_tabulate_color_set\m_tabl_tabulate_color
     \ifcase\c_tabl_tabulate_colorspan
       %\glettonothing\m_tabl_tabulate_color_previous
     \or
       \glettonothing\m_tabl_tabulate_color_previous
     \or
       \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color
     \or
       \glet\m_tabl_tabulate_color_previous\m_tabl_tabulate_color
     \fi
   \fi}

\let\tabl_tabulate_color_side_right \relax
\let\tabl_tabulate_color_side_left  \relax
\let\tabl_tabulate_color_side_both  \relax

\appendtoks
    \let\tabl_tabulate_color_side_right\tabl_tabulate_color_side_right_second
    \let\tabl_tabulate_color_side_left \tabl_tabulate_color_side_left_second
    \let\tabl_tabulate_color_side_both \tabl_tabulate_color_side_both_second
\to \t_tabl_tabulate_initializers_second

\def\tabl_tabulate_set_color_column#1% overloaded / todo
  {\unskip
   \doifelsefastoptionalcheck{\tabl_tabulate_set_color_column_yes#1}{\tabl_tabulate_set_color_column_nop#1}}

\def\tabl_tabulate_set_color_column_nop
  {\tabl_tabulate_column_normal\zerocount}

\def\tabl_tabulate_set_color_column_yes#1[#2]%
  {\xdef\m_tabl_tabulate_color_local{#2}%
   \tabl_tabulate_column_normal\zerocount#1}

% normal columns:

\def\tabl_tabulate_column_normal#1#2%
  {\unskip
   \aligntab
   \ifconditional\c_tabl_tabulate_equal\tabulateequalpos\else\tabulatenormalpos\fi
   \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn\else
     \tabl_tabulate_column_vrule_setup
   \fi
   \aligntab
   \global\c_tabl_tabulate_kind#1%
   \global\c_tabl_tabulate_type#2%
   \aligntab}

% equal columns

\def\tabl_tabulate_column_equal#1#2%
  {\unskip
   \aligntab
   \tabulateequalpos
   \aligntab
   \global\c_tabl_tabulate_kind#1%
   \global\c_tabl_tabulate_type#2%
   \aligntab}

% ruled columns

\def\tabl_tabulate_column_vruled_preset
  {\glet\m_tabl_tabulate_vrule_color_local\m_tabl_tabulate_vrule_color_default
   \global\d_tabl_tabulate_vrulethickness_local\d_tabl_tabulate_vrulethickness_default}

\def\tabl_tabulate_column_vruled#1#2%
  {\unskip % 0-n
  %\ifnum\c_tabl_tabulate_column=\plusone
  %  \global\c_tabl_tabulate_has_rule_spec_first\plusone
  %\orelse\ifnum\c_tabl_tabulate_column=\c_tabl_tabulate_nofcolumns
  %  \global\c_tabl_tabulate_has_rule_spec_last\plusone
  %\fi
   \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_vrulecolumn
     \global\c_tabl_tabulate_max_vrulecolumn\c_tabl_tabulate_column
   \fi
   \doifelsefastoptionalcheck{\tabl_tabulate_column_vruled_yes#1#2}{\tabl_tabulate_column_vruled_nop#1#2}}

\def\tabl_tabulate_column_vrule_setup
  {\begincsname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname}

\def\tabl_tabulate_column_vruled_nop
  {\gletcsname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname\tabl_tabulate_column_vruled_preset
   \tabl_tabulate_column_normal}

\def\tabl_tabulate_column_vruled_step#1%
  {\doifelsenumber{#1}%
     {\global\d_tabl_tabulate_vrulethickness_local#1\d_tabl_tabulate_vrulethickness_default}
     {\xdef\m_tabl_tabulate_vrule_color_local{#1}}}

\def\tabl_tabulate_column_vruled_yes#1#2[#3]%
  {\gdefcsname\??tabulatevrule\the\c_tabl_tabulate_column\endcsname
     {\tabl_tabulate_column_vruled_preset
      \rawprocesscommalist[#3]\tabl_tabulate_column_vruled_step}%
   \tabl_tabulate_column_normal#1#2}

\def\tabl_tabulate_vrule_reset
  {\ifcase\c_tabl_tabulate_max_vrulecolumn\else
     \tabl_tabulate_vrule_reset_indeed
   \fi}

\def\tabl_tabulate_vrule_reset_indeed
  {\localcontrolledloop\zerocount\c_tabl_tabulate_max_vrulecolumn\plusone % start at 0
     {\gletcsname\??tabulatevrule\the\currentloopiterator\endcsname\undefined}%
   \global\c_tabl_tabulate_max_vrulecolumn\zerocount}

\appendtoks
    \tabl_tabulate_vrule_reset
\to \t_tabl_tabulate_every_after_row

\def\tabl_tabulate_column_vruled_normal
  {\vrule\s!width\d_tabl_tabulate_vrulethickness\relax}

\def\tabl_tabulate_column_vruled_colored
  {\dousecolorparameter\m_tabl_tabulate_vrule_color
   \vrule\s!width\d_tabl_tabulate_vrulethickness\relax}

\protected\def\tabl_tabulate_column_vrule_inject_first
  {\ifcase\d_tabl_tabulate_vrulethickness\else
     \tabl_tabulate_column_vruled_normal % could be a skip instead
   \fi
   \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one

\protected\def\tabl_tabulate_column_vrule_inject_second
  {\ifcase\d_tabl_tabulate_vrulethickness
   \orelse\ifempty\m_tabl_tabulate_vrule_color
     \tabl_tabulate_column_vruled_normal
   \else
     \tabl_tabulate_column_vruled_colored
   \fi
   \global\d_tabl_tabulate_vrulethickness\zeropoint} % nils second one

\let\tabl_tabulate_column_vrule_inject\relax

\appendtoks
    \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \let\tabl_tabulate_column_vrule_inject\tabl_tabulate_column_vrule_inject_second
\to \t_tabl_tabulate_initializers_second

% auto columns

\def\tabl_tabulate_column_inject_auto
  {\tabl_tabulate_column_normal\zerocount\zerocount
   \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_columns\relax
     \expandafter\NR
   \else
     \expandafter\ignorepars % \ignorespaces % interferes with the more tricky hooks
   \fi}

\protected\def\tabl_tabulate_set_quick#1% see \startlegend \startgiven (for the moment still public)
  {\enforced\let#1\tabl_tabulate_column_inject_auto
   \enforced\let\\\tabl_tabulate_column_inject_auto} % brrr, will go

\defcsname\??tabulateseparator\v!blank \endcsname{\s_tabl_tabulate_separator\bigskipamount}
\defcsname\??tabulateseparator\v!depth \endcsname{\s_tabl_tabulate_separator\strutdp}
\defcsname\??tabulateseparator\v!small \endcsname{\def\m_tabl_tabulate_separator_factor{.25}}
\defcsname\??tabulateseparator\v!medium\endcsname{\def\m_tabl_tabulate_separator_factor{.5}}
\defcsname\??tabulateseparator\v!big   \endcsname{}
\defcsname\??tabulateseparator\v!none  \endcsname{\s_tabl_tabulate_separator\zeroskip\let\m_tabl_tabulate_separator_factor\zerocount}
\defcsname\??tabulateseparator\v!grid  \endcsname{\s_tabl_tabulate_separator\zeroskip\let\m_tabl_tabulate_separator_factor\zerocount}

\def\tabl_tabulate_column_rule_separator_step#1%
  {\ifcsname\??tabulateseparator#1\endcsname
     \lastnamedcs
   \else
     \s_tabl_tabulate_separator#1\relax
   \fi}

\def\tabl_tabulate_column_rule_separator_inject % can be sped up (will do when used frequently)
  {\bgroup
   \s_tabl_tabulate_separator\strutdp
   \ifempty\p_distance\else
     \let\m_tabl_tabulate_separator_factor\plusone
     \processcommacommand[\p_distance]\tabl_tabulate_column_rule_separator_step
     \s_tabl_tabulate_separator\m_tabl_tabulate_separator_factor\s_tabl_tabulate_separator
   \fi
   % someamble: footer or header: unfortunately a skip can trigger a page break (weird
   % as we have lots of nobreaks)
 % \ifconditional\c_tabl_tabulate_someamble\kern\else\vskip\fi\s_tabl_tabulate_separator % new
 % \directvspacing{\the\s_tabl_tabulate_separator}% new
   \directvskip\s_tabl_tabulate_separator
   \egroup}

% \starttabulate
% \FL[1,2] % linewidthfactor, dashstepfactor
% \NC test \NC test and test and test and done \NC \NR
% \ML[1,1]
% \NC test \NC test and test and test and done \NC \NR
% \NC test \NC test and test and test and done \NC \NR
% \NC test \NC test and test and test and done \NC \NR
% \LL[1,10]
% \stoptabulate

\lettonothing\m_tabl_tabulate_hrule_color

\def\tabl_tabulate_hrule_preset[#1]%
  {\glet\m_tabl_tabulate_hrule_color\m_tabl_tabulate_hrule_color_default
   \global\d_tabl_tabulate_hrulethickness_local\d_tabl_tabulate_hrulethickness_default
   \global\d_tabl_tabulate_hruledashsteps_local\zeropoint
   \c_tabl_tabulate_step\zerocount
   \ifempty{#1}\else\rawprocesscommalist[#1]\tabl_tabulate_hrule_preset_step\fi}

\def\tabl_tabulate_hrule_preset_step#1%
  {\ifchknum#1\or
     \advanceby\c_tabl_tabulate_step\plusone
     \ifcase\c_tabl_tabulate_step\or
       \global\d_tabl_tabulate_hrulethickness_local#1\d_tabl_tabulate_hrulethickness_default
     \else
       \global\d_tabl_tabulate_hruledashsteps_local#1\d_tabl_tabulate_hruledashsteps_default
     \fi
   \else
     \xdef\m_tabl_tabulate_hrule_color{#1}%
   \fi}

\def\tabl_tabulate_hrule_inject_normal
  {\autorule
     \s!height.5\d_tabl_tabulate_hrulethickness_local
     \s!depth .5\d_tabl_tabulate_hrulethickness_local
     \s!left    \d_tabl_tabulate_indent
     on         \d_tabl_tabulate_hruledashsteps_local
     off        \d_tabl_tabulate_hruledashsteps_local
   \relax}

% \def\tabl_tabulate_hrule_inject_normal .. messes with prevdepth and needs mode
%   {\hrule % running
%      \s!height.5\d_tabl_tabulate_hrulethickness_local
%      \s!depth .5\d_tabl_tabulate_hrulethickness_local
%      \s!left    \d_tabl_tabulate_indent
%      on         \d_tabl_tabulate_hruledashsteps_local
%      off        \d_tabl_tabulate_hruledashsteps_local
%    \relax}

\def\tabl_tabulate_hrule_inject_colored
  {\dousecolorparameter\m_tabl_tabulate_hrule_color
   \tabl_tabulate_hrule_inject_normal}

\protected\def\tabl_tabulate_hrule_inject_first
  {\ifcase\d_tabl_tabulate_hrulethickness_local\else
     \tabl_tabulate_hrule_inject_normal
   \fi}

\protected\def\tabl_tabulate_hrule_inject_second
  {\ifcase\d_tabl_tabulate_hrulethickness_local\else
     \ifempty\m_tabl_tabulate_hrule_color
       \tabl_tabulate_hrule_inject_normal
     \else
       \tabl_tabulate_hrule_inject_colored
     \fi
   \fi}

\let\tabl_tabulate_hrule_inject\relax

\appendtoks
    \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \let\tabl_tabulate_hrule_inject\tabl_tabulate_hrule_inject_second
\to \t_tabl_tabulate_initializers_second

%D Color:

% \starttabulate[||p||]
% \NC test \NC test \NC test \NC \NR
% \NC test \CC[green] \input tufte  \CC[yellow] test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \CC[blue] test \CC[red] test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \CC[gray] test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \CC[blue] test \NC test \NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \NC test \CC[magenta] test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \CC[cyan] \dorecurse{10}{\input ward }\NC test \NC \NR
% \NC test \NC test \NC test \NC \NR
% \NC test \CC[yellow] test \NC test \NC \NR
% \stoptabulate

\protected\def\tabl_tabulate_color_set#1% we could store the attributes at the cost of a lua call
  {\begingroup
   \clf_enablebackgroundalign % was \node_backgrounds_align_initialize
   \glet\tabl_tabulate_color_repeat\tabl_tabulate_color_repeat_second
   \ifnum\c_tabl_tabulate_column>\c_tabl_tabulate_max_colorcolumn
     \global\c_tabl_tabulate_max_colorcolumn\c_tabl_tabulate_column
   \fi
   \xdefcsname\??tabulatecolor\the\c_tabl_tabulate_column\endcsname{#1}%
   \hpack \thealignbackgroundcolorattr{#1}{}% pack ?
   \endgroup}

\def\tabl_tabulate_color_repeat_second % for split off lines
  {\begingroup
   \scratchcounter{\c_tabl_tabulate_column-\plusone}% ugly !
   \ifcsname\??tabulatecolor\the\scratchcounter\endcsname
   % \hbox \thealignbackgroundcolorattr{\csname\??tabulatecolor\the\scratchcounter\endcsname}{}% pack ?
     \hpack \expandafter\thealignbackgroundcolorattr\expandafter{\lastnamedcs}{}% pack ?
   \fi
   \endgroup}

\let\tabl_tabulate_color_repeat\relax

\appendtoks
    \let\tabl_tabulate_color_repeat\relax
\to \everytabulate

\def\tabl_tabulate_color_reset
  {\ifcase\c_tabl_tabulate_max_colorcolumn\else
     \tabl_tabulate_color_reset_indeed
   \fi}

% \def\tabl_tabulate_color_reset_indeed
%   {\dofastloopcs\c_tabl_tabulate_max_colorcolumn\tabl_tabulate_color_reset_step}
%
% \def\tabl_tabulate_color_reset_step % undefined or empty?
%   {\gletcsname\??tabulatecolor\number\fastloopindex\endcsname\undefined}

\def\tabl_tabulate_color_reset_indeed
  {\localcontrolledloop\zerocount\c_tabl_tabulate_max_colorcolumn\plusone % start at 1
     {\gletcsname\??tabulatecolor\the\currentloopiterator\endcsname\undefined}%
   \global\c_tabl_tabulate_max_colorcolumn\zerocount} % why not like vrule?

\appendtoks
    \tabl_tabulate_color_reset
\to \t_tabl_tabulate_every_after_row

% \def\tabl_tabulate_register_par_options_indeed
%   {\iftrialtypesetting \else
%      \registerparoptions
%      \ifinsidefloat
%        % that is, an unbreakable one
%        \glettonothing\tabl_tabulate_register_par_options
%      \else
%        % unsafe in crossing pages, at each b...
%        % \glettonothing\tabl_tabulate_register_par_options
%      \fi
%    \fi}
%
% \appendtoks
%     \glet\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_indeed
% \to \everytabulate

\def\tabl_tabulate_register_par_options_first % maybe track here if needed
  {}

\def\tabl_tabulate_register_par_options_second
  {\registerparoptions
   \ifinsidefloat
     % that is, an unbreakable one
     \glettonothing\tabl_tabulate_register_par_options
   \else
     % unsafe in crossing pages, at each b...
     % \glettonothing\tabl_tabulate_register_par_options
   \fi}

\let\tabl_tabulate_register_par_options\relax

\appendtoks
    \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \let\tabl_tabulate_register_par_options\tabl_tabulate_register_par_options_second
\to \t_tabl_tabulate_initializers_second

\appendtoks
    \tabl_tabulate_register_par_options
\to \t_tabl_tabulate_every_row

\def\tabl_tabulate_flush_indent_indeed
  {\hbox to \d_tabl_tabulate_indent % pack ?
     {% we now have a local hsize, and since we want to
      % register positional info (i.e. real hsizes) we
      % need to reconstitute the original hsize
      \advanceby\hsize\d_tabl_tabulate_indent
      % this is indeed rather messy and took a few hours
      % to dis/uncover
      \expand\t_tabl_tabulate_every_row
      \hss}}

\def\tabl_tabulate_flush_indent
  {\ifzero\c_tabl_tabulate_column
     \tabl_tabulate_flush_indent_indeed
   \fi}

\def\tabl_tabulate_digits{\digits}

%D Beware, we cannot use \type {\protected} on \type {\HL} cum suis, since \TEX's
%D hard coded noalign lookahead fails on it! I mistakenly added this for a while.
%D Well, this is no longer true in \LMTX.

\defcsname\??tabulatealigning\v!normal\endcsname{0}
\defcsname\??tabulatealigning\v!right \endcsname{1}
\defcsname\??tabulatealigning\v!left  \endcsname{2}
\defcsname\??tabulatealigning\v!middle\endcsname{3}

\defcsname\??tabulateheader\v!repeat\endcsname{\plusone}
\defcsname\??tabulateheader\v!text  \endcsname{\plustwo}

\protected\def\tabl_tabulate_bskip_first {\setbox\b_tabl_tabulate\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop}
\protected\def\tabl_tabulate_eskip_first {\par\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes}
\protected\def\tabl_tabulate_xbskip_first{\hpack\bgroup\vbox\bgroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_nop}
\protected\def\tabl_tabulate_xeskip_first{\par\egroup\egroup\glet\tabl_tabulate_hook\tabl_tabulate_hook_yes}

\let\tabl_tabulate_bbskip\relax
\let\tabl_tabulate_eeskip\relax
\let\tabl_tabulate_bskip \relax
\let\tabl_tabulate_eskip \relax
\let\tabl_tabulate_xbskip\relax
\let\tabl_tabulate_xeskip\relax

\appendtoks
   \let\tabl_tabulate_bbskip\relax
  %\let\tabl_tabulate_eeskip\relax % adapted by bskip
   \let\tabl_tabulate_bskip \tabl_tabulate_bskip_first
   \let\tabl_tabulate_eskip \tabl_tabulate_eskip_first
   \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_first
   \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_first
\to \t_tabl_tabulate_initializers_first

\def\tabl_tabulate_baselinecorrection % keep an eye on this one
  {\def\dobaselinecorrection{\vskip{-\prevdepth+\strutdp+\strutdp}}% todo: mkiv
   \baselinecorrection}

% some hack to prevent an allowbreak ... actually we could set up a system then
% that is dealt with atthe lua end in the skip handler: turn penalties with attributes
% values into other penalties that get removed

\installcorenamespace{tabulatenobreak}

\def\tabl_tabulate_break_allow{\directvpenalty\zerocount}
\def\tabl_tabulate_break_maybe{\directvpenalty\zerocount}
\def\tabl_tabulate_break_no   {\directvpenalty\plustenthousand} % ,order:2}}

\let\tabl_tabulate_break_state_set       \relax
\let\tabl_tabulate_break_state_reset     \relax
\let\tabl_tabulate_break_state_allowbreak\tabl_tabulate_break_maybe

% so far

\permanent\protected\def\tabl_tabulate_VL_first{\tabl_tabulate_column_vruled\zerocount\zerocount}
\permanent\protected\def\tabl_tabulate_NC_first{\tabl_tabulate_column_normal\zerocount\zerocount}
\permanent\protected\def\tabl_tabulate_RC_first{\tabl_tabulate_column_normal\zerocount\plusone}
\permanent\protected\def\tabl_tabulate_HC_first{\tabl_tabulate_column_normal\zerocount\plustwo}
\permanent\protected\def\tabl_tabulate_EQ_first{\tabl_tabulate_column_equal \plustwo  \zerocount}
\permanent\protected\def\tabl_tabulate_RQ_first{\tabl_tabulate_column_equal \zerocount\plusone}
\permanent\protected\def\tabl_tabulate_HQ_first{\tabl_tabulate_column_equal \zerocount\plustwo}

\permanent\protected\def\tabl_tabulate_NG_first{\tabl_tabulate_column_normal\zerocount\zerocount}
\permanent\protected\def\tabl_tabulate_NN_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % new, undocumented, test first
\permanent\protected\def\tabl_tabulate_ND_first{\tabl_tabulate_column_normal\zerocount\zerocount\tabl_tabulate_digits} % same, for old times sake

\permanent\protected\def\tabl_tabulate_NR_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_check_penalties} % next row
\permanent\protected\def\tabl_tabulate_NB_first {\tabl_tabulate_NR_common\conditionaltrue \tabl_tabulate_nobreak_inject } % next row no break

\permanent\protected\def\tabl_tabulate_NR_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_check_penalties} % next row
\permanent\protected\def\tabl_tabulate_NB_second{\tabl_tabulate_NR_common\conditionalfalse\tabl_tabulate_nobreak_inject } % next row no break

\permanent\protected\def\tabl_tabulate_CC_first{\global\c_tabl_tabulate_localcolorspan\zerocount\tabl_tabulate_set_color_column\zerocount}
\permanent\protected\def\tabl_tabulate_CL_first{\global\c_tabl_tabulate_localcolorspan\plusone  \tabl_tabulate_set_color_column\zerocount}
\permanent\protected\def\tabl_tabulate_CM_first{\global\c_tabl_tabulate_localcolorspan\plustwo  \tabl_tabulate_set_color_column\zerocount}
\permanent\protected\def\tabl_tabulate_CR_first{\global\c_tabl_tabulate_localcolorspan\plusthree\tabl_tabulate_set_color_column\zerocount}

%D New per 27/12/2022:

% \defineorientation[test][orientation=down,vertical=top]
%
% \definetabulatemove[a][xoffset=40pt]
% \definetabulatemove[b][orientation=test,yoffset=depth]
%
% \startbuffer[b]
% \starttabulate[|c|c|]
% \TM[a] \NC \darkred   cell one   \NC \darkgray cell one   \NC \NR
% \TM[b] \NC \darkgreen cell one   \NC \darkblue cell one   \NC \NR
% \TM[a] \NC \darkred   cell two   \NC \darkgray cell two   \NC \NR
% \TM[b] \NC \darkgreen cell two   \NC \darkblue cell two   \NC \NR
% \TM[a] \NC \darkred   cell three \NC \darkgray cell three \NC \NR
% \TM[b] \NC \darkgreen cell three \NC \darkblue cell three \NC \NR
% \TM[a] \NC \darkred   cell four  \NC \darkgray cell four  \NC \NR
% \TM[b] \NC \darkgreen cell four  \NC \darkblue cell four  \NC \NR
% \stoptabulate
% \stopbuffer
%
% \start \showmakeup[line] \showstruts \ruledvbox{\getbuffer[b]} \stop
% \start                   \showstruts \ruledvbox{\getbuffer[b]} \stop
% \start                               \ruledvbox{\getbuffer[b]} \stop
%
% \startbuffer[b]
% \starttabulate[|p|p|]
% \TM[a] \NC \darkred   \samplefile{tufte} \NC \darkgray \samplefile{ward} \NC \NR
%        \NC \darkgreen \samplefile{tufte} \NC \darkblue \samplefile{ward} \NC \NR
% \TM[a] \NC \darkred   \samplefile{tufte} \NC \darkgray \samplefile{ward} \NC \NR
%        \NC \darkgreen \samplefile{tufte} \NC \darkblue \samplefile{ward} \NC \NR
% \stoptabulate
% \stopbuffer
%
% \start \showmakeup[line] \showstruts \getbuffer[b] \stop

\installcorenamespace{tabulatemove}

\installcommandhandler \??tabulatemove {tabulatemove} \??tabulatemove

\setuptabulatemove
  [\c!xoffset=\zeropoint,
   \c!yoffset=\zeropoint,
   \c!orientation=]

\noaligned\permanent\tolerant\protected\def\tabl_tabulate_TM_yes[#S#1]#*[#S#2]%
  {\beginlocalcontrol
   \ifhastok={#1}%
     \setupcurrenttabulatemove[#1]%
   \else
     \cdef\currenttabulatemove{#1}%
     \setupcurrenttabulatemove[#2]%
   \fi
   \edef\p_orientation{\theorientation{\tabulatemoveparameter\c!orientation}}%
   \edef\p_xoffset    {\tabulatemoveparameter\c!xoffset}%
   \edef\p_yoffset    {\tabulatemoveparameter\c!yoffset}%
   \scratchyoffset
     \ifx\p_yoffset\v!depth
       -\strutdp
     \orelse\ifx\p_yoffset\v!height
       -\strutht
     \else
       \p_yoffset
     \fi
   \relax
   \scratchxoffset\p_xoffset\relax
   \xdef\tabl_tabulate_tm
     {\ifzeropt\scratchxoffset\else\s!xmove  \the\scratchxoffset\fi % or move
      \ifzeropt\scratchyoffset\else\s!ymove  \the\scratchyoffset\fi % or move
      \ifzero  \p_orientation \else\s!orientation\p_orientation \fi
     }%
   \endlocalcontrol
   \noalign\tabl_tabulate_tm{}}

\noaligned\permanent\tolerant\protected\def\tabl_tabulate_TM_nop[#S#1]#*[#S#2]%
  {}

\lettonothing\tabl_tabulate_tm % new 27/12/2022

%D Sort of special:
%D
%D \startbuffer
%D \startitemize[n]
%D \starttabulate[|||||]
%D \NC p \NC \itemtag \NC q \NC r \NC \NR
%D \NC p \NC \itemtag \NC q \NC r \NC \NR
%D \NC p \NC \itemtag \NC q \NC r \NC \NR
%D \NC p \NC \itemtag \NC q \NC r \NC \NR
%D \stoptabulate
%D \stopitemize
%D
%D \startitemize[n]
%D \starttabulate[|||||]
%D \NI b \NC c \NC d \NC \NR
%D \NC a \NI c \NC d \NC \NR
%D \NC a \NC b \NI d \NC \NR
%D \NC a \NC b \NC c \NI \NR
%D \stoptabulate
%D \stopitemize
%D \stopbuffer
%D
%D \typebuffer \getbuffer

\permanent\tolerant\protected\def\tabl_tabulate_NI_first[#1]{\NC\itemtag[#1]\NC}

%D The following shortcut is handy for tables where one needs bold headers:

\permanent\protected\def\tabl_tabulate_BC_first
  {\tabl_tabulate_column_normal\plusone\zerocount
   \let\fontstyle\globalfontstyle
   \bf}

% \permanent\overloaded\protected\def\tabl_tabulate_TC_first
%   {\tabl_tabulate_column_normal\plusone\zerocount
%    \tt}

\appendtoks
    \enforced\let\VL\tabl_tabulate_VL_first
    \enforced\let\NC\tabl_tabulate_NC_first
    \enforced\let\BC\tabl_tabulate_BC_first
%   \enforced\let\TC\tabl_tabulate_TC_first
    \enforced\let\RC\tabl_tabulate_RC_first
    \enforced\let\HC\tabl_tabulate_HC_first
    \enforced\let\EQ\tabl_tabulate_EQ_first
    \enforced\let\RQ\tabl_tabulate_RQ_first
    \enforced\let\HQ\tabl_tabulate_HQ_first
    \enforced\let\NG\tabl_tabulate_NG_first
    \enforced\let\NN\tabl_tabulate_NN_first
    \enforced\let\ND\tabl_tabulate_ND_first
    \enforced\let\NR\tabl_tabulate_NR_first
    \enforced\let\NB\tabl_tabulate_NB_first
    \enforced\let\CC\tabl_tabulate_CC_first
    \enforced\let\CL\tabl_tabulate_CL_first
    \enforced\let\CM\tabl_tabulate_CM_first
    \enforced\let\CR\tabl_tabulate_CR_first
    \enforced\let\NI\tabl_tabulate_NI_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \enforced\let\NR\tabl_tabulate_NR_second
    \enforced\let\NB\tabl_tabulate_NB_second
    \enforced\let\TM\tabl_tabulate_TM_yes
\to \t_tabl_tabulate_initializers_second

\appendtoks
    \enforced\let\SR\NR
    \enforced\let\FR\NR
    \enforced\let\MR\NR
    \enforced\let\LR\NR
    \enforced\let\AR\NR
    \enforced\let\TM\tabl_tabulate_TM_nop
\to \t_tabl_tabulate_initializers_first

% \permanent\protected\def\tabl_tabulate_NR_common#1#2%
%   {\global\advanceby\c_tabl_tabulate_noflines\plusone
%    \global\c_tabl_tabulate_firstflushed\conditionalfalse
%    \global\c_tabl_tabulate_equal\conditionalfalse
%    \global\c_tabl_tabulate_column\zerocount
%    \ifconditional#1\relax
%      \tabl_tabulate_break_state_reset
%    \fi
%    \tabl_tabulate_pheight_reset
%    \unskip\unskip\crcr\tabl_tabulate_flush_collected
%    % can we omit the next one in the first run? probably
%    \noalign{\expand\t_tabl_tabulate_every_after_row#2}}

% test case for ignorepar error
%
% \starttabulatehead
%     \NC A \NC B \NC \NR
% \stoptabulatehead
% \starttabulate[|l|l|]
%     \NC 1 \NC 2 \NC \NR
% \stoptabulate

\permanent\tolerant\protected\def\tabl_tabulate_NR_common#1#2% #. gobbles pars and spaces
  {\global\advanceby\c_tabl_tabulate_noflines\plusone
   \global\c_tabl_tabulate_firstflushed\conditionalfalse
   \global\c_tabl_tabulate_equal\conditionalfalse
   \global\c_tabl_tabulate_column\zerocount
   \ifconditional#1\relax
     \tabl_tabulate_break_state_reset
   \fi
   \tabl_tabulate_pheight_reset
   \unskip\unskip\crcr\tabl_tabulate_flush_collected
   % can we omit the next one in the first run? probably
   % todo: move \ignorepars ourside so no alignment error then
   \noalign{\expand\t_tabl_tabulate_every_after_row#2\ignorepars}}

%D \starttyping
%D \showmakeup[vpenalty]
%D
%D \starttabulate
%D \NC one \NC \samplefile{ward} \NC \NR
%D \NC one \NC \samplefile{ward} \NC \NR
%D \NC one \NC \samplefile{ward} \NC \NR
%D \stoptabulate
%D
%D \starttabulate
%D \NC one \NC ward \NC \NR
%D \NC one \NC ward \NC \NR
%D \NC one \NC ward \NC \NR
%D \stoptabulate
%D \stoptyping

% \def\tabl_tabulate_check_penalties
%   {\ifconditional\c_tabl_tabulate_tolerant_break\else
%      \ifnum\c_tabl_tabulate_totalnoflines=\plusone
%      %  \tabl_tabulate_break_allow
%      \else
%        \ifconditional\c_tabl_tabulate_someamble \ifcase\c_tabl_tabulate_repeathead \else
%          \tabl_tabulate_break_allow
%        \fi \fi
%        \ifnum\c_tabl_tabulate_noflines=\plusone
%          \tabl_tabulate_nobreak_inject
%        \orelse\ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_minusnoflines
%          \ifnum\c_tabl_tabulate_plines_max<\plustwo
%            \tabl_tabulate_nobreak_inject
%          \else
%            \tabl_tabulate_break_allow % needed with pbreak prevention
%          \fi
%        \else
%          \tabl_tabulate_break_state_allowbreak
%        \fi
%      \fi
%    \fi
%    \global\c_tabl_tabulate_firstflushed\conditionalfalse
%    \ifconditional\c_tabl_tabulate_no_interline_space
%      \nointerlineskip
%      \injectzerobaselineskip
%    \fi}

\def\tabl_tabulate_check_penalties
  {\ifconditional\c_tabl_tabulate_tolerant_break\else
     \ifnum\c_tabl_tabulate_totalnoflines=\plusone
     %  \tabl_tabulate_break_allow
     \else
       \ifconditional\c_tabl_tabulate_someamble \ifcase\c_tabl_tabulate_repeathead \else
         \tabl_tabulate_break_allow
       \fi \fi
       \ifnum\c_tabl_tabulate_noflines=\plusone
         \tabl_tabulate_nobreak_inject
       \orelse\ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_minusnoflines
         \ifnum\c_tabl_tabulate_plines_max<\plustwo
           \tabl_tabulate_nobreak_inject
         \else
           \tabl_tabulate_break_allow % needed with pbreak prevention
         \fi
       \else
         \tabl_tabulate_break_state_allowbreak
       \fi
     \fi
   \fi
   \global\c_tabl_tabulate_firstflushed\conditionalfalse
   \ifconditional\c_tabl_tabulate_no_interline_space
     \nointerlineskip
     \injectzerobaselineskip
   \fi}

\protected\def\tabl_tabulate_bbskip_second_split_yes
  {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column
     \ifempty\tabl_tabulate_flush_collected_indeed\else
       \tabl_tabulate_tag_start_cell\dotagtabulatesignal\tabl_tabulate_tag_stop_cell
       \setbox0\hbox
     \fi
  \fi}

\protected\def\tabl_tabulate_eskip_second
  {\par
   \ifconditional\c_tabl_tabulate_no_blank_in_paragraphs
     \removelastskip
   \fi
   \egroup
   \tabl_tabulate_pheight_set
   \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
   \tabl_tabulate_splitoff_box}

\protected\def\tabl_tabulate_bskip_second_split_yes
  {\ifvoid\b_tabl_tabulate_current\c_tabl_tabulate_column
     % first line
     \global\setbox\b_tabl_tabulate_current\c_tabl_tabulate_column\vbox
     \bgroup
     \ifconditional\c_tabl_tabulate_no_blank_in_paragraphs
       \inhibitblank
     \fi
     \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop
     \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi
     % \begstrut % interferes with pre-\pars
     % evt: \appendtoks\begstrut\to\everypar
     \let\tabl_tabulate_eskip\tabl_tabulate_eskip_second
     \expandafter\ignorepars % \ignorespaces
   \else
     % successive lines
     \lettonothing\tabl_tabulate_eskip
    %\dontcomplain
     \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
     \expandafter\tabl_tabulate_splitoff_box
   \fi}

\protected\def\tabl_tabulate_xbskip_second{\tabl_tabulate_bskip}
\protected\def\tabl_tabulate_xeskip_second{\tabl_tabulate_eskip}

% \protected\def\tabl_tabulate_flush_second_indeed
%   {\glettonothing\tabl_tabulate_flush_collected_indeed
%    \global\c_tabl_tabulate_column\zerocount
%    \tabl_tabulate_pbreak_check
%    \global\c_tabl_tabulate_split_done\conditionalfalse % new 27/12/2022
%    \dofastloopcs\c_tabl_tabulate_columns\tabl_tabulate_flush_second_step
%    \ifconditional\c_tabl_tabulate_split_done\else
%      \glet\tabl_tabulate_tm\s!reset % new 27/12/2022
%    \fi
%    \global\c_tabl_tabulate_firstflushed\conditionaltrue}

% \protected\def\tabl_tabulate_flush_second_step
%   {\ifvoid\b_tabl_tabulate_current\fastloopindex
%    \else
%      \gdef\tabl_tabulate_flush_collected_indeed{\expand\t_tabl_tabulate_dummy}%
%      \ifvoid\b_tabl_tabulate_current\fastloopindex \else
%        \global\c_tabl_tabulate_split_done\conditionaltrue % new 27/12/2022
%      \fi
%    \fi}

\newconditional\c_tabl_tabulate_split_done

\protected\def\tabl_tabulate_flush_second_indeed
  {\glettonothing\tabl_tabulate_flush_collected_indeed
   \global\c_tabl_tabulate_column\zerocount
   \tabl_tabulate_pbreak_check
   \global\c_tabl_tabulate_split_done\conditionalfalse % new 27/12/2022
   \localcontrolledloop\plusone\c_tabl_tabulate_columns\plusone{\tabl_tabulate_flush_second_step}%
   \ifconditional\c_tabl_tabulate_split_done\else
     \glet\tabl_tabulate_tm\s!reset % new 27/12/2022
   \fi
   \global\c_tabl_tabulate_firstflushed\conditionaltrue}

% \protected\def\tabl_tabulate_flush_second_step
%   {\ifvoid\b_tabl_tabulate_current\currentloopiterator
%    \else
%      \gdef\tabl_tabulate_flush_collected_indeed{\expand\t_tabl_tabulate_dummy}%
%      \ifvoid\b_tabl_tabulate_current\currentloopiterator \else
%        \global\c_tabl_tabulate_split_done\conditionaltrue % new 27/12/2022
%      \fi
%    \fi}

\protected\def\tabl_tabulate_flush_second_step
  {\iflist\b_tabl_tabulate_current\currentloopiterator\relax % \ifvoid fails for balanced
     \gdef\tabl_tabulate_flush_collected_indeed{\expand\t_tabl_tabulate_dummy}%
     \global\c_tabl_tabulate_split_done\conditionaltrue % new 27/12/2022
   \fi}

\def\tabl_tabulate_flush_second
  {\noalign{\tabl_tabulate_flush_second_indeed}%
   \noalign\tabl_tabulate_tm{\ifx\tabl_tabulate_tm\s!reset\glettonothing\tabl_tabulate_tm\fi}% new 27/12/2022
   \tabl_tabulate_flush_collected_indeed}

\protected\def\tabl_tabulate_bskip_second_split_nop
% {\dbox\bgroup
  {\vtop\bgroup
     \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi
\inhibitblank
     % \begstrut % interferes with pre-\pars
     % evt: \appendtoks\begstrut\to\everypar
     \ignorepars} % \ignorespaces

\protected\def\tabl_tabulate_eskip_second_split_nop % vertical strut added august 2003
  {\par\verticalstrut
   \vskip-\struttotal
   \egroup}

% \let\tabl_tabulate_eskip \relax % adapted by bskip
% \let\tabl_tabulate_eeskip\relax % adapted by bskip

\appendtoks
   \let\tabl_tabulate_xbskip\tabl_tabulate_xbskip_second
   \let\tabl_tabulate_xeskip\tabl_tabulate_xeskip_second
   \ifconditional\c_tabl_tabulate_split
     \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_yes
     \let\tabl_tabulate_bbskip\tabl_tabulate_bbskip_second_split_yes
   \else
     \let\tabl_tabulate_bskip \tabl_tabulate_bskip_second_split_nop
     \let\tabl_tabulate_eskip \tabl_tabulate_eskip_second_split_nop
   \fi
\to \t_tabl_tabulate_initializers_second

% see ***
%
% \enabletrackers[nodes.page_vspacing]
% \starttext
%     \starttabulate[||] \dorecurse{100}{\NC Eins \NC \NR \HL} \stoptabulate
% \stoptext

\permanent\tolerant\noaligned\protected\def\tabl_tabulate_XX_none  [#1]{\noalign{\tabl_tabulate_break_state_set}}

\permanent\tolerant\noaligned\protected\def\tabl_tabulate_FL_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_FL_second_indeed}}
\permanent\tolerant\noaligned\protected\def\tabl_tabulate_ML_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_ML_second_indeed}}
\permanent\tolerant\noaligned\protected\def\tabl_tabulate_SL_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_SL_second_indeed}}
\permanent\tolerant\noaligned\protected\def\tabl_tabulate_LL_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_LL_second_indeed}}
\permanent\tolerant\noaligned\protected\def\tabl_tabulate_TL_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_TL_second_indeed}}
\permanent\tolerant\noaligned\protected\def\tabl_tabulate_BL_second[#1]{\noalign{\tabl_tabulate_hrule_preset[#1]\tabl_tabulate_BL_second_indeed}}

\protected\def\tabl_tabulate_FL_second_indeed
  {\ifinsidefloat\orelse\ifempty{\tabulationparameter\c!before}%%
     \tabl_tabulate_baselinecorrection
   \fi
   \tabl_tabulate_hrule_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \prevdepth\strutdp
   \tabl_tabulate_break_no}

\def\spac_vspacing_no_topskip % use grouped
  {\c_attr_skipcategory\plusten}

\protected\def\tabl_tabulate_ML_second_indeed
  {\tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_hrule_inject
   \vskip-\p_rulethickness\relax
   \begingroup
   \spac_vspacing_no_topskip
   \tabl_tabulate_hrule_inject
   \endgroup
   \tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject}

\protected\def\tabl_tabulate_SL_second_indeed
  {\tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_hrule_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \tabl_tabulate_break_no}

\protected\def\tabl_tabulate_LL_second_indeed
  {\tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_hrule_inject
   \ifinsidefloat
     \tabl_tabulate_inside_inbetween
   \else
     \tabl_tabulate_outside_inbetween
   \fi}

\protected\def\tabl_tabulate_TL_second_indeed
  {\tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_hrule_inject
   \tabl_tabulate_break_no
   \tabl_tabulate_column_rule_separator_inject
  %\prevdepth\strutdp % todo, might differ between TL and BL
   \tabl_tabulate_break_no}

\let\tabl_tabulate_BL_second_indeed\tabl_tabulate_TL_second_indeed

\permanent\def\tabl_tabulate_HL_second
  {\csname
     \ifnum\c_tabl_tabulate_noflines=\zerocount                     F\orelse
   % \ifzeroc_tabl_tabulate_noflines                                F\orelse
     \ifnum\c_tabl_tabulate_noflines=\c_tabl_tabulate_totalnoflines L\else
                                                                    M\fi
   L\endcsname}

\appendtoks
    \enforced\let\FL\tabl_tabulate_XX_none
    \enforced\let\ML\tabl_tabulate_XX_none
    \enforced\let\SL\tabl_tabulate_XX_none
    \enforced\let\LL\tabl_tabulate_XX_none
    \enforced\let\TL\tabl_tabulate_XX_none
    \enforced\let\BL\tabl_tabulate_XX_none
    \enforced\let\HL\tabl_tabulate_XX_none
    \enforced\let\HR\tabl_tabulate_XX_none
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \enforced\let\FL\tabl_tabulate_FL_second
    \enforced\let\ML\tabl_tabulate_ML_second
    \enforced\let\SL\tabl_tabulate_SL_second
    \enforced\let\LL\tabl_tabulate_LL_second
    \enforced\let\TL\tabl_tabulate_TL_second
    \enforced\let\BL\tabl_tabulate_BL_second
    \enforced\let\HL\tabl_tabulate_HL_second
    \enforced\let\HR\tabl_tabulate_HL_second
\to \t_tabl_tabulate_initializers_second

% \dorecurse{10}{
%     \starttabulate[|l|]
%     \FL
%     \NC first line, bound to next rule    \NC \NR
%     \TL
%     \NC bound to previous rule            \NC \NR
%     \NC some line                         \NC \NR
%     \NC some line                         \NC \NR
%     \NC some line                         \NC \NR
%     \NC bound to next rule                \NC \NR
%     \ML
%     \NC bound to previous rule            \NC \NR
%     \NC bound to next rule                \NC \NR
%     \BL
%     \NC last line, bound to previous rule \NC \NR
%     \LL
%     \stoptabulate
% }

% This needs checking:

\permanent\def\tabulaterule    {\HR} % a rule with lineheight
\permanent\def\tabulateline    {\HL} % just a spaced rule
\permanent\def\tabulateautorule{\HR}%
\permanent\def\tabulateautoline{\HL} % no longer different (to be looked into)

%D When support for vertical rules we needed a way to pick up the specification for
%D the final rule and a \type {|{}} interface was chosen. As a result parsing had to
%D become more complex and I was not in the mood for messing up the code too much.
%D Therefore from now on the preamble is split by \LUA. There are definitely more
%D places where we can use \LUA\ code (for instance in alignment of numbers. The
%D repeat parser is replace at the \LUA\ end as well.

\lettonothing\tabl_tabulate_flush_collected
\lettonothing\tabl_tabulate_flush_collected_indeed

\let\v_tabl_tabulate_align\!!zerocount

\def\tabl_tabulate_check_side_float % new per 29-07-2016
  {\ifdefined\page_sides_check_floats_indeed
     \page_sides_check_floats_indeed
     \ifdim\hangindent>\zeropoint
       \advanceby\d_tabl_tabulate_indent\hangindent
     \fi
   \fi}

\def\tabl_tabulate_set_local_hsize
  {\setlocalhsize
   \hsize\localhsize}

% test case for pre/post spacing:
%
% \ruledvbox{\starttabulate[|l|]  \FL\NC xxx \NC         \NR\LL\stoptabulate}
% \ruledvbox{\starttabulate[|l|l|]\FL\NC xxx \NC xxx \NC \NR\LL\stoptabulate}
% \ruledvbox{\starttabulate[|l|]     \NC xxx \NC         \NR   \stoptabulate}
% \ruledvbox{\starttabulate[|lj8|]   \NC xxx \NC         \NR   \stoptabulate}
% \ruledvbox{\starttabulate[|k8|]    \NC xxx \NC         \NR   \stoptabulate}
% \ruledvbox{\starttabulate[|l|l|]   \NC xxx \NC xxx \NC \NR   \stoptabulate}

% \enabletrackers[localanchor]
%
% \startoverlayMPgraphic{mp:whatever-6}
%     draw anchorcell (1,1)       withpen pencircle scaled 1pt withcolor "blue" ;
%     fill anchorspan (2,2) (3,5) withpen pencircle scaled 1pt withcolor "yellow" ;
%     draw anchorcell (2,2)       withpen pencircle scaled 1pt withcolor "green" ;
%     draw anchorcell (3,3)       withpen pencircle scaled 1pt withcolor "red" ;
% \stopoverlayMPgraphic
%
% \starttabulate[synchronize=background,background=mp:whatever-6,format={|l|c|r|}]
%     \NC test      \NC test      \NC test      \NC \NR
%     \NC test      \NC test test \NC test      \NC \NR
%     \NC test test \NC test      \NC test      \NC \NR
%     \NC test      \NC test      \NC test      \NC \NR
%     \NC test      \NC test      \NC test test \NC \NR
% \stoptabulate

\protected\def\tabl_tabulate_anchor_indeed
  {\edef\xanchor{\the\c_tabl_tabulate_column}%
   \edef\yanchor{\the\c_tabl_tabulate_nofrealrows}%
   \markanchor{matrix}{\c_tabl_tabulate_column}{\c_tabl_tabulate_nofrealrows}}

\def\tabl_tabulate_anchor_setup % a bit of a cheat but good enough for a lightweight experiment
  {\edef\p_synchronize{\tabulationparameter\c!synchronize}%
   \ifx\p_synchronize\v!background
     \cdef\currentframedcontent{\tabulationparameter\c!frame}%
     \ifx\currentframedcontent\v!off
       \resettabulationparameter\c!frame
       \lettonothing\currentframedcontent
       \letframedcontentparameter\c!frame\v!off
     \fi
     \letframedcontentparameter\c!synchronize\p_synchronize
     \setframedcontentparameter\c!background {\tabulationparameter\c!background}%
     \enforced\let\tabl_tabulate_anchor\tabl_tabulate_anchor_indeed
     \setlocalanchoring
   \fi}

\permanent\protected\lettonothing\tabl_tabulate_anchor

\definesystemattribute[alignskip][public]

\lettonothing\c_tabl_tabulate_split_options
\lettonothing\c_tabl_tabulate_split_reset

\def\tabl_tabulate_process
  {\c_tabl_tabulate_pass\plusone
   \tabl_tabulate_check_full_content
   \edef\v_tabl_tabulate_align{\ifcsname\??tabulatealigning\p_align\endcsname\lastnamedcs\else0\fi}%
   \s_tabl_tabulate_first.5\d_tabl_tabulate_unit
   \s_tabl_tabulate_last\s_tabl_tabulate_first
   \s_tabl_tabulate_pre\zeroskip
   \s_tabl_tabulate_post\zeroskip
   %c_tabl_pre_is_set\conditionalfalse
   \c_tabl_post_is_set\conditionalfalse
   \global\c_tabl_tabulate_columns\zerocount
   \global\c_tabl_tabulate_nofauto\zerocount
   \global\c_tabl_tabulate_noflines\zerocount
   \c_tabl_tabulate_totalnoflines\zerocount
   \c_tabl_tabulate_minusnoflines\zerocount
   \global\d_tabl_tabulate_width_p\zeropoint
   \global\d_tabl_tabulate_width_w\zeropoint
   \global\c_tabl_tabulate_equal\conditionalfalse
   \tabl_tabulate_pheight_reset
   \tabl_tabulate_split_reset
   \tabskip\zeroskip
   \ifinsidesplitfloat
     \donetrue
   \orelse\ifinsidefloat
     \donefalse
   \else
     \donetrue
   \fi
   \global\c_tabl_tabulate_repeathead
     \ifdone
       \ifcsname\??tabulateheader\tabulationparameter\c!header\endcsname
         \lastnamedcs
       \else
         \zerocount
       \fi
     \else
       \zerocount
     \fi
   %
   \expand\t_tabl_tabulate_initializers_first % collect more here
   %
   \glettonothing\tabl_tabulate_flush_collected
   \ifdim\d_tabl_tabulate_margin>\zeropoint
     \t_tabl_tabulate_preamble
       {\aligntab
        \tabl_tabulate_flush_indent
% \global\advanceby\c_tabl_tabulate_noflines\plusone
        \strut
        \aligncontent % \alignmark\alignmark
        \tabskip\d_tabl_tabulate_margin
        \strut
        \aligntab
        \aligncontent % \alignmark\alignmark
        \tabskip\zeropoint}%
   \else
     \t_tabl_tabulate_preamble
       {\aligntab
        \tabl_tabulate_flush_indent
% \global\advanceby\c_tabl_tabulate_noflines\plusone
        \strut
        \aligncontent % \alignmark\alignmark
        \aligntab
        \aligncontent % \alignmark\alignmark
        \tabskip\zeroskip}%
   \fi
   \d_tabl_tabulate_width\zeropoint
   % these counters are set at the lua end
   \c_tabl_tabulate_nofcolumns         \zerocount
   \c_tabl_tabulate_has_rule_spec_first\zerocount
   \c_tabl_tabulate_has_rule_spec_last \zerocount
   \clf_presettabulate{\detokenizedtabulationparameter\c!format}%
   %
   \d_tabl_tabulate_width\zeropoint
   \tabl_tabulate_initialize_boxes\c_tabl_tabulate_columns
   \toksapp\t_tabl_tabulate_preamble{%
     \aligntab
     \aligncontent % \alignmark\alignmark
     \global\advanceby\c_tabl_tabulate_column\plusone % maybe just set it already
   }%
   \toksapp\t_tabl_tabulate_dummy{%
     \NC\unskip\unskip\crcr\tabl_tabulate_flush_collected % no count
   }%
   \global\c_tabl_tabulate_column\zerocount
   \tabl_tabulate_pheight_reset
   \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
   \ifx\p_indenting\v!no
     \forgetparindent
   \fi
   \ifinsidefloat
     \d_tabl_tabulate_indent\zeropoint
   \else
     \tabl_tabulate_check_side_float
     \tabl_tabulate_set_local_hsize
   \fi
   \dontcomplain
   \forgetall % hm, interference with preceding \forgetparindent probably bug, to be solved
   \everypar\everytabulatepar
   \setbox\scratchbox\vbox % outside \if because of line counting
     {\notesenabledfalse
      \d_tabl_tabulate_indent\zeropoint
      \settrialtypesetting % very important
      \anch_backgrounds_text_level_start
      \halign
        \ifconditional\c_tabl_sparse_skips \s!noskips\fi
        \ifconditional\c_tabl_auto_align_mode_new \alignmentcharactertrigger\fi
        \expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}}%
      \anch_backgrounds_text_level_stop
      \ifcase\c_anch_backgrounds_text_state\else
        \global\tablehaspositions\conditionaltrue
      \fi
   \ifnum\c_tabl_tabulate_nofauto>\zerocount
     % so, even if the natural size is larger, in the final run, we force the calculated width
     \d_tabl_tabulate_width{\hsize-\wd\scratchbox-\d_tabl_tabulate_width_p-\d_tabl_tabulate_width_w}%
     \ifnum\c_tabl_tabulate_nofauto>\zerocount
       \divideby\d_tabl_tabulate_width \c_tabl_tabulate_nofauto\relax
     \fi
   \fi
   \setbox\scratchbox\emptybox % free memory
   \ifconditional\c_tabl_tabulate_split
     \splittopskip\strutht
     \glettonothing\tabl_tabulate_flush_collected_indeed
     \glet\tabl_tabulate_flush_collected\tabl_tabulate_flush_second
   \fi
   \c_tabl_tabulate_totalnoflines\c_tabl_tabulate_noflines
   \c_tabl_tabulate_minusnoflines{\c_tabl_tabulate_noflines+\minusone}%
   \global\c_tabl_tabulate_noflines\zerocount
   %
   \c_tabl_tabulate_pass\plustwo % final pass
   \expand\t_tabl_tabulate_initializers_second % collect more here
   %
   \ifx\p_line\v!line
     \enforced\let\HL\HR
     \enforced\let\tabulateautoline\tabulateautorule
     \enforced\let\tabulateline    \tabulaterule
   \fi
   %
   \ifcase\c_tabl_tabulate_repeathead
     \ifinsidesplitfloat
        \global\setbox\b_tabl_tabulate\vbox \bgroup
      \else
        \tabl_tabulate_anchor_setup
        \startframedcontent[\tabulationparameter\c!frame]%
      \fi
   \else
     \global\setbox\b_tabl_tabulate\vbox \bgroup
   \fi
   %
   \tabl_tabulate_tag_start
   \tabl_tabulate_tag_start_row
   \inhibitmargindata\conditionalfalse % new per 2012.06.13 ... really needed
   \toksapp\everycr{\noalign{\the\t_tabl_tabulate_every_real_row\tabl_tabulate_tag_stop_row\tabl_tabulate_tag_start_row\empty}}%
   \halign
     \tabl_tabulate_split_options
     \s!callbacks \align_callback_alignskip % always
     \ifconditional\c_tabl_sparse_skips \s!noskips\fi
     \ifconditional\c_tabl_auto_align_mode_new \alignmentcharactertrigger\fi
     \expandafter{\the\t_tabl_tabulate_preamble\crcr\tabl_tabulate_insert_content\crcr}%
   \tabl_tabulate_tag_stop_row
   \tabl_tabulate_tag_stop
   \ifhmode\par\prevdepth\strutdp\fi % nog eens beter, temporary hack
   \ifx\p_distance\v!grid
     \vskip-\strutdp % experimental tm-prikkels
   \fi
   %
   \ifcase\c_tabl_tabulate_repeathead
     \ifinsidesplitfloat
       \egroup % box
       \egroup % settings
       \tabl_split_box\b_tabl_tabulate
     \else
       \stopframedcontent
       \egroup
     \fi
   \else
     \egroup % box
     \egroup % settings
     \tabl_split_box\b_tabl_tabulate
   \fi
   %
   \ifinsidefloat
     \tabl_tabulate_inside_after
   \else
     \tabl_tabulate_outside_after
   \fi
   \egroup} % whole thing

% \egroup

% \setuptabulate[split=yes,header=text,title=Vervolg van Tabel]
%
% % \starttabulatehead
% % \NC test \NC hans\NC \NR
% % \stoptabulatehead
%
% \starttabulate
% \NC test \NC \input tufte \relax \NC \NR
% \NC test \NC \input knuth \relax \NC \NR
% \NC test \NC \input knuth \relax \NC \NR
% \NC test \NC \input tufte \relax \NC \NR
% \NC test \NC \input tufte \relax \NC \NR
% \NC test \NC \input tufte \relax \NC \NR
% \stoptabulate

% todo: use the more modern line getter

\def\tabl_split_box#1% #1 <> 0/2 / derived from the one in core-ntb.tex
  {\ifinsidesplitfloat
     \tabl_split_box_indeed#1%
   \orelse\ifinsidefloat
     \unvbox#1%
   \else
     \tabl_split_box_indeed#1%
   \fi}

\def\tabl_split_box_indeed#1%
  {\resettsplit
   \c_split_minimum_free_lines\plustwo
   \d_split_minimum_free_space\zeropoint
   \setbox\b_split_content\box#1%
   \ifcase\c_tabl_tabulate_repeathead\or
     \setbox\b_split_head\vsplit\b_split_content upto \lineheight
   \or
     \setbox\b_split_head\vbox{\hbox{\strut\tabulationparameter\c!title}}%
   \fi
   \handletsplit}

%D \starttyping
%D \setuptabulate[split=no,rule=line]
%D
%D \starttabulate
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \NC tufte \NC \input tufte \NC \NR \tabulateautorule
%D \stoptabulate
%D \stoptyping

%D Spacing:
%
% \starttabulate
% \NC text \NC text \NC \NR
% \TB[small]
% \NC text \NC text \NC \NR
% \TB[4*big]
% \NC text \NC text \NC \NR
% \stoptabulate

\permanent\tolerant\noaligned\protected\def\tabl_tabulate_TB_yes[#1]%
  {\noalign\bgroup
     \unless\ifempty{#1}%
       \blank[#1]%
     \orelse\ifempty\m_tabl_tabulate_blank_default
       \blank
     \else
       \blank[\m_tabl_tabulate_blank_default]%
     \fi
   \egroup}

\permanent\tolerant\noaligned\protected\def\tabl_tabulate_TB_nop[#1]%
  {}

\appendtoks
    \enforced\let\TB\tabl_tabulate_TB_nop
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \enforced\let\TB\tabl_tabulate_TB_yes
\to \t_tabl_tabulate_initializers_second

% %D Between alignment lines certain rules apply, and even a simple test can mess
% %D up a table, which is why we have a special test facilityL
% %D
% %D \startbuffer
% %D \starttabulate[|l|p|]
% %D \NC 1test \NC test \NC \NR
% %D \tableifelse{\doifelse{a}{a}}{\NC Xtest \NC test \NC \NR}{}%
% %D \stoptabulate
% %D \stopbuffer
% %D
% %D \typebuffer \getbuffer
%
% \def\tableifelse#1% should be tabulatenoalign then
%   {\tablenoalign
%      {#1%
%        {\aftergroup \firstoftwoarguments}%
%        {\aftergroup\secondoftwoarguments}}}
%
% \def\tableiftextelse#1{\tableifelse{\doiftextelse{#1}}}

%D Some new trickery:
%D
%D \startbuffer
%D \c_tabl_tabulate_splitoff_whitespace\conditionaltrue
%D
%D \starttabulate[|p(2cm)|p(2cm)|p(2cm)|]
%D     \NC test 1a \NC test 2a \NC test 3a
%D                                 \par
%D                                 test 3b          \NC \NR
%D     \NC test 1a \NC test 2a \NC test 3a
%D                                 \blank[line]
%D                                 test 3b          \NC \NR
%D     \NC test 1a \NC test 2a \NC test 3a
%D                                 \blank[halfline]
%D                                 test 3b
%D                                 \blank[halfline]
%D                                 test 3c          \NC \NR
%D     \NC \blank  \NC \blank  \NC \blank           \NC \NR
%D     \NC test 1a \NC test 2a \NC test 3a
%D                                 \blank[halfline]
%D                                 test 3b
%D                                 \blank[halfline]
%D                                 test 3c          \NC \NR
%D     \NC \blank  \NC \blank  \NC                  \NC \NR
%D     \NC test 1a
%D         \par
%D         test 1b
%D         \par
%D         test 1b \NC test 2a
%D                     \par
%D                     test 2b
%D                     \par
%D                     test 2b \NC test 3a          \NC \NR
%D     \NC test 1a
%D         \blank
%D         test 1b
%D         \par
%D         test 1b \NC test 2a
%D                     \par
%D                     test 2b
%D                     \blank
%D                     test 2b \NC test 3a          \NC \NR
%D \stoptabulate
%D \stopbuffer
%D
%D \typebuffer \start \getbuffer \stop

% \starttabulatie[|mc|]
% \NC \digits{100.000,00} \NC\NR
% \NC \digits{@10.000,00} \NC\NR
% \NC \digits{@@@.100,00} \NC\NR
% \NC \digits{@@@.@10,@@} \NC\NR
% \NC \digits{@@@.@@1,@@} \NC\NR
% \stoptabulatie
%
% \starttabulatie[|mc|]
% \ND 100.000,00 \NC\NR
% \ND @10.000,00 \NC\NR
% \ND @@@.100,00 \NC\NR
% \ND @@@.@10,@@ \NC\NR
% \ND @@@.@@1,@@ \NC\NR
% \stoptabulatie
%
% \starttabulatie[|c|]
% \ND $100.000,00$ \NC\NR
% \ND $@10.000,00$ \NC\NR
% \ND $@@@.100,00$ \NC\NR
% \ND $@@@.@10,@@$ \NC\NR
% \ND $@@@.@@1,@@$ \NC\NR
% \stoptabulatie
%
% \starttabulatie[|c|]
% \NC $\digits 100.000,00 $ \NC\NR
% \NC $\digits @10.000,00 $ \NC\NR
% \NC $\digits @@@.100,00 $ \NC\NR
% \NC $\digits @@@.@10,@@ $ \NC\NR
% \NC $\digits @@@.@@1,@@ $ \NC\NR
% \stoptabulatie
%
% \starttabulatie[|c|]
% \NC \digits $100.000,00$ \NC\NR
% \NC \digits $@10.000,00$ \NC\NR
% \NC \digits $@@@.100,00$ \NC\NR
% \NC \digits $@@@.@10,@@$ \NC\NR
% \NC \digits $@@@.@@1,@@$ \NC\NR
% \stoptabulatie

%D Predefined categories (moved from core-mis):

\mutable\let\leg \relax % column separators
\mutable\let\fact\relax % column separators

\definetabulate
  [\v!legend]
  [|emj1|i1|mR|]

\setuptabulate
  [\v!legend]
  [\c!unit=.75em,\c!inner=\tabl_tabulate_set_quick\leg,EQ={=}]

\definetabulate
  [\v!legend][\v!two]
  [|emj1|emk1|i1|mR|]

\definetabulate
  [\v!fact]
  [|R|ecmj1|i1mR|]

\setuptabulate
  [\v!fact]
  [\c!unit=.75em,\c!inner=\tabl_tabulate_set_quick\fact,EQ={=}]

%D Another example:
%D
%D \starttyping
%D \definetabulate
%D   [whatever]
%D   [|l|r|]
%D
%D \definetabulate
%D   [whatever][else]
%D   [|l|c|r|]
%D
%D \startwhatever
%D \NC l    \NC r     \NC \NR
%D \NC left \NC right \NC \NR
%D \stopwhatever
%D
%D \startwhatever[else]
%D \NC l    \NC m      \NC r     \NC \NR
%D \NC left \NC middle \NC right \NC \NR
%D \stopwhatever
%D
%D \startwhatever[else][format={|c|c|c|c|}]
%D \NC l    \NC m      \NC m      \NC r     \NC \NR
%D \NC left \NC middle \NC middle \NC right \NC \NR
%D \stopwhatever
%D \stoptyping

%D This is needed because we sometimes use the english command in tracing macros. In
%D fact, most detailed tracing macros that are done with \LUA\ only work in the
%D english interface anyway.

% \definetabulate[tabulate] \setuptabulate[tabulate][\c!format=\v!none] % so no \v! here

\newconditional\c_tabl_generic

\pushoverloadmode

\permanent\protected\defcsname starttabulate\endcsname
  {\bgroup % whole thing
   \c_tabl_generic\conditionaltrue
   \lettonothing\currenttabulationparent
   \tabl_start_regular}

\permanent\letcsname stoptabulate\endcsname\relax % testcase cvs-002.tex

\popoverloadmode

%D The following helpers are just there because we also have them at the \LUA\ end:
%D
%D \startbuffer
%D \starttabulate[|l|c|r|]
%D     \tabulaterow    {a,b,c}
%D     \tabulaterowbold{aa,bb,cc}
%D     \tabulaterowtype{aaa,bbb,ccc}
%D     \tabulaterowtyp {aaaa,bbbb,cccc}
%D \stoptabulate
%D \stopbuffer
%D
%D \typebuffer \getbuffer

\def\tabl_tabulate_compact_row#1#2%
  {\NC\tabl_tabulate_compact_step#1#2,\end,}

\def\tabl_tabulate_compact_step#1#2#3,%
  {\ifx#2\end
     \NR
     \expandafter\gobbleoneargument
   \else
     #1{#2#3}\NC
     \expandafter\tabl_tabulate_compact_step
   \fi#1}

\permanent\protected\def\tabulaterow    {\tabl_tabulate_compact_row\relax}
\permanent\protected\def\tabulaterowbold{\tabl_tabulate_compact_row\bold}
\permanent\protected\def\tabulaterowtype{\tabl_tabulate_compact_row\type}
\permanent\protected\def\tabulaterowtyp {\tabl_tabulate_compact_row\typ}

%D Here we plug in a row background feature. As we only have support for
%D \type {frame=name} we can use these variables.
%D
%D \starttyping
%D \startuseMPgraphic{foo}
%D     fill unitsquare
%D         xyscaled (RuleWidth,RuleHeight+RuleDepth) enlarged (ExHeight/4,ExHeight/8)
%D         randomized ExHeight
%D         shifted  (-ExHeight/8,ExHeight/16)
%D         withcolor RuleColor ;
%D \stopuseMPgraphic
%D
%D \setuptabulate % wel only have frame=name so we can use these:
%D   [background=foo,
%D    backgroundcolor=darkred,
%D    foregroundcolor=white]
%D
%D \definelinefiller[foo][mp=foo,color=darkgreen]
%D \definelinefiller[bar][mp=foo,color=darkred]
%D
%D \starttabulate[|||]
%D     \DB foo \BC bar \BC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D \stoptabulate
%D
%D \starttabulate[|||]
%D     \PB foo \BC bar \BC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D     \NC foo \NC bar \NC \NR
%D \stoptabulate
%D
%D \starttabulate[|||]
%D     \FB[bar] foo \BC bar \BC \NR
%D     \NC      foo \NC bar \NC \NR
%D     \NC      foo \NC bar \NC \NR
%D     \NC      foo \NC bar \NC \NR
%D     \NC      foo \NC bar \NC \NR
%D \stoptabulate
%D
%D \startnarrower
%D     \starttabulate[|||]
%D         \DB foo \DB bar \BC \NR
%D         \NC foo \NC bar \NC \NR
%D         \NC foo \NC bar \NC \NR
%D         \NC foo \NC bar \NC \NR
%D         \NC foo \NC bar \NC \NR
%D     \stoptabulate
%D \stopnarrower
%D
%D \starttabulate[|||]
%D     \BC          foo \BC bar \BC \NR
%D     \NL[magenta] foo \NC bar \NC \NR
%D     \NL[yellow]  foo \NC bar \NC \NR
%D     \NL[cyan]    foo \NC bar \NC \NR
%D     \NL[gray]    foo \NC bar \NC \NR
%D \stoptabulate
%D
%D \starttabulate
%D     \NL[red]     foo \NC bar \NC \NR
%D     \NL[green]   foo \NL[red] bar \NC \NR
%D     \NC          foo \NC bar \NC \NR
%D     \NL[blue]    foo \NC \input tufte  \NC \NR
%D     \NL[gray]    foo \NC bar \NC \NR
%D     \NL[yellow]  foo \NC bar \NC \NR
%D \stoptabulate
%D \stoptyping

% \setuptabulate
%   [\c!background=,
%    \c!backgroundcolor=,
%    \c!foregroundcolor=,
%    \c!foregroundstyle=]

\lettonothing\m_table_current_row_background
\lettonothing\m_table_current_row_background_default
\lettonothing\m_table_current_row_background_filler
\lettonothing\m_table_current_row_background_default_filler
\lettonothing\m_table_current_row_background_auto

\protected\def\tabl_register_row_background#1%
  {\xdef\m_table_current_row_background{#1}}

\protected\def\tabl_register_row_background_filler#1%
  {\xdef\m_table_current_row_background_filler{#1}}

\protected\def\tabl_synchronize_row_background
  {\iftrialtypesetting\else
     \ifempty\m_table_current_row_background_filler
       \ifempty\m_table_current_row_background
         % nothing
         \tabl_synchronize_row_background_dummy
       \else
         \tabl_synchronize_row_background_indeed\m_table_current_row_background
       \fi
     \else
       \tabl_synchronize_row_background_filler_indeed\m_table_current_row_background_filler
     \fi
   \fi}

\protected\def\tabl_synchronize_row_background_dummy
  {\iftrialtypesetting\else
     \begingroup
     \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\zerocount\zeropoint
     \endgroup
   \fi}

\protected\def\tabl_synchronize_row_background_indeed#1%
  {\iftrialtypesetting\else
     \begingroup
     \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata
     \dousecolorparameter{#1}%
     \setbox\scratchbox\hpack{}%
     \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent
     \endgroup
   \fi}

\protected\def\tabl_synchronize_row_background_filler_indeed#1%
  {\iftrialtypesetting\else
     \begingroup
     \clf_enablebackgroundalign % can be moved into \clf_setbackgroundrowdata
     \node_linefiller_set{#1}%
     \setbox\scratchbox\hpack{}%
     \clf_setbackgroundrowdata\c_tabl_tabulate_nofrealrows\scratchbox\d_tabl_tabulate_indent
     \endgroup
   \fi}

\appendtoks
    \glettonothing\m_table_current_row_background
    \glettonothing\m_table_current_row_background_filler
    \global\c_tabl_tabulate_nofrealrows\zerocount
    \global\c_tabl_tabulate_autocolor\zerocount
    \clf_resetbackgroundrowdata
\to \t_tabl_tabulate_initializers_first

\appendtoks
    \glettonothing\m_table_current_row_background
    \glettonothing\m_table_current_row_background_filler
    \global\c_tabl_tabulate_nofrealrows\zerocount
    \global\c_tabl_tabulate_autocolor\zerocount
    \clf_resetbackgroundrowdata
\to \t_tabl_tabulate_initializers_second

\appendtoks
    \tabl_synchronize_row_background
\to \t_tabl_tabulate_every_real_row

\appendtoks
    \glettonothing\m_table_current_row_background
    \glettonothing\m_table_current_row_background_filler
\to \t_tabl_tabulate_every_after_row

\permanent\protected\def\tabl_tabulate_NL_first[#1]%
  {\tabl_tabulate_column_normal\zerocount\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background{#1}%
   \fi
   \ignorepars} % \ignorespaces

\pushoverloadmode

    % redefinition needs checking

    \permanent\overloaded\protected\def\tabl_tabulate_ND_first
      {\tabl_tabulate_column_normal\zerocount\zerocount\relax
       \ifcase\c_tabl_tabulate_column\or
         \tabl_register_row_background\m_table_current_row_background_default
       \fi
       \ignorepars} % \ignorespaces

\popoverloadmode

\permanent\protected\def\tabl_tabulate_LB_first[#1]%
  {\tabl_tabulate_column_normal\plusone\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background{#1}%
   \fi
   \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_DB_first
  {\tabl_tabulate_column_normal\plusone\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background\m_table_current_row_background_default
   \fi
   \enforced\let\fontstyle\globalfontstyle
   \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_NF_first[#1]%
  {\tabl_tabulate_column_normal\zerocount\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background_filler{#1}%
   \fi
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_NP_first
  {\tabl_tabulate_column_normal\zerocount\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background_filler\m_table_current_row_background_default_filler
   \fi
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_FB_first[#1]%
  {\tabl_tabulate_column_normal\plusone\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background_filler{#1}%
   \fi
   \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_PB_first
  {\tabl_tabulate_column_normal\plusone\zerocount\relax
   \ifcase\c_tabl_tabulate_column\or
     \tabl_register_row_background_filler\m_table_current_row_background_default_filler
   \fi
   \enforced\let\fontstyle\globalfontstyle
   \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
   \ignorepars} % \ignorespaces

\pushoverloadmode

    \permanent\overloaded\protected\def\tabl_tabulate_BC_first
      {\tabl_tabulate_column_normal\plusone\zerocount
       \enforced\let\fontstyle\globalfontstyle
       \ifempty\m_table_current_row_background
         \ifempty\m_table_current_row_background_filler
           \usetabulationstyleandcolor\c!headstyle\c!headcolor
         \else
           \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
         \fi
       \else
         \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
       \fi}

\popoverloadmode

\permanent\protected\def\tabl_tabulate_A_first
  {\global\advanceby\c_tabl_tabulate_autocolor\plusone
   \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\the\c_tabl_tabulate_autocolor}}%
   \ifempty\m_table_current_row_background_auto
     \global\c_tabl_tabulate_autocolor\plusone
     \edef\m_table_current_row_background_auto{\tabulateparameter{\c!backgroundcolor:\the\c_tabl_tabulate_autocolor}}%
   \fi
   \ifempty\m_table_current_row_background_auto
     \lettonothing\m_table_current_row_background_auto % \m_table_current_row_background_default
   \fi
   \tabl_register_row_background{\m_table_current_row_background_auto}}

\permanent\protected\def\tabl_tabulate_NA_first
  {\tabl_tabulate_column_normal\zerocount\zerocount\relax
   \iftrialtypesetting\orelse\ifcase\c_tabl_tabulate_column\or
     \tabl_tabulate_A_first
   \fi
   \ignorepars} % \ignorespaces

\permanent\protected\def\tabl_tabulate_BA_first
  {\tabl_tabulate_column_normal\plusone\zerocount\relax
   \iftrialtypesetting\orelse\ifcase\c_tabl_tabulate_column\or
     \tabl_tabulate_A_first
   \fi
   \usetabulationstyleandcolor\c!foregroundstyle\c!foregroundcolor
   \ignorepars} % \ignorespaces

\appendtoks
    \enforced\let\NL\tabl_tabulate_NL_first % NC with Line
    \enforced\let\ND\tabl_tabulate_ND_first % NC with Default Line
    \enforced\let\LB\tabl_tabulate_LB_first % BC with Line
    \enforced\let\DB\tabl_tabulate_DB_first % BC with Default Line
    \enforced\let\NF\tabl_tabulate_NF_first % NC with Filler
    \enforced\let\NP\tabl_tabulate_NP_first % NC with Predefined Filler
    \enforced\let\FB\tabl_tabulate_FB_first % BC with Filler
    \enforced\let\PB\tabl_tabulate_PB_first % BC with Predefined Filler
    \enforced\let\NA\tabl_tabulate_NA_first % NC with Auto Line
    \enforced\let\BA\tabl_tabulate_BA_first % NC with Auto Line
\to \t_tabl_tabulate_initializers_first

\appendtoks
   \edef\m_table_current_row_background_default{\tabulateparameter\c!backgroundcolor}%
   \edef\m_table_current_row_background_default_filler{\tabulateparameter\c!background}%
   \lettonothing\m_table_current_row_background_auto
\to \everytabulate

\setuptabulate
  [\c!headcolor=,
   \c!headstyle=\bf,
   \c!backgroundcolor=\tabulationparameter\c!rulecolor,
   \c!foregroundcolor=,
   \c!foregroundstyle=\tabulationparameter\c!headstyle]

%D Only for simple cases (read:myself):
%D
%D \starttyping
%D \starttabulate[|c|c|c|]
%D     \NC 1   \NC second column \NC third column \NC \NR
%D     \NC 2   \NC second        \NC third        \NC \NR
%D     \NC 3 r \NS[1][r]second & third \NC \NR
%D     \NC 3 c \NS[1][c]second & third \NC \NR
%D     \NC 3 l \NS[1][l]second & third \NC \NR
%D \stoptabulate
%D \stoptyping

% Not okay yet as we loose alignment in later columns .. weird .. do
% we miss a tab?

\installcorenamespace{tabulatespanb}
\installcorenamespace{tabulatespana}

\noaligned\def\tabl_tabulate_span{\omit\span\omit\span\omit\span}

%\letcsname\??tabulatespanb l\endcsname\relax
\letcsname\??tabulatespana l\endcsname\hfill
\letcsname\??tabulatespanb c\endcsname\hfill
\letcsname\??tabulatespana c\endcsname\hfill
\letcsname\??tabulatespanb m\endcsname\hfill
\letcsname\??tabulatespana m\endcsname\hfill
\letcsname\??tabulatespanb r\endcsname\hfill
%\letcsname\??tabulatespana r\endcsname\relax

\noaligned\tolerant\def\tabl_tabulate_NS[#1]#*[#2]%
  {\NC\loopcs{#1}\tabl_tabulate_span % use localloop and quit
   \gdef\tabl_tabulate_kooh
     {\begincsname\??tabulatespana#2\endcsname
      \glet\tabl_tabulate_kooh\relax}%
   \begincsname\??tabulatespanb#2\endcsname
   \ignorepars} % \ignorespaces

\appendtoks
    \enforced\let\NS\tabl_tabulate_NS
\to \t_tabl_tabulate_initializers_first

% \appendtoks
%     \let\NS\tabl_tabulate_NS
% \to \t_tabl_tabulate_initializers_second

% This feature is not public yet and only meant for Wolfgang, Mikael and Hans to
% play with. We need to deal with the hooks and might also add some extra features
% in this variant. In addition there might be a variant for simple cases: if we have
% only one P we can avoid processing that paragraph because it will take the left
% over space. For manuals this might be more efficient because often we have a few
% simple columns plus a paragraph, like [|l|l|P|] where wd(P) == hsize - trial wd(l)
% - trial wd(l) - separators.

\installtabulatepreambleoption{P}{\tabl_tabulate_set_paragraph_split}

\newconditional\c_tabl_tabulate_use_split

\def\tabl_tabulate_set_paragraph_split
  {\global\c_tabl_tabulate_use_split\conditionaltrue
   \doifelsenextparenthesis
     {\c_tabl_tabulate_modus\plusfour
      \c_tabl_tabulate_pwidth_set\conditionaltrue
      \tabl_tabulate_pickup_width}
     {\c_tabl_tabulate_modus\plusfive
      \c_tabl_tabulate_pwidth_set\conditionalfalse
      \tabl_tabulate_set_preamble}}

\def\tabl_tabulate_split_reset
  {\global\c_tabl_tabulate_use_split\conditionalfalse}

\def\tabl_tabulate_split_options
  {\ifconditional\c_tabl_tabulate_use_split
      split
    % gluemode 1 or 2 : will be a parameter if tabulate (glue instead of box or penalties
      minheight \strutht
      mindepth  \strutdp
   \fi}

\def\tabl_tabulate_bsplit_raggedright {\tabl_tabulate_bsplit\tabl_tabulate_set_raggedright }
\def\tabl_tabulate_bsplit_raggedleft  {\tabl_tabulate_bsplit\tabl_tabulate_set_raggedleft  }
\def\tabl_tabulate_bsplit_raggedcenter{\tabl_tabulate_bsplit\tabl_tabulate_set_raggedcenter}

\def\tabl_tabulate_set_width_fixed_split
  {\ifcase\c_tabl_tabulate_align\relax
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit             \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedright \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedleft  \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedcenter\tabl_tabulate_esplit \fi}

\def\tabl_tabulate_set_width_auto_split
  {\global\advanceby\c_tabl_tabulate_nofauto\plusone
   \ifcase\c_tabl_tabulate_align\relax
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit             \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedright \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedleft  \tabl_tabulate_esplit \or
     \tabl_tabulate_set_preamble_step\tabl_tabulate_bsplit_raggedcenter\tabl_tabulate_esplit \fi}

\def\tabl_tabulate_bsplit_first
  {\setbox\b_tabl_tabulate\vbox
   \bgroup}
%      \glet\tabl_tabulate_hook\tabl_tabulate_hook_nop

\def\tabl_tabulate_esplit_first
  {\egroup}
%    \ifcase\c_tabl_tabulate_pass\or
%        \glet\tabl_tabulate_hook\tabl_tabulate_hook_yes
%    \fi

\def\tabl_tabulate_bsplit_second
  {\vtop
     alignsplit
   \bgroup
     \ifconditional\c_tabl_tabulate_no_blank_in_paragraphs
       \inhibitblank
     \fi
     \ifconditional\c_tabl_tabulate_automode\hsize\d_tabl_tabulate_width\fi
     \expandafter\ignorepars} % \ignorespaces

\def\tabl_tabulate_esplit_second
  {\ifconditional\c_tabl_tabulate_no_blank_in_paragraphs
     \removelastskip
   \fi
   \egroup}

\lettonothing\tabl_tabulate_bsplit
\lettonothing\tabl_tabulate_esplit

\appendtoks
     \let\tabl_tabulate_bsplit\tabl_tabulate_bsplit_first
     \let\tabl_tabulate_esplit\tabl_tabulate_esplit_first
\to \t_tabl_tabulate_initializers_first

\appendtoks
     \let\tabl_tabulate_bsplit\tabl_tabulate_bsplit_second
     \let\tabl_tabulate_esplit\tabl_tabulate_esplit_second
\to \t_tabl_tabulate_initializers_second

\protect \endinput
