%D \module
%D   [       file=spac-ali,
%D        version=2009.10.16, % 1997.03.31, was core-spa.tex
%D          title=\CONTEXT\ Spacing Macros,
%D       subtitle=Alignments,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\writestatus{loading}{ConTeXt Spacing Macros / Alignments}

\unprotect

%D The \type {new} and \type {old} methods are gone as we now have \type {flush*}
%D variants. Starting at the last day of 2011 both methods are merged into one and
%D caching has been added, which makes switching twice as fast.

\registerctxluafile{spac-ali}{autosuffix,optimize}

% Used once so ... replace it or use if more frequently ...

\installcorenamespace {alignswitch}

% maybe \setconstantvalue or so

\expandafter\integerdef\csname\??alignswitch\v!left  \endcsname\zerocount
\expandafter\integerdef\csname\??alignswitch\v!middle\endcsname\plusone
\expandafter\integerdef\csname\??alignswitch\v!right \endcsname\plustwo

\mutable\integerdef\alignmentswitch\zerocount

\permanent\protected\def\setalignmentswitch#1%
  {\integerdef\alignmentswitch\csname\??alignswitch\ifcsname\??alignswitch#1\endcsname#1\else\v!left\fi\endcsname}

% till here

\definesystemattribute[realign]   [public] % might be combined with the next one
\definesystemattribute[alignstate][public] % will make a single attributes for several states

\appendtoks
    \c_attr_realign   \attributeunsetvalue
    \c_attr_alignstate\attributeunsetvalue
\to \everyforgetall

\permanent\protected\def\signalinnerrealign{\clf_setrealign\plustwo}
\permanent\protected\def\signalouterrealign{\clf_setrealign\plusone}

\installcorenamespace{aligncommand}
\installcorenamespace{alignhorizontal}
\installcorenamespace{alignvertical}

% \installcorenamespace{alignmentnormalcache}
% \installcorenamespace{alignmentraggedcache}

% nasty hack:

\installcorenamespace{alignmentnormalcacheodd}
\installcorenamespace{alignmentnormalcacheeven}

\installcorenamespace{alignmentraggedcacheodd}
\installcorenamespace{alignmentraggedcacheeven}

\immutable\def\??alignmentnormalcache{\ifodd\realpageno\??alignmentnormalcacheodd\else\??alignmentnormalcacheeven\fi}
\immutable\def\??alignmentraggedcache{\ifodd\realpageno\??alignmentraggedcacheodd\else\??alignmentraggedcacheeven\fi}

\newtoks\everyresetalign % todo

% This will become a more advanced layout controller soon:

\newconditional\layoutlefttoright   \settrue\layoutlefttoright
\newconditional\displaylefttoright  \settrue\displaylefttoright
\newconditional\inlinelefttoright   \settrue\inlinelefttoright

\permanent\protected\def\lefttoright
  {\ifvmode
     \spac_directions_lefttoright_vmode
   \else
     \spac_directions_lefttoright_hmode
   \fi}

\permanent\protected\def\righttoleft
  {\ifvmode
     \spac_directions_righttoleft_vmode
   \else
     \spac_directions_righttoleft_hmode
   \fi}

\protected\def\spac_directions_lefttoright_vmode
  {\settrue\displaylefttoright
   \settrue\inlinelefttoright
   \textdirection\directionlefttoright
   \pardirection \directionlefttoright}

\protected\def\spac_directions_righttoleft_vmode
  {\setfalse\displaylefttoright
   \setfalse\inlinelefttoright
   \textdirection\directionrighttoleft
   \pardirection \directionrighttoleft}

\protected\def\spac_directions_lefttoright_hmode
  {\linedirection\directionlefttoright % linedir keeps subtype of skip
   \settrue\inlinelefttoright}

\protected\def\spac_directions_righttoleft_hmode
  {\linedirection\directionrighttoleft % linedir keeps subtype of skip
   \setfalse\inlinelefttoright}

\permanent\protected\def\synchronizelayoutdirection
  {\ifconditional\layoutlefttoright
     \spac_directions_synchronize_lr
   \else
     \spac_directions_synchronize_rl
   \fi}

\permanent\protected\def\synchronizedisplaydirection
  {\ifconditional\displaylefttoright
     \spac_directions_synchronize_lr
   \else
     \spac_directions_synchronize_rl
   \fi}

\def\spac_directions_synchronize_lr
  {\settrue\inlinelefttoright
   \textdirection\directionlefttoright
   \pardirection \directionlefttoright}

\def\spac_directions_synchronize_rl
  {\setfalse\inlinelefttoright
   \textdirection\directionrighttoleft
   \pardirection \directionrighttoleft}

\permanent\protected\def\synchronizeinlinedirection
  {% why not \linedirection here
   \textdirection\ifconditional\inlinelefttoright\directionlefttoright\else\directionrighttoleft\fi}

\permanent\protected\def\checkedlefttoright
  {\ifvmode
     \spac_directions_lefttoright_vmode
   \else
     \spac_directions_lefttoright_hmode_checked
   \fi}

\permanent\protected\def\checkedrighttoleft
  {\ifvmode
     \spac_directions_righttoleft_vmode
   \else
     \spac_directions_righttoleft_hmode_checked
   \fi}

\protected\def\spac_directions_lefttoright_hmode_checked
  {\ifconditional\inlinelefttoright\else
     \lefttoright
   \fi}

\protected\def\spac_directions_righttoleft_hmode_checked
  {\ifconditional\inlinelefttoright
     \righttoleft
   \fi}

\installcorenamespace{bidi}

\letcsname\??bidi\v!left \endcsname\checkedlefttoright \letcsname\??bidi l2r\endcsname\checkedlefttoright
\letcsname\??bidi\v!right\endcsname\checkedrighttoleft \letcsname\??bidi r2l\endcsname\checkedrighttoleft

\permanent\protected\def\usebidiparameter#1%
  {\begincsname\??bidi#1\c!bidi\endcsname}

\permanent\protected\def\showdirections
  {\dontleavehmode
   \begingroup\infofont\textdirection\directionlefttoright[\space
   layout:  \ifconditional\layoutlefttoright  l2r\else r2l\fi\space
   display: \ifconditional\displaylefttoright l2r\else r2l\fi\space
   inline:  \ifconditional\inlinelefttoright  l2r\else r2l\fi\space
   ]\endgroup}

\permanent\protected\def\righttolefthbox#1#{\reversehbox#1\bgroup\righttoleft\let\next} \aliased\let\rtlhbox\righttolefthbox
\permanent\protected\def\lefttorighthbox#1#{\naturalhbox#1\bgroup\lefttoright\let\next} \aliased\let\ltrhbox\lefttorighthbox
\permanent\protected\def\righttoleftvbox#1#{\reversevbox#1\bgroup\righttoleft\let\next} \aliased\let\rtlvbox\righttoleftvbox
\permanent\protected\def\lefttorightvbox#1#{\naturalvbox#1\bgroup\lefttoright\let\next} \aliased\let\ltrvbox\lefttorightvbox
\permanent\protected\def\righttoleftvtop#1#{\reversevtop#1\bgroup\righttoleft\let\next} \aliased\let\rtlvtop\righttoleftvtop
\permanent\protected\def\lefttorightvtop#1#{\naturalvtop#1\bgroup\lefttoright\let\next} \aliased\let\ltrvtop\lefttorightvtop

\permanent\protected\def\autodirhbox#1#{\hbox#1\bgroup\synchronizeinlinedirection\let\next}
\permanent\protected\def\autodirvbox#1#{\vbox#1\bgroup\synchronizeinlinedirection\let\next} % maybe also pardir or maybe just a \vbox
\permanent\protected\def\autodirvtop#1#{\vtop#1\bgroup\synchronizeinlinedirection\let\next} % maybe also pardir or maybe just a \vtop

\permanent\protected\def\leftorrighthbox{\ifconditional\displaylefttoright\expandafter\lefttorighthbox\else\expandafter\righttolefthbox\fi}
\permanent\protected\def\leftorrightvbox{\ifconditional\displaylefttoright\expandafter\lefttorightvbox\else\expandafter\righttoleftvbox\fi}
\permanent\protected\def\leftorrightvtop{\ifconditional\displaylefttoright\expandafter\lefttorightvtop\else\expandafter\righttoleftvtop\fi}

% Tolerance and hyphenation

\ifdefined\lesshyphens \else \let\lesshyphens\relax \fi
\ifdefined\morehyphens \else \let\morehyphens\relax \fi
\ifdefined\nohyphens   \else \let\nohyphens  \relax \fi
\ifdefined\dohyphens   \else \let\dohyphens  \relax \fi

\newconstant\c_spac_tolerance_default  \c_spac_tolerance_default 1500 % shouldn't that be 200
\newconstant\c_spac_tolerance_minimum  \c_spac_tolerance_minimum 1500
\newconstant\c_spac_tolerance_normal   \c_spac_tolerance_normal  3000
\newconstant\c_spac_tolerance_extreme  \c_spac_tolerance_extreme 4500

\def\spac_align_set_raggedness_left  {\plustwo\bodyfontsize}
\def\spac_align_set_raggedness_right {\plustwo\bodyfontsize}
\def\spac_align_set_raggedness_middle{\plussix\bodyfontsize} % overloaded below

% oeps, hsize can be 0pt in which case we get a strange division
% was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}

\def\spac_align_set_raggedness_middle{\ifzeropt\hsize\plussix\bodyfontsize\else.5\hsize\fi}

\permanent\protected\def\setraggedness#1% tricky .. we keep the global tolerance otherwise ... to be reconsidered
  {\ifnum\tolerance<\c_spac_tolerance_minimum
     \tolerance\c_spac_tolerance_minimum % small values have unwanted side effects
   \else
     % todo: take set value or none .. better done elsewhere (200 is normal)
   \fi
   \ifrelax\dohyphens % was 2.5 in old implementation using scratch registers
     \hyphenpenalty\dimexpr2.8\hsize/\dimexpr#1\relax\relax % 50 in raggedright/raggedleft
  %\else
     % no need to do something as we're in \nohyphens
   \fi}

\protected\def\spac_align_set_tolerant
  {\tolerance\c_spac_tolerance_normal}

\protected\def\spac_align_set_very_tolerant
  {\tolerance\c_spac_tolerance_extreme}

\protected\def\spac_align_set_stretch
  {\emergencystretch\bodyfontsize}

\protected\def\spac_align_set_extreme_stretch
  {\emergencystretch10\bodyfontsize}

% Vertical

\newconstant\c_spac_align_state_vertical

\protected\def\spac_align_set_vertical_none
  {\enforced\let\raggedtopcommand   \relax
   \enforced\let\raggedbottomcommand\relax}

\protected\def\spac_align_set_vertical_lohi
  {\enforced\let\raggedtopcommand   \vfilll
   \enforced\let\raggedbottomcommand\vfilll}

\protected\def\spac_align_set_vertical_low
  {\enforced\let\raggedtopcommand   \vfilll
   \enforced\let\raggedbottomcommand\relax}

\protected\def\spac_align_set_vertical_high
  {\enforced\let\raggedtopcommand   \relax
   \enforced\let\raggedbottomcommand\vfilll}

\def\spac_align_flush_vertical
  {\ifcase\c_spac_align_state_vertical
     \spac_align_set_vertical_none
   \or
     \spac_align_set_vertical_lohi
   \or
     \spac_align_set_vertical_low
   \or
     \spac_align_set_vertical_high
   \fi}

% Horizontal

\ifdefined\raggedonelinerstate \else
    \newconditional\raggedonelinerstate  % public
\fi

% \appendtoks
%     \setfalse\raggedonelinerstate
% \to \everyforgetall

\newconstant\raggedstatus % public

\newconstant\c_spac_align_state_horizontal
\newconstant\c_spac_align_state_broad
\newconstant\c_spac_align_state_par_fill

\def\v_spac_align_fill_amount          {\plusone  fil}
\def\v_spac_align_fill_amount_hard     {\plusone fill}
\def\v_spac_align_fill_amount_extreme  {\plustenthousand  filll}
\def\v_spac_align_fill_amount_negative {\minusone fil}
\def\v_spac_align_fill_amount_double   {\plustwo  fil}
\def\v_spac_align_fill_amount_space    {\plustwo  fil} % can be added to xspace if we have a key
\def\v_spac_align_fill_amount_half             {.5fil}
\let\v_spac_align_space_amount        \interwordspace
\def\v_spac_align_space_amount_x          {.5\emwidth}

\newskip\s_zero_plus_one_fil \s_zero_plus_one_fil = 0pt plus 1fil
\newskip\s_zero_plus_zero    \s_zero_plus_zero    = 0pt plus 0pt

% \s!plus ... slower than inline

\permanent\protected\def\spac_align_set_horizontal_none % should also relax \updateraggedskips
  {\raggedstatus     \zerocount
   \c_attr_alignstate\attributeunsetvalue
   \leftskip         \plusone\leftskip
   \rightskip        \plusone\rightskip
   \spaceskip        \zeropoint
   \xspaceskip       \zeropoint
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_one_fil % new
   \setfalse         \raggedonelinerstate % now here
   \enforced\aliased\let\updateraggedskips\relax}          % no need for adaption

\permanent\protected\def\spac_align_set_horizontal_left
  {\setraggedness    \spac_align_set_raggedness_left
   \raggedstatus     \plusone
   \c_attr_alignstate\plusone
   \leftskip         \plusone\leftskip \s!plus\spac_align_set_raggedness_left
   \rightskip        \plusone\rightskip\s!plus\zeropoint
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_center
  {\setraggedness    \spac_align_set_raggedness_middle
   \raggedstatus     \plustwo
   \c_attr_alignstate\plustwo
   \leftskip         \plusone\leftskip \s!plus\spac_align_set_raggedness_middle
   \rightskip        \plusone\rightskip\s!plus\spac_align_set_raggedness_middle
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_right
  {\setraggedness    \spac_align_set_raggedness_right
   \raggedstatus     \plusthree
   \c_attr_alignstate\plusthree
   \leftskip         \plusone\leftskip \s!plus\zeropoint
   \rightskip        \plusone\rightskip\s!plus\spac_align_set_raggedness_right
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_one_fil
  %\parindent        \parindent
   \relax}

\permanent\protected\def\spac_align_set_horizontal_very_left
  {\raggedstatus     \plusone
   \c_attr_alignstate\plusone
   \leftskip         \plusone\leftskip \s!plus\v_spac_align_fill_amount
   \rightskip        \plusone\rightskip\s!plus\zeropoint
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_very_center
  {\raggedstatus     \plustwo
   \c_attr_alignstate\plustwo
   \leftskip         \plusone\leftskip \s!plus\v_spac_align_fill_amount
   \rightskip        \plusone\rightskip\s!plus\v_spac_align_fill_amount
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_very_right
  {\raggedstatus     \plusthree
   \c_attr_alignstate\plusthree
   \leftskip         \plusone\leftskip \s!plus\zeropoint
   \rightskip        \plusone\rightskip\s!plus\v_spac_align_fill_amount
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
  %\parindent        \parindent
   \relax}

\permanent\protected\def\spac_align_set_horizontal_wide_center
  {\setraggedness    \spac_align_set_raggedness_middle
   \raggedstatus     \plustwo
   \c_attr_alignstate\plustwo
   \leftskip         \plusone\leftskip \s!plus\v_spac_align_fill_amount_half
   \rightskip        \plusone\rightskip\s!plus\v_spac_align_fill_amount_half
   \spaceskip        \v_spac_align_space_amount
   \xspaceskip       \v_spac_align_space_amount_x
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_centered_last_line
  {\raggedstatus     \zerocount
   \c_attr_alignstate\attributeunsetvalue
   \leftskip         \plusone\leftskip \s!plus\v_spac_align_fill_amount\relax
   \rightskip        \plusone\rightskip\s!plus\v_spac_align_fill_amount_negative\relax
   \spaceskip        \zeropoint\relax
   \xspaceskip       \zeropoint\relax
   \parfillleftskip  \zeropoint
   \parfillskip      \zeropoint\s!plus\v_spac_align_fill_amount_double\relax
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_flushedright_last_line
  {\raggedstatus     \zerocount
   \c_attr_alignstate\attributeunsetvalue
   \leftskip         \plusone\leftskip \s!plus\v_spac_align_fill_amount\relax
   \rightskip        \plusone\rightskip\s!plus\v_spac_align_fill_amount_negative\relax
   \spaceskip        \zeropoint\relax
   \xspaceskip       \zeropoint\relax
   \parfillskip      \zeropoint
   \parfillleftskip  \zeropoint\s!plus\v_spac_align_fill_amount_extreme\relax
   \parindent        \zeropoint
   \relax}

\permanent\protected\def\spac_align_set_horizontal_right_tt % a plain command
  {\tttf % brrr
   \raggedstatus     \plusthree
   \c_attr_alignstate\plusthree
   \leftskip         \plusone\leftskip \s!plus\zeropoint\relax
   \rightskip        \plusone\rightskip\s!plus\spac_align_set_raggedness_right\relax
   \spaceskip        \zeropoint\relax
   \xspaceskip       \zeropoint\relax
   \parfillleftskip  \zeropoint
   \parfillskip      \s_zero_plus_zero
  %\parindent        \parindent
   \relax}

\permanent\protected\def\spac_align_set_horizontal_extra
  {\xspaceskip\zeropoint\s!plus\v_spac_align_fill_amount_space\relax}

\def\spac_align_flush_horizontal
  {\ifcase\c_spac_align_state_horizontal
     % 0
     \spac_align_set_horizontal_none
   \or
     % 1 center
     \ifcase\c_spac_align_state_broad
       \spac_align_set_horizontal_center
     \or
       \spac_align_set_horizontal_very_center
     \or
       \spac_align_set_horizontal_wide_center
     \fi
   \or
     % 2 flush left
     \ifcase\c_spac_align_state_broad
       \spac_align_set_horizontal_right
     \else
       \spac_align_set_horizontal_very_right
     \fi
   \or
     % 3 flush right
     \ifcase\c_spac_align_state_broad
       \spac_align_set_horizontal_left
     \else
       \spac_align_set_horizontal_very_left
     \fi
   \or
     % 4 inner
     \ifdoublesided
       \signalinnerrealign
     \fi
     \rightorleftpageaction\spac_align_set_horizontal_right\spac_align_set_horizontal_left
   \or
     % 5 outer
     \ifdoublesided
       \signalouterrealign
     \fi
     \rightorleftpageaction\spac_align_set_horizontal_left\spac_align_set_horizontal_right
   \or
     % 6 oneliner
     \ifcase\c_spac_align_state_broad
       \spac_align_set_horizontal_right
     \else
       \spac_align_set_horizontal_very_right
     \fi
     \parfillskip\zeropoint
   \or
     % 7 centered last line
     \spac_align_set_horizontal_centered_last_line
   \or
     % 8 right aligned last line
     \spac_align_set_horizontal_flushedright_last_line
   \or
     % 9 paragraph
     \parfillskip\zeropoint
   \fi
   \relax}

% Page spacing:

\newconstant\c_spac_align_state_page

\mutable\def\bottomalignlimit{\plusthree\lineheight}

\newconstant\bottomraggednessmode % 0=ragged 1=normal/align 2=baseline

\permanent\protected\def\raggedbottom
  {\bottomraggednessmode\zerocount
   \settopskip}

\permanent\protected\def\alignbottom
  {\bottomraggednessmode\plusone
   \settopskip}

\permanent\protected\def\baselinebottom
  {\bottomraggednessmode\plustwo
   \settopskip}

\aliased\let\normalbottom\alignbottom % downward compatible

\permanent\protected\def\setbottomalignmode#1%
  {\bottomraggednessmode#1%
   \settopskip}

\def\spac_align_flush_page
  {\ifcase\c_spac_align_state_page
     % keep state
   \or
     \raggedbottom
   \or
     \alignbottom
   \or
     \baselinebottom
   \fi}

% Directions

\newconstant\c_spac_align_state_direction

\def\spac_align_flush_direction
  {\ifcase\c_spac_align_state_direction
    % keep state
   \or
     \lefttoright
   \or
     \righttoleft
   \fi}

% Interesting is that the non cached version is also pretty efficient
% and as we cache we seldom call that one now so one can debate the
% speedup.

\newtoks\t_spac_align_collected

\aliased\let\raggedcommand    \relax
\aliased\let\updateraggedskips\relax

\def\spac_align_add_to_cache
  {\enforced\let\raggedbox\relax % why
   % we inherit hyphenation and tolerance
   \t_spac_align_collected       \emptytoks
   \c_spac_align_state_broad     \zerocount
   \c_spac_align_state_horizontal\zerocount
   \c_spac_align_state_vertical  \zerocount
   \c_spac_align_state_direction \zerocount % what is default ?
   \c_spac_align_state_page      \zerocount
   \c_spac_align_state_par_fill  \zerocount
   \ifcsname\??aligncommand\m_spac_align_asked\endcsname
     \lastnamedcs
   \else
     \rawprocesscommacommand[\m_spac_align_asked]\spac_align_collect
   \fi
   \normalexpanded{\t_spac_align_collected
     {\setfalse\raggedonelinerstate % bad
      \the\t_spac_align_collected
      \spac_align_flush_horizontal
      \spac_align_flush_vertical
      \spac_align_flush_direction
      \spac_align_flush_page
      \spac_align_flush_parfill
      }}% kept, nice for tracing
   \enforced\permanent\protected\edef\raggedcommand    {\the\t_spac_align_collected }%
   \enforced\permanent\protected\edef\updateraggedskips{\spac_align_flush_horizontal}%
   \enforced\aliased\gletcsname\??alignmentnormalcache\m_spac_align_asked\endcsname\raggedcommand
   \enforced\aliased\gletcsname\??alignmentraggedcache\m_spac_align_asked\endcsname\updateraggedskips}

\def\spac_align_collect#1%
  {\csname\??aligncommand#1\endcsname}

% The local (key driven) setter:

\permanent\protected\def\spac_align_prepare#1% deferred
  {\edef\m_spac_align_asked{#1}%
   \enforced\aliased\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifrelax\raggedcommand
     \spac_align_add_to_cache
   \else
     \enforced\aliased\expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi}

\aliased\let\dosetraggedcommand\spac_align_prepare % sort of public

% The regular align setter:

\permanent\tolerant\protected\def\setupalign[#1]% immediate
  {\edef\m_spac_align_asked{#1}%
   \enforced\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifrelax\raggedcommand
     \spac_align_add_to_cache
   \else
     \enforced\aliased\expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi
   \raggedcommand}

\permanent\protected\def\usealignparameter#1% faster local variant
  {\edef\m_spac_align_asked{#1\c!align}%
   \ifempty\m_spac_align_asked\else
     \spac_align_use_indeed
   \fi}

\permanent\protected\def\dousealignparameter#1% faster local variant
  {\edef\m_spac_align_asked{#1}%
   \ifempty\m_spac_align_asked\else
     \spac_align_use_indeed
   \fi}

\def\spac_align_use_indeed
  {\enforced\aliased\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifrelax\raggedcommand
     \spac_align_add_to_cache
   \else
     \enforced\aliased\expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi
   \raggedcommand}

% experiment

\protected\def\spac_align_use_later#1%
  {\begingroup
   \edef\m_spac_align_asked{#1}%
   \enforced\aliased\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifrelax\raggedcommand
     \spac_align_add_to_cache
   \fi
   \endgroup}

\protected\def\spac_align_use_now#1%
  {\csname\??alignmentnormalcache#1\endcsname}

% Maybe we need something different in columns.

\permanent\protected\def\installalign#1#2% beware: commands must be unexpandable!
  {\ifcsname\??aligncommand#1\endcsname \else
     \defcsname\??aligncommand#1\endcsname{\toksapp\t_spac_align_collected{#2}}%
   \fi}

% The keywords:

\letcsname\??aligncommand\empty            \endcsname\empty
\defcsname\??aligncommand\v!broad          \endcsname{\c_spac_align_state_broad     \plusone  }
\defcsname\??aligncommand\v!wide           \endcsname{\c_spac_align_state_broad     \plustwo  }

\defcsname\??aligncommand\v!bottom         \endcsname{\c_spac_align_state_page      \plusone  }
\defcsname\??aligncommand\v!height         \endcsname{\c_spac_align_state_page      \plustwo  }
\defcsname\??aligncommand\v!line           \endcsname{\c_spac_align_state_page      \plusthree
                                                      % this will become another keyword (undocumented anyway)
                                                      \toksapp\t_spac_align_collected{\settrue\raggedonelinerstate}}

\defcsname\??aligncommand\v!high           \endcsname{\c_spac_align_state_vertical  \plusthree}
\defcsname\??aligncommand\v!low            \endcsname{\c_spac_align_state_vertical  \plustwo  }
\defcsname\??aligncommand\v!lohi           \endcsname{\c_spac_align_state_vertical  \plusone  }

\defcsname\??aligncommand\v!flushright     \endcsname{\c_spac_align_state_horizontal\plusthree}
\defcsname\??aligncommand\v!flushleft      \endcsname{\c_spac_align_state_horizontal\plustwo  }
\defcsname\??aligncommand\v!middle         \endcsname{\c_spac_align_state_horizontal\plusone  }
\defcsname\??aligncommand\v!no             \endcsname{\c_spac_align_state_horizontal\plustwo  }
\defcsname\??aligncommand\v!yes            \endcsname{\c_spac_align_state_horizontal\zerocount}
\defcsname\??aligncommand\v!width          \endcsname{\c_spac_align_state_horizontal\zerocount}
\defcsname\??aligncommand\v!normal         \endcsname{\c_spac_align_state_horizontal\zerocount}
\defcsname\??aligncommand\v!reset          \endcsname{\c_spac_align_state_page      \zerocount
                                                      \c_spac_align_state_horizontal\zerocount}
\defcsname\??aligncommand\v!inner          \endcsname{\c_spac_align_state_horizontal\plusfour }
\defcsname\??aligncommand\v!outer          \endcsname{\c_spac_align_state_horizontal\plusfive }
\defcsname\??aligncommand\v!flushinner     \endcsname{\c_spac_align_state_horizontal\plusfour }
\defcsname\??aligncommand\v!flushouter     \endcsname{\c_spac_align_state_horizontal\plusfive }
\defcsname\??aligncommand\v!right          \endcsname{\c_spac_align_state_horizontal\plustwo  }
\defcsname\??aligncommand\v!left           \endcsname{\c_spac_align_state_horizontal\plusthree}
\defcsname\??aligncommand\v!center         \endcsname{\c_spac_align_state_horizontal\plusone
                                                      \c_spac_align_state_broad     \plustwo  }
\defcsname\??aligncommand\v!disable        \endcsname{\c_spac_align_state_horizontal\plussix  }
\defcsname\??aligncommand\v!last           \endcsname{\c_spac_align_state_horizontal\plusseven}
\defcsname\??aligncommand\v!end            \endcsname{\c_spac_align_state_horizontal\pluseight}
\defcsname\??aligncommand\v!paragraph      \endcsname{\c_spac_align_state_horizontal\plusnine}

\defcsname\??aligncommand\v!lefttoright    \endcsname{\c_spac_align_state_direction \plusone  }
\defcsname\??aligncommand\v!righttoleft    \endcsname{\c_spac_align_state_direction \plustwo  }
\defcsname\??aligncommand               l2r\endcsname{\c_spac_align_state_direction \plusone  }
\defcsname\??aligncommand               r2l\endcsname{\c_spac_align_state_direction \plustwo  }

\defcsname\??aligncommand\v!table          \endcsname{\c_spac_align_state_vertical  \plusthree
                                                      \c_spac_align_state_broad     \plusone
                                                      \c_spac_align_state_horizontal\plustwo  }

\defcsname\??aligncommand\v!lesshyphenation\endcsname{\toksapp\t_spac_align_collected{\lesshyphens}}
\defcsname\??aligncommand\v!morehyphenation\endcsname{\toksapp\t_spac_align_collected{\morehyphens}}

\defcsname\??aligncommand\v!hanging        \endcsname{\toksapp\t_spac_align_collected{\font_protruding_enable }}
\defcsname\??aligncommand\v!hangingboth    \endcsname{\toksapp\t_spac_align_collected{\font_protruding_enable_b}}
\defcsname\??aligncommand\v!nothanging     \endcsname{\toksapp\t_spac_align_collected{\font_protruding_disable}}
\defcsname\??aligncommand\v!hz             \endcsname{\toksapp\t_spac_align_collected{\font_expansion_enable  }}
\defcsname\??aligncommand\v!fullhz         \endcsname{\toksapp\t_spac_align_collected{\font_expansion_enable_k}}
\defcsname\??aligncommand\v!nohz           \endcsname{\toksapp\t_spac_align_collected{\font_expansion_disable }}
%defcsname\??aligncommand\v!spacing        \endcsname{\toksapp\t_spac_align_collected{\normalspacing\zerocount}} % not yet
%defcsname\??aligncommand\v!nospacing      \endcsname{\toksapp\t_spac_align_collected{\normalspacing\plusone}}   % not yet
\defcsname\??aligncommand\v!hyphenated     \endcsname{\toksapp\t_spac_align_collected{\dohyphens}}
\defcsname\??aligncommand\v!nothyphenated  \endcsname{\toksapp\t_spac_align_collected{\nohyphens}}
\defcsname\??aligncommand\v!collapsed      \endcsname{\toksapp\t_spac_align_collected{\dohyphencollapsing}}
\defcsname\??aligncommand\v!notcollapsed   \endcsname{\toksapp\t_spac_align_collected{\nohyphencollapsing}}

\defcsname\??aligncommand\v!tolerant       \endcsname{\toksapp\t_spac_align_collected{\spac_align_set_tolerant}}
\defcsname\??aligncommand\v!verytolerant   \endcsname{\toksapp\t_spac_align_collected{\spac_align_set_very_tolerant}}
\defcsname\??aligncommand\v!stretch        \endcsname{\toksapp\t_spac_align_collected{\spac_align_set_stretch}}
\defcsname\??aligncommand\v!extremestretch \endcsname{\toksapp\t_spac_align_collected{\spac_align_set_extreme_stretch}}

\defcsname\??aligncommand          \v!final\endcsname{\c_spac_align_state_par_fill\plusone}
\defcsname\??aligncommand        1*\v!final\endcsname{\c_spac_align_state_par_fill\plusone}
\defcsname\??aligncommand        2*\v!final\endcsname{\c_spac_align_state_par_fill\plustwo}      % hardcoded multiplier
\defcsname\??aligncommand        3*\v!final\endcsname{\c_spac_align_state_par_fill\plusthree}
\defcsname\??aligncommand        4*\v!final\endcsname{\c_spac_align_state_par_fill\plusfour}

% a one shot (only usefull in e.g. framed, also needs tolerance and stretch)

\defcsname\??aligncommand          \v!more\endcsname{\toksapp\t_spac_align_collected{\looseness\plusone}}
\defcsname\??aligncommand        1*\v!more\endcsname{\toksapp\t_spac_align_collected{\looseness\plusone}}
\defcsname\??aligncommand        2*\v!more\endcsname{\toksapp\t_spac_align_collected{\looseness\plustwo}}

%defcsname\??aligncommand ...\endcsname{\toksapp\t_spac_align_collected{\nopenalties}}
%defcsname\??aligncommand ...\endcsname{\toksapp\t_spac_align_collected{\setdefaultpenalties}}

% experiment

\defcsname\??aligncommand\v!always\endcsname{\toksapp\t_spac_align_collected{\bitwiseflip\hyphenationmode\forcecheckhyphenationmodecode}}

\definehspace [\v!final] [\emspaceamount]

\def\spac_align_flush_parfill
  {\ifcase\c_spac_align_state_par_fill\else
     \spac_align_flush_parfill_indeed{\number\c_spac_align_state_par_fill}%
   \fi}

\protected\def\spac_align_flush_parfill_indeed#1%
  {\parfillskip
     #1\directhspaceamount\v!final
   % plus \dimexpr\availablehsize-#1\directhspaceamount\v!final\relax
     plus 1fill
   \relax}

%D For Wolfgang:

\newtoks \t_spac_every_swap_align

\appendtoks
    \defcsname\??aligncommand\v!right\endcsname{\c_spac_align_state_horizontal\plusthree}%
    \defcsname\??aligncommand\v!left \endcsname{\c_spac_align_state_horizontal\plustwo  }%
\to \t_spac_every_swap_align

\permanent\protected\def\enablereversealignment
  {\the\t_spac_every_swap_align
   \t_spac_every_swap_align\emptytoks}

% Visible commands:

\aliased\let\notragged           \spac_align_set_horizontal_none
\aliased\let\raggedleft          \spac_align_set_horizontal_left
\aliased\let\raggedcenter        \spac_align_set_horizontal_center
\aliased\let\raggedright         \spac_align_set_horizontal_right
\aliased\let\veryraggedleft      \spac_align_set_horizontal_very_left
\aliased\let\veryraggedcenter    \spac_align_set_horizontal_very_center
\aliased\let\veryraggedright     \spac_align_set_horizontal_very_right
\aliased\let\raggedwidecenter    \spac_align_set_horizontal_wide_center
\aliased\let\centeredlastline    \spac_align_set_horizontal_centered_last_line
\aliased\let\flushedrightlastline\spac_align_set_horizontal_flushedright_last_line
\aliased\let\ttraggedright       \spac_align_set_horizontal_right_tt            % a plain command
\aliased\let\forgetragged        \spac_align_set_horizontal_none

\appendtoks
    \spac_align_set_horizontal_none
\to \everyforgetall

% Box commands.

\permanent\protected\def\ibox
  {\vbox\bgroup
     \forgetall
     \enforced\let\\\endgraf
     \ifdoublesided\signalinnerrealign\fi
     \doifelserightpage\spac_align_set_horizontal_right\spac_align_set_horizontal_left
     \let\next}

\permanent\protected\def\obox
  {\vbox\bgroup
     \forgetall
     \enforced\let\\\endgraf
     \ifdoublesided\signalouterrealign\fi
     \doifelserightpage\spac_align_set_horizontal_left\spac_align_set_horizontal_right
     \let\next}

\let\raggedbox\relax

\permanent\protected\def\dosetraggedvbox#1% can be more keys .. how about caching here (but seldom used)
  {\enforced\let\raggedbox\vbox
   \processcommacommand[#1]\spac_align_set_ragged_vbox}

\permanent\protected\def\dosetraggedhbox#1% can be more keys .. how about caching here (but seldom used)
  {\enforced\let\raggedbox\hbox
   \processcommacommand[#1]\spac_align_set_ragged_hbox}

\def\spac_align_set_ragged_vbox#1%
  {\ifcsname\??alignvertical#1\endcsname
     \lastnamedcs
     \quitcommalist
   \fi}

\def\spac_align_set_ragged_hbox#1%
  {\ifcsname\??alignhorizontal#1\endcsname
     \lastnamedcs
     \quitcommalist
   \fi}

\permanent\protected\def\spac_align_vertical_left      {\lbox}
\permanent\protected\def\spac_align_vertical_right     {\rbox}
\permanent\protected\def\spac_align_vertical_middle    {\cbox}
\permanent\protected\def\spac_align_vertical_inner     {\ibox}
\permanent\protected\def\spac_align_vertical_outer     {\obox}
\permanent\protected\def\spac_align_vertical_flushleft {\rbox}
\permanent\protected\def\spac_align_vertical_flushright{\lbox}
\permanent\protected\def\spac_align_vertical_center    {\cbox}
\permanent\protected\def\spac_align_vertical_no        {\vbox\bgroup\spac_align_set_horizontal_right\let\next=}

\permanent\protected\def\spac_align_horizontal_left      {\doalignedline\v!left}
\permanent\protected\def\spac_align_horizontal_right     {\doalignedline\v!right}
\permanent\protected\def\spac_align_horizontal_middle    {\doalignedline\v!middle}
\permanent\protected\def\spac_align_horizontal_inner     {\doalignedline\v!inner}
\permanent\protected\def\spac_align_horizontal_outer     {\doalignedline\v!outer}
\permanent\protected\def\spac_align_horizontal_flushleft {\doalignedline\v!right}
\permanent\protected\def\spac_align_horizontal_flushright{\doalignedline\v!left}
\permanent\protected\def\spac_align_horizontal_center    {\doalignedline\v!middle}

\defcsname\??alignvertical  \v!left      \endcsname{\enforced\let\raggedbox\spac_align_vertical_left}
\defcsname\??alignvertical  \v!right     \endcsname{\enforced\let\raggedbox\spac_align_vertical_right}
\defcsname\??alignvertical  \v!middle    \endcsname{\enforced\let\raggedbox\spac_align_vertical_middle}
\defcsname\??alignvertical  \v!inner     \endcsname{\enforced\let\raggedbox\spac_align_vertical_inner}
\defcsname\??alignvertical  \v!outer     \endcsname{\enforced\let\raggedbox\spac_align_vertical_outer}
\defcsname\??alignvertical  \v!flushleft \endcsname{\enforced\let\raggedbox\spac_align_vertical_flushleft }
\defcsname\??alignvertical  \v!flushright\endcsname{\enforced\let\raggedbox\spac_align_vertical_flushright}
\defcsname\??alignvertical  \v!center    \endcsname{\enforced\let\raggedbox\spac_align_vertical_center}
\defcsname\??alignvertical  \v!no        \endcsname{\enforced\let\raggedbox\spac_align_vertical_no}

\defcsname\??alignhorizontal\v!left      \endcsname{\enforced\let\raggedbox\spac_align_horizontal_left}
\defcsname\??alignhorizontal\v!right     \endcsname{\enforced\let\raggedbox\spac_align_horizontal_right}
\defcsname\??alignhorizontal\v!middle    \endcsname{\enforced\let\raggedbox\spac_align_horizontal_middle}
\defcsname\??alignhorizontal\v!inner     \endcsname{\enforced\let\raggedbox\spac_align_horizontal_inner}
\defcsname\??alignhorizontal\v!outer     \endcsname{\enforced\let\raggedbox\spac_align_horizontal_outer}
\defcsname\??alignhorizontal\v!flushleft \endcsname{\enforced\let\raggedbox\spac_align_horizontal_flushleft}
\defcsname\??alignhorizontal\v!flushright\endcsname{\enforced\let\raggedbox\spac_align_horizontal_flushright}
\defcsname\??alignhorizontal\v!center    \endcsname{\enforced\let\raggedbox\spac_align_horizontal_center}

% The next one can be in use so we keep it around but oen should
% be aware of possible interference.

\permanent\protected\def\setraggedskips#1#2#3#4#5#6#7% never change this name (todo: inline this one .. less tracingall)
  {\enforced\permanent\protected\def\updateraggedskips{\dosetraggedskips{#1}{#2}{#3}{#4}{#5}{#6}{#7}}%
   \updateraggedskips}

\permanent\protected\def\dosetraggedskips#1#2#3#4#5#6#7%
  {\raggedstatus                 #1\relax
   \leftskip   1\leftskip \s!plus#2\relax
   \rightskip  1\rightskip\s!plus#3\relax
   \spaceskip                    #4\relax
   \xspaceskip                   #5\relax
   \parfillskip \zeropoint\s!plus#6\relax
   \parindent                    #7\relax
   \c_attr_alignstate\ifcase\raggedstatus\attributeunsetvalue\else\raggedstatus\fi}

% older (context) names:

\aliased\let\spaceamount  \interwordspace
\aliased\let\emspaceamount\emwidth

% tracing:

\def\spac_show_par_data#1%
  {\ifrelax#1\else
     \hbox{\string#1: \the#1}\endgraf
     \expandafter\spac_show_par_data
   \fi}

\permanent\protected\def\showpardata
  {\normalexpanded{\dontleavehmode\inleftmargin{\vsmash{\infofont\framed[\c!align=\v!right]{%
     \hbox{font: \fontname\font}\endgraf
     \spac_show_par_data
       \interwordspace \interwordstretch \interwordshrink \emwidth \exheight \extraspace
       \hsize     \vsize
       \leftskip  \rightskip
       \spaceskip \xspaceskip
       \parindent \parfillskip
       \hyphenpenalty \exhyphenpenalty \automatichyphenpenalty \explicithyphenpenalty
       \displaywidowpenalty \widowpenalty \clubpenalty \brokenpenalty
       \doublehyphendemerits \finalhyphendemerits \adjdemerits
   \relax}}}}}

\permanent\protected\def\startshowpardata
  {\begingroup
   \showstruts
   \tracingparagraphs\maxdimen
   \appendtoksonce\showpardata\to\everypar}

\permanent\protected\def\stopshowpardata
  {\endgraf
   \endgroup}

% Structure:

\protected\def\startalignment
  {\par
   \begingroup
   \setupalign}

\protected\def\stopalignment
  {\par
   \endgroup}

\setnewconstant\alignstrutmode\plusone

% see later for the real definition, which in the simple case is:

\newtoks \everyleftofalignedline
\newtoks \everyrightofalignedline

\permanent\protected\def\shiftalignedline#1#2#3#4% left, right, inner, outer
  {\rightorleftpageaction
     {\everyleftofalignedline {\hskip\dimexpr#1+#3\relax}%
      \everyrightofalignedline{\hskip\dimexpr#2+#4\relax}}
     {\everyleftofalignedline {\hskip\dimexpr#1+#4\relax}%
      \everyrightofalignedline{\hskip\dimexpr#2+#3\relax}}}

\permanent\protected\def\doalignline#1#2% \\ == newline
  {\noindentation  % was \noindent
   \dontleavehmode % added in marrakesch at TUG 2006\begingroup
   \begingroup
   \setlocalhsize % new
   \enforced\permanent\protected\def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
   \dowithnextbox
     {\hbox to \localhsize
        {\ifcase\alignstrutmode\or\strut\fi
         \the\everyleftofalignedline
         #1\unhbox\nextbox#2\relax
         \the\everyrightofalignedline}%
      \endgroup}
     \hbox}

% plain commands

\ifdefined\line       \else \permanent\protected\def\line        {\hbox to\hsize}    \fi
\ifdefined\leftline   \else \permanent\protected\def\leftline  #1{\line{#1\hss}}     \fi
\ifdefined\rightline  \else \permanent\protected\def\rightline #1{\line{\hss#1}}     \fi
\ifdefined\centerline \else \permanent\protected\def\centerline#1{\line{\hss#1\hss}} \fi

% direct commands

\installcorenamespace{alignwrapper}

\protected\defcsname\??alignwrapper\v!left  \endcsname{\doalignline\relax \hss  }
\protected\defcsname\??alignwrapper\v!middle\endcsname{\doalignline\hss   \hss  }
\protected\defcsname\??alignwrapper\v!right \endcsname{\doalignline\hss   \relax}
\protected\defcsname\??alignwrapper\v!max   \endcsname{\doalignline\relax \relax}

\def\spac_align_wrapper_middle{\doalignline\hss\hss}

\def\spac_align_wrapper_handle#1%
  {\ifcsname\??alignwrapper#1\endcsname\expandafter\lastnamedcs\else\expandafter\spac_align_wrapper_middle\fi}

\permanent\tolerant\protected\def\startlinealignment[#1]%
  {\spac_align_wrapper_handle{#1}%
   \bgroup\ignorespaces}

\protected\def\spac_align_wrapper_stop
  {\removeunwantedspaces\egroup}

\permanent\let\stoplinealignment\spac_align_wrapper_stop

\permanent\protected\def\startleftaligned  {\startlinealignment[\v!left  ]}  \permanent\let\stopleftaligned  \spac_align_wrapper_stop
\permanent\protected\def\startmiddlealigned{\startlinealignment[\v!middle]}  \permanent\let\stopmiddlealigned\spac_align_wrapper_stop
\permanent\protected\def\startrightaligned {\startlinealignment[\v!right ]}  \permanent\let\stoprightaligned \spac_align_wrapper_stop
\permanent\protected\def\startmaxaligned   {\startlinealignment[\v!max   ]}  \permanent\let\stopmaxaligned   \spac_align_wrapper_stop

\aliased\let\startmidaligned   \startmiddlealigned  \aliased\let\stopmidaligned   \stopmiddlealigned
\aliased\let\startcenteraligned\startmiddlealigned  \aliased\let\stopcenteraligned\stopmiddlealigned

\permanent\protected\def\leftaligned  {\spac_align_wrapper_handle\v!left  }
\permanent\protected\def\middlealigned{\spac_align_wrapper_handle\v!middle}
\permanent\protected\def\rightaligned {\spac_align_wrapper_handle\v!right }
\permanent\protected\def\maxaligned   {\spac_align_wrapper_handle\v!max   }

\aliased\let\midaligned   \middlealigned
\aliased\let\centeraligned\middlealigned

\installcorenamespace{alignline}

\letcsname\??alignline\v!left      \endcsname\leftaligned
\letcsname\??alignline\v!right     \endcsname\rightaligned
\letcsname\??alignline\v!middle    \endcsname\midaligned
\letcsname\??alignline\v!flushleft \endcsname\rightaligned % beware, makes no sense in locations / we will have a special locations handler
\letcsname\??alignline\v!flushright\endcsname\leftaligned  % beware, makes no sense in locations / we will have a special locations handler
\letcsname\??alignline\v!center    \endcsname\midaligned
\letcsname\??alignline\v!max       \endcsname\maxaligned

%D Experimental (will be redone when floats are redone as it's real messy
%D now). It can also be made faster (if needed).

\permanent\protected\def\doxalignline#1#2#3#4#5#6%
  {\noindentation  % was \noindent
   \dontleavehmode % added in marrakesch at TUG 2006\begingroup
   \begingroup
   \setlocalhsize
   \enforced\permanent\protected\def\\{\egroup\par\doxalignline#1#2#3#4#5#6\bgroup}% inefficient
   \dowithnextbox
     {\hbox to \localhsize
        {#1\hskip\ifdone#2\else#3\fi#4%
         \hbox to \localhsize
           {\the\everyleftofalignedline
            \ifcase\alignstrutmode\or\strut\fi
            \ifdone#5\unhbox\nextbox#6\else#6\unhbox\nextbox#5\fi
            \the\everyrightofalignedline}%
         \hss}%
        \endgroup}
     \hbox}

\permanent\protected\def\doxcheckline % used for floats so multipass anyway
  {\signalrightpage\doifelserightpage\donetrue\donefalse}

\defcsname\??alignline\v!inner      \endcsname{\doxalignline\doxcheckline++\zeropoint       \relax\hss  }
\defcsname\??alignline\v!outer      \endcsname{\doxalignline\doxcheckline++\zeropoint       \hss  \relax}
\defcsname\??alignline\v!innermargin\endcsname{\doxalignline\doxcheckline-+\innermargintotal\relax\hss  }
\defcsname\??alignline\v!outermargin\endcsname{\doxalignline\doxcheckline+-\outermargintotal\hss  \relax}
\defcsname\??alignline\v!inneredge  \endcsname{\doxalignline\doxcheckline-+\inneredgetotal  \relax\hss  }
\defcsname\??alignline\v!outeredge  \endcsname{\doxalignline\doxcheckline+-\outeredgetotal  \hss  \relax}
\defcsname\??alignline\v!backspace  \endcsname{\doxalignline\doxcheckline-+\backspace       \relax\hss  }
\defcsname\??alignline\v!cutspace   \endcsname{\doxalignline\doxcheckline+-\cutspace        \hss  \relax}

\defcsname\??alignline\v!leftmargin \endcsname{\doxalignline\donefalse   --\leftmargintotal \hss  \relax}
\defcsname\??alignline\v!rightmargin\endcsname{\doxalignline\donefalse   ++\rightmargintotal\relax\hss  }
\defcsname\??alignline\v!leftedge   \endcsname{\doxalignline\donefalse   --\leftedgetotal   \hss  \relax}
\defcsname\??alignline\v!rightedge  \endcsname{\doxalignline\donefalse   ++\rightedgetotal  \relax\hss  }

\permanent\protected\def\doalignedline#1{\begincsname\??alignline#1\endcsname}

\permanent\protected\def\alignedline#1#2% setting default
  {\ifcsname\??alignline#1\endcsname
     \expandafter\lastnamedcs
   \else
     \csname\??alignline#2\expandafter\endcsname
   \fi}

% beware: \wordright{whatever\kern-\rightskip} should work!
% so, no funny boxing here

%D We need to pick up a box (downward compatible in case \type {\bgroup}
%D is used (test suite index example).

\permanent\tolerant\protected\def\wordright[#1]%
  {\dowithnextbox
     {\normalexpanded{\spac_word_right_indeed{#1}{\hpack{\thebox\nextbox}}}}
     \hbox}

\protected\def\spac_word_right_indeed#1#2%
  {\registerparwrapper
     {\v!word:\v!right}
     {\begingroup
      \frozen\parfillskip        \zeropoint
      \frozen\finalhyphendemerits\zerocount
      \endgroup}
     {\doifelseparwrapper{\v!word:\v!right}%
        {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
         \strut \removeunwantedspaces
         \hfill
         \allowbreak % changed back from \hskip\zeropoint
         \quad}%
        {\allowbreak % changed back from \hskip\zeropoint
         \break}%
      \unregisterparwrapper{\v!word:\v!right}%
      \strut
      \hfill
      \nobreak
      #2%
      \allowbreak}}

% \dorecurse{5}{something} \wordright{--someone} \endgraf
% \dorecurse{6}{something} \wordright{--someone} \endgraf
% \dorecurse{7}{something} \wordright{--someone} \endgraf
%
% \dorecurse{5}{something} \wordright{--someone else entirely} \endgraf
% \dorecurse{6}{something} \wordright{--someone else entirely} \endgraf
% \dorecurse{7}{something} \wordright{--someone else entirely} \endgraf
%
% \wordright[\rightskip]{whatever}

% Trick posted by WS on mailing list, generalized a bit. The bottom text only shows
% op when there is one line space available. We could add some extra space if needed.

% v\protected\def\bottomword
%   {\par
%    \dowithnextbox
%      {\leaders\box\nextbox\vfil\page}
%      \vbox to \lineheight}
%
% \permanent\protected\def\bottomword
%   {\par
%    \groupedcommand
%      {\leaders
%       \vbox to \lineheight\bgroup}
%      {\egroup
%       \vfil
%       \page}}

% \simplealignedbox{2cm}{right}{x}

\installcorenamespace{alignsimple}
\installcorenamespace{alignsimplereverse}

% todo: also handle \bgroup ... \egroup

\protected\def\spac_align_simple_left  #1{{#1\hss}}
\protected\def\spac_align_simple_right #1{{\hss#1}}
\protected\def\spac_align_simple_middle#1{{\hss#1\hss}}

\letcsname\??alignsimple       \v!right     \endcsname\spac_align_simple_left
\letcsname\??alignsimple       \v!outer     \endcsname\spac_align_simple_left   % not managed! see linenumbers
\letcsname\??alignsimple       \v!flushleft \endcsname\spac_align_simple_left
\letcsname\??alignsimple       \v!left      \endcsname\spac_align_simple_right
\letcsname\??alignsimple       \v!inner     \endcsname\spac_align_simple_right  % not managed! see linenumbers
\letcsname\??alignsimple       \v!flushright\endcsname\spac_align_simple_right
\letcsname\??alignsimple       \v!middle    \endcsname\spac_align_simple_middle

\letcsname\??alignsimplereverse\v!right     \endcsname\spac_align_simple_right
\letcsname\??alignsimplereverse\v!outer     \endcsname\spac_align_simple_right % not managed! see linenumbers
\letcsname\??alignsimplereverse\v!flushleft \endcsname\spac_align_simple_right
\letcsname\??alignsimplereverse\v!left      \endcsname\spac_align_simple_left
\letcsname\??alignsimplereverse\v!inner     \endcsname\spac_align_simple_left  % not managed! see linenumbers
\letcsname\??alignsimplereverse\v!flushright\endcsname\spac_align_simple_left
\letcsname\??alignsimplereverse\v!middle    \endcsname\spac_align_simple_middle

\permanent\protected\def\simplealignedbox#1#2%
  {\hbox \ifdim#1>\zeropoint to #1
     \ifcsname\??alignsimple#2\endcsname
       \doubleexpandafter\lastnamedcs
     \else
       \doubleexpandafter\spac_align_simple_left
     \fi
   \fi}

\permanent\protected\def\simplealignedspreadbox#1#2%
  {\hbox \ifdim#1>\zeropoint spread #1
     \ifcsname\??alignsimple#2\endcsname
       \doubleexpandafter\lastnamedcs
     \else
       \doubleexpandafter\spac_align_simple_left
     \fi
   \fi}

\permanent\protected\def\simplealignedboxplus#1#2#3%
  {\hbox #3 \ifdim#1>\zeropoint to #1
     \ifcsname\??alignsimple#2\endcsname
       \doubleexpandafter\lastnamedcs
     \else
       \doubleexpandafter\spac_align_simple_left
     \fi
   \fi}

\newconditional\alignsimplelefttoright \settrue\alignsimplelefttoright

\permanent\protected\def\simplereversealignedbox#1#2%
  {\hbox \ifdim#1>\zeropoint to #1
     \ifcsname\??alignsimplereverse#2\endcsname
       \doubleexpandafter\lastnamedcs
     \else
       \doubleexpandafter\spac_align_simple_left
     \fi
   \fi}

\permanent\protected\def\simplereversealignedboxplus#1#2#3%
  {\hbox #3 \ifdim#1>\zeropoint to #1
     \ifcsname\??alignsimplereverse#2\endcsname
       \doubleexpandafter\lastnamedcs
     \else
       \doubleexpandafter\spac_align_simple_left
     \fi
   \fi}

% Some obsolete (old) helpers:

\permanent\tolerant\protected\def\definehbox[#1]#*[#2]%
  {\ifarguments\else\frozen\instance\protected\defcsname hbox#1\endcsname##1{\hbox to #2{\begstrut##1\endstrut\hss}}\fi}

%D Some direction related helpers:

\installcorenamespace {reverse}

\defcsname\??reverse\v!normal \endcsname{\ifconditional\inlinelefttoright\else\s!reverse\fi}
\defcsname\??reverse\v!reverse\endcsname{\ifconditional\inlinelefttoright     \s!reverse\fi}

\permanent\def\usedirectionparameterreverse#1{\begincsname\??reverse#1\c!direction\endcsname}

%D Now official:

\permanent\protected\def\spaceorpar{\endgraf\ifhmode\space\fi}

\protect \endinput
