spac-ali.mkiv / last modification: 2020-01-30 14:16
%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
%D {flush*} variants. Starting at the last day of 2011 both methods are
%D merged into one and caching has been added, which makes switching
%D twice as fast.

% Todo: find a way to force last lines to have some distance from the right
% edge (problem: keywords or presets), maybe a plugin
%
% \setupalign[...,myoption] % last
%
% but that also means myoption gets frozen due to caching.

\registerctxluafile{spac-ali}{optimize}

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

\appendtoks
    \attribute\realignattribute   \attributeunsetvalue
    \attribute\alignstateattribute\attributeunsetvalue
\to \everyforgetall

\unexpanded\def\resetrealignsignal{\attribute\realignattribute\attributeunsetvalue}
\unexpanded\def\signalinnerrealign{\clf_setrealign\plustwo}
\unexpanded\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}

\def\??alignmentnormalcache{\ifodd\realpageno\??alignmentnormalcacheodd\else\??alignmentnormalcacheeven\fi}
\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

\unexpanded\def\lefttoright
  {\ifvmode
     \spac_directions_lefttoright_vmode
   \else
     \spac_directions_lefttoright_hmode
   \fi}

\unexpanded\def\righttoleft
  {\ifvmode
     \spac_directions_righttoleft_vmode
   \else
     \spac_directions_righttoleft_hmode
   \fi}

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

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

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

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

\unexpanded\def\synchronizelayoutdirection
  {\ifconditional\layoutlefttoright
     \spac_directions_synchronize_lr
   \else
     \spac_directions_synchronize_rl
   \fi}

\unexpanded\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}

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

\unexpanded\def\checkedlefttoright
  {\ifvmode
     \spac_directions_lefttoright_vmode
   \else
     \spac_directions_lefttoright_hmode_checked
   \fi}

\unexpanded\def\checkedrighttoleft
  {\ifvmode
     \spac_directions_righttoleft_vmode
   \else
     \spac_directions_righttoleft_hmode_checked
   \fi}

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

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

\installcorenamespace{bidi}

\letvalue{\??bidi\v!left }\checkedlefttoright \letvalue{\??bidi l2r}\checkedlefttoright
\letvalue{\??bidi\v!right}\checkedrighttoleft \letvalue{\??bidi r2l}\checkedrighttoleft

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

\unexpanded\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}

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

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

\unexpanded\def\leftorrighthbox{\ifconditional\displaylefttoright\expandafter\lefttorighthbox\else\expandafter\righttolefthbox\fi}
\unexpanded\def\leftorrightvbox{\ifconditional\displaylefttoright\expandafter\lefttorightvbox\else\expandafter\righttoleftvbox\fi}
\unexpanded\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}

\unexpanded\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
   \ifx\dohyphens\relax % 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}

\unexpanded\def\spac_align_set_tolerant
  {\tolerance\c_spac_tolerance_normal}

\unexpanded\def\spac_align_set_very_tolerant
  {\tolerance\c_spac_tolerance_extreme}

\unexpanded\def\spac_align_set_stretch
  {\emergencystretch\bodyfontsize}

\unexpanded\def\spac_align_set_extreme_stretch
  {\emergencystretch10\bodyfontsize}

% Vertical

\newconstant\c_spac_align_state_vertical

\unexpanded\def\spac_align_set_vertical_none
  {\let\raggedtopcommand   \relax
   \let\raggedbottomcommand\relax}

\unexpanded\def\spac_align_set_vertical_lohi
  {\let\raggedtopcommand   \vfilll
   \let\raggedbottomcommand\vfilll}

\unexpanded\def\spac_align_set_vertical_low
  {\let\raggedtopcommand   \vfilll
   \let\raggedbottomcommand\relax}

\unexpanded\def\spac_align_set_vertical_high
  {\let\raggedtopcommand   \relax
   \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

\unexpanded\def\spac_align_set_horizontal_none % should also relax \updateraggedskips
  {\raggedstatus\zerocount
   \attribute\alignstateattribute\attributeunsetvalue
   \leftskip   \plusone\leftskip
   \rightskip  \plusone\rightskip
   \spaceskip  \zeropoint
   \xspaceskip \zeropoint
   \parfillskip\s_zero_plus_one_fil % new
   \setfalse\raggedonelinerstate    % now here
   \let\updateraggedskips\relax}    % no need for adaption

\unexpanded\def\spac_align_set_horizontal_left
  {\setraggedness\spac_align_set_raggedness_left
   \raggedstatus\plusone
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_center
  {\setraggedness\spac_align_set_raggedness_middle
   \raggedstatus\plustwo
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_right
  {\setraggedness\spac_align_set_raggedness_right
   \raggedstatus\plusthree
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_one_fil
  %\parindent  \parindent
   \relax}

\unexpanded\def\spac_align_set_horizontal_very_left
  {\raggedstatus\plusone
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_very_center
  {\raggedstatus\plustwo
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_very_right
  {\raggedstatus\plusthree
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
  %\parindent  \parindent
   \relax}

\unexpanded\def\spac_align_set_horizontal_wide_center
  {\setraggedness\spac_align_set_raggedness_middle
   \raggedstatus\plustwo
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_centered_last_line
  {\raggedstatus\zerocount
   \attribute\alignstateattribute\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\s!plus\v_spac_align_fill_amount_double\relax
   \parindent  \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_flushedright_last_line
  {\raggedstatus\zerocount
   \attribute\alignstateattribute\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
   \parfillleftmode\plustwo % \plusone checks for multiple lines
   \parindent      \zeropoint
   \relax}

\unexpanded\def\spac_align_set_horizontal_right_tt % a plain command
  {\tttf % brrr
   \raggedstatus\plusthree
   \attribute\alignstateattribute\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
   \parfillskip\s_zero_plus_zero
  %\parindent  \parindent
   \relax}

\unexpanded\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

\def\bottomalignlimit{\plusthree\lineheight}

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

\unexpanded\def\raggedbottom
  {\bottomraggednessmode\zerocount
   \settopskip}

\unexpanded\def\alignbottom
  {\bottomraggednessmode\plusone
   \settopskip}

\unexpanded\def\baselinebottom
  {\bottomraggednessmode\plustwo
   \settopskip}

\let\normalbottom\alignbottom % downward compatible

\unexpanded\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

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

\def\spac_align_add_to_cache
  {\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
     {% \resetrealignsignal % can go as it is always set
      \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
   \edef\raggedcommand    {\the\t_spac_align_collected }%
   \edef\updateraggedskips{\spac_align_flush_horizontal}%
   \expandafter\glet\csname\??alignmentnormalcache\m_spac_align_asked\endcsname\raggedcommand
   \expandafter\glet\csname\??alignmentraggedcache\m_spac_align_asked\endcsname\updateraggedskips}

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

% The local (key driven) setter:

\unexpanded\def\spac_align_prepare#1% deferred
  {\edef\m_spac_align_asked{#1}%
   \expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifx\raggedcommand\relax
     \spac_align_add_to_cache
   \else
     \expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi}

\let\dosetraggedcommand\spac_align_prepare % sort of public

% The regular align setter:

\unexpanded\def\setupalign
  {\dosingleempty\spac_align_setup}

\def\spac_align_setup[#1]% immediate
  {\edef\m_spac_align_asked{#1}%
   \expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifx\raggedcommand\relax
     \spac_align_add_to_cache
   \else
     \expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi
   \raggedcommand}

\unexpanded\def\usealignparameter#1% faster local variant
  {\edef\m_spac_align_asked{#1\c!align}%
   \ifx\m_spac_align_asked\empty\else
     \spac_align_use_indeed
   \fi}

\unexpanded\def\dousealignparameter#1% faster local variant
  {\edef\m_spac_align_asked{#1}%
   \ifx\m_spac_align_asked\empty\else
     \spac_align_use_indeed
   \fi}

\def\spac_align_use_indeed
  {\expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifx\raggedcommand\relax
     \spac_align_add_to_cache
   \else
     \expandafter\let\expandafter\updateraggedskips\csname\??alignmentraggedcache\m_spac_align_asked\endcsname
   \fi
   \raggedcommand}

% experiment

\unexpanded\def\spac_align_use_later#1%
  {\begingroup
   \edef\m_spac_align_asked{#1}%
   \expandafter\let\expandafter\raggedcommand\csname\??alignmentnormalcache\m_spac_align_asked\endcsname
   \ifx\raggedcommand\relax
     \spac_align_add_to_cache
   \fi
   \endgroup}

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

% Maybe we need something different in columns.

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

% beware, toks stuff and states are set at a differt time, so installalign is
% only for special options
%
% \setvalue{\??aligncommand whatever}%
%   {\c_spac_align_state_horizontal\plushundred
%    \toksapp\t_spac_align_collected{.....}}
%
% this one could deal with both
%
% \unexpanded\def\installalignoption#1#2%
%   {\ifcsname\??aligncommand#1\endcsname \else
%      \setvalue{\??aligncommand#1}%
%        {\spac_align_set_horizontal_none
%         \c_spac_align_state_horizontal\plushundred % don't set
%         \toksapp\t_spac_align_collected{#2}}%
%    \fi}
%
% \installalignoption
%   {whatever}
%   {}

% The keywords:

\letvalue{\??aligncommand\empty            }\empty
\setvalue{\??aligncommand\v!broad          }{\c_spac_align_state_broad     \plusone  }
\setvalue{\??aligncommand\v!wide           }{\c_spac_align_state_broad     \plustwo  }

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

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

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

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

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

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

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

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

\setvalue{\??aligncommand  \v!final}{\c_spac_align_state_par_fill\plusone}
\setvalue{\??aligncommand1*\v!final}{\c_spac_align_state_par_fill\plusone}
\setvalue{\??aligncommand2*\v!final}{\c_spac_align_state_par_fill\plustwo}      % hardcoded multiplier
\setvalue{\??aligncommand3*\v!final}{\c_spac_align_state_par_fill\plusthree}
\setvalue{\??aligncommand4*\v!final}{\c_spac_align_state_par_fill\plusfour}

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

\setvalue{\??aligncommand  \v!more}{\toksapp\t_spac_align_collected{\looseness\plusone}}
\setvalue{\??aligncommand1*\v!more}{\toksapp\t_spac_align_collected{\looseness\plusone}}
\setvalue{\??aligncommand2*\v!more}{\toksapp\t_spac_align_collected{\looseness\plustwo}}

% \setvalue{\??aligncommand ... }{\toksapp\t_spac_align_collected{\nopenalties}}
% \setvalue{\??aligncommand ... }{\toksapp\t_spac_align_collected{\setdefaultpenalties}}

\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}

\unexpanded\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
    \setvalue{\??aligncommand\v!right}{\c_spac_align_state_horizontal\plusthree}%
    \setvalue{\??aligncommand\v!left }{\c_spac_align_state_horizontal\plustwo  }%
\to \t_spac_every_swap_align

\unexpanded\def\enablereversealignment
  {\the\t_spac_every_swap_align
   \t_spac_every_swap_align\emptytoks}

% Visible commands:

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

\let\forgetragged      \spac_align_set_horizontal_none

\appendtoks
    \spac_align_set_horizontal_none
\to \everyforgetall

% Box commands.

\unexpanded\def\ibox
  {\vbox\bgroup
     \forgetall
     \let\\=\endgraf
     \ifdoublesided\signalinnerrealign\fi
     \doifelserightpage\spac_align_set_horizontal_right\spac_align_set_horizontal_left
     \let\next}

\unexpanded\def\obox
  {\vbox\bgroup
     \forgetall
     \let\\=\endgraf
     \ifdoublesided\signalouterrealign\fi
     \doifelserightpage\c_spac_align_state_horizontal_left\spac_align_set_horizontal_right
     \let\next}

\let\raggedbox\relax

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

\def\dosetraggedhbox#1% can be more keys .. how about caching here (but seldom used)
  {\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}

% \def\usealignparametersethbox#1%
%   {\edef\p_spac_align{#1\c!align}%
%    \let\raggedbox\hbox
%    \ifx\p_spac_align\empty \else
%      \processcommacommand[\p_spac_align]\spac_align_set_ragged_hbox
%    \fi}
%
% \def\usealignparametersetvbox#1%
%   {\edef\p_spac_align{#1\c!align}%
%    \let\raggedbox\vbox
%    \ifx\p_spac_align\empty \else
%      \processcommacommand[\p_spac_align]\spac_align_set_ragged_vbox
%    \fi}

\setvalue{\??alignvertical  \v!left      }{\let\raggedbox\lbox}
\setvalue{\??alignvertical  \v!right     }{\let\raggedbox\rbox}
\setvalue{\??alignvertical  \v!middle    }{\let\raggedbox\cbox}
\setvalue{\??alignvertical  \v!inner     }{\let\raggedbox\ibox}
\setvalue{\??alignvertical  \v!outer     }{\let\raggedbox\obox}
\setvalue{\??alignvertical  \v!flushleft }{\let\raggedbox\rbox}
\setvalue{\??alignvertical  \v!flushright}{\let\raggedbox\lbox}
\setvalue{\??alignvertical  \v!center    }{\let\raggedbox\cbox}
\setvalue{\??alignvertical  \v!no        }{\def\raggedbox{\vbox\bgroup\spac_align_set_horizontal_right\let\next=}]}

% maybe \let's

\setvalue{\??alignhorizontal\v!left      }{\def\raggedbox{\doalignedline\v!left  }}
\setvalue{\??alignhorizontal\v!right     }{\def\raggedbox{\doalignedline\v!right }}
\setvalue{\??alignhorizontal\v!middle    }{\def\raggedbox{\doalignedline\v!middle}}
\setvalue{\??alignhorizontal\v!inner     }{\def\raggedbox{\doalignedline\v!inner }}
\setvalue{\??alignhorizontal\v!outer     }{\def\raggedbox{\doalignedline\v!outer }}
\setvalue{\??alignhorizontal\v!flushleft }{\def\raggedbox{\doalignedline\v!right }}
\setvalue{\??alignhorizontal\v!flushright}{\def\raggedbox{\doalignedline\v!left  }}
\setvalue{\??alignhorizontal\v!center    }{\def\raggedbox{\doalignedline\v!middle}}

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

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

\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
   \attribute\alignstateattribute\ifcase\raggedstatus\attributeunsetvalue\else\raggedstatus\fi}

% older (context) names:

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

% tracing:

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

\unexpanded\def\showpardata
  {\edef\thepardata
     {\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}%
   \dontleavehmode
   \begingroup
   \inleftmargin{\vsmash{\infofont\framed[\c!align=\v!right]{\thepardata}}}%
   \endgroup
   \let\showpardata\relax}

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

\unexpanded\def\stopshowpardata
  {\endgraf
   \endgroup}

% Structure:

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

\unexpanded\def\stopalignment
  {\par
   \endgroup}

\setnewconstant\alignstrutmode\plusone

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

\newtoks \everyleftofalignedline
\newtoks \everyrightofalignedline

\unexpanded\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}}}

\def\doalignline#1#2% \\ == newline
  {\noindentation  % was \noindent
   \dontleavehmode % added in marrakesch at TUG 2006\begingroup
   \begingroup
   \setlocalhsize % new
   \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 \def\line        {\hbox to\hsize}    \fi
\ifdefined\leftline   \else \def\leftline  #1{\line{#1\hss}}     \fi
\ifdefined\rightline  \else \def\rightline #1{\line{\hss#1}}     \fi
\ifdefined\centerline \else \def\centerline#1{\line{\hss#1\hss}} \fi

% direct commands

\installcorenamespace{alignwrapper}

\setuvalue{\??alignwrapper\v!left  }{\doalignline\relax \hss  }
\setuvalue{\??alignwrapper\v!middle}{\doalignline\hss   \hss  }
\setuvalue{\??alignwrapper\v!right }{\doalignline\hss   \relax}
\setuvalue{\??alignwrapper\v!max   }{\doalignline\relax \relax}

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

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

\unexpanded\def\spac_align_wrapper_start[#1]%
  {\spac_align_wrapper_handle{#1}%
   \bgroup\ignorespaces}

\unexpanded\def\spac_align_wrapper_stop
  {\removeunwantedspaces\egroup}

\unexpanded\def\startlinealignment
  {\dosingleempty\spac_align_wrapper_start}

\let\stoplinealignment\spac_align_wrapper_stop

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

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

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

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

\installcorenamespace{alignline}

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

\def\doalignedline#1{\resetrealignsignal\csname\??alignline#1\endcsname}

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

\def\doxalignline#1#2#3#4#5#6%
  {\noindentation  % was \noindent
   \dontleavehmode % added in marrakesch at TUG 2006\begingroup
   \begingroup
   \setlocalhsize
   \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}

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

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

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

\def\doalignedline#1% unchecked
  {\csname\??alignline#1\endcsname} % no \resetrealignsignal here ?

\def\alignedline#1#2% setting default
 % {\csname\??alignline\ifcsname\??alignline#1\endcsname#1\else#2\fi\endcsname}
  {\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

\unexpanded\def\wordright
  {\dosingleempty\spac_word_right}

\def\spac_word_right[#1]%
  {% don't change
   \groupedcommand
     {\removeunwantedspaces
      \hfill
      \allowbreak % changed back from \hskip\zeropoint
      \strut
      \hfill
      \quad % decent spacing
      \hbox}
     {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
      \parfillskip\zeropoint
      \finalhyphendemerits\zerocount % yes or no (see hyhenation/specialcases-001.tex)
      \par}}

% \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.

% \unexpanded\def\bottomword
%   {\par
%    \dowithnextbox
%      {\leaders\box\nextbox\vfil\page}
%      \vbox to \lineheight}
%
% \unexpanded\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

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

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

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

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

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

\unexpanded\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

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

\unexpanded\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}

% \installnamespace{alignsets}
%
% \setvalue{\??alignsets\v!right     }#1#2{\let#1\relax\let#2\hss  }
% \setvalue{\??alignsets\v!left      }#1#2{\let#1\hss  \let#2\relax}
% \setvalue{\??alignsets\v!flushright}#1#2{\let#1\hss  \let#2\relax}
% \setvalue{\??alignsets\v!flushleft }#1#2{\let#1\relax\let#2\hss  }
% \setvalue{\??alignsets\v!middle    }#1#2{\let#1\hss  \let#2\hss  }
% \setvalue{\??alignsets\v!low       }#1#2{\let#1\vss  \let#2\relax}
% \setvalue{\??alignsets\v!high      }#1#2{\let#1\relax\let#2\vss  }
% \setvalue{\??alignsets\v!lohi      }#1#2{\let#1\vss  \let#2\vss  }
% \setvalue{\??alignsets\s!unknown   }#1#2{\let#1\relax\let#2\relax}
%
% \unexpanded\def\spac_align_set_ss#1%
%   {\csname\??alignsetss\ifcsname\??alignsetss#1\endcsname#1\else\s!unknown\fi\endcsname}

% Some obsolete (old) helpers:

\unexpanded\def\definehbox
  {\dodoubleargument\spac_align_definehbox}

\def\spac_align_definehbox[#1][#2]%
  {\setvalue{hbox#1}##1{\hbox to #2{\begstrut##1\endstrut\hss}}}

%D Some direction related helpers:

\installcorenamespace {reverse}

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

\ifcase\contextlmtxmode
  \let\usedirectionparameterreverse\gobbleoneargument
\else
  \def\usedirectionparameterreverse#1{\begincsname\??reverse#1\c!direction\endcsname}
\fi

\protect \endinput