%D \module
%D   [       file=spac-hor,
%D        version=2009.10.16, % 1997.03.31, was core-spa.tex
%D          title=\CONTEXT\ Spacing Macros,
%D       subtitle=Horizontal,
%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 / Horizontal}

% document: \enabledirectives[backends.spaces]

\unprotect

\registerctxluafile{spac-hor}{autosuffix}

\ifdefined\parfillrightskip\else \aliased\let\parfillrightskip\parfillskip \fi

\bitwiseflip \normalizelinemode \normalizelinenormalizecode
\bitwiseflip \normalizelinemode \parindentskipnormalizecode
\bitwiseflip \normalizelinemode \clipwidthnormalizecode
\bitwiseflip \normalizelinemode \flattendiscretionariesnormalizecode
\bitwiseflip \normalizelinemode \flattenhleadersnormalizecode
\bitwiseflip \normalizelinemode \balanceinlinemathnormalizecode
%bitwiseflip \normalizelinemode \discardzerotabskipsnormalizecode

\bitwiseflip \normalizeparmode \normalizeparnormalizeparcode
\bitwiseflip \normalizeparmode \flattenvleadersnormalizeparcode
\bitwiseflip \normalizeparmode \removetrailingspacesnormalizeparcode

\lettonothing\v_spac_indentation_current % amount/keyword

\newdimension\d_spac_indentation_par
\parindent   \d_spac_indentation_par % for the show

\newconditional\c_spac_indentation_indent_first \c_spac_indentation_indent_first\conditionaltrue
\newconstant   \c_spac_indentation_toggle_state

%D After a blank or comparable situation (left side floats) we
%D need to check if the next paragraph has to be indented.

% \permanent\protected\def\presetindentation
%   {\doifoutervmode{\ifconditional\c_spac_indentation_indent_first\else\spac_indentation_variant_no\fi}}

\permanent\protected\def\presetindentation
  {\unless\ifvmode
     % do nothing
   \orelse\ifinner
     % do nothing
   \orelse\ifconditional\c_spac_indentation_indent_first
     % do nothing
   \else
     \spac_indentation_variant_no
   \fi}


\permanent\protected\def\setupindenting
  {\doifelsenextoptionalcs\spac_indentation_setup_options\spac_indentation_setup_size}

\permanent\protected\def\spac_indentation_setup_size
  {\assigndimension\v_spac_indentation_current\d_spac_indentation_par{1\emwidth}{1.5\emwidth}{2\emwidth}%
   \ifzeropt\parindent\else
     \parindent\d_spac_indentation_par\relax % new per 2019-04-12 : just in case it has been set beforehand
   \fi}

\aliased\let\synchronizeindenting\spac_indentation_setup_size

\lettonothing\m_spac_indentation_options

\def\spac_indentation_setup_options[#1]%
  {\edef\m_spac_indentation_options{#1}% comma separated list
   \ifempty\m_spac_indentation_options \else
     \spac_indentation_setup_indeed
   \fi}

\def\spac_indentation_setup_indeed
  {% not here: \c_spac_indentation_indent_first\conditionaltrue
   % not here: \parindent\d_spac_indentation_par
   % not here: \c_spac_indentation_toggle_state\zerocount
   \processcommacommand[\m_spac_indentation_options]\spac_indentation_apply_step_one % catch small, medium, etc
   \processcommacommand[\m_spac_indentation_options]\spac_indentation_apply_step_two % catch rest
   \ifzeropt\parindent\else
     \doifemptytoks\everypar\spac_indentation_set_everypar
   \fi
   \ifconditional\c_spac_indentation_indent_first
     \spac_indentation_variant_yes % better than: \let\checkindentation\relax
   \else
     \spac_indentation_variant_no
   \fi
   \spac_indentation_check_toggle}

\def\spac_indentation_set_everypar
  {\everypar{\checkindentation}}

\permanent\protected\def\useindentingparameter#1% faster local variant
  {\edef\m_spac_indentation_options{#1\c!indenting}%
   \ifempty\m_spac_indentation_options \else
     \spac_indentation_setup_indeed
   \fi}

% \defineindenting[whatever][yes,2cm]
% %defineindenting[whatever][yes,-2cm]
%
% \setupindenting[yes,-2em] \input ward \par
% \setupindenting[yes,2em]  \input ward \par
% \setupindenting[whatever] \input ward \par

\installcorenamespace {indentingpreset}

\permanent\tolerant\protected\def\defineindenting[#1]#*[#2]% todo: mixes
  {\ifarguments\else\edefcsname\??indentingpreset#1\endcsname{#2}\fi}

\def\spac_indentation_apply_step_one_nested
  {\expandafter\processcommacommand\expandafter[\lastnamedcs]\spac_indentation_apply_step_one}

\def\spac_indentation_apply_step_two_nested
  {\expandafter\processcommacommand\expandafter[\lastnamedcs]\spac_indentation_apply_step_two}

\def\spac_indentation_apply_step_one#1%
  {\ifcsname\??indentingpreset#1\endcsname
     \spac_indentation_apply_step_one_nested
   \orelse\ifcsname\??indentingmethod#1\endcsname
     % case two
   \else
     \edef\v_spac_indentation_current{#1}% single entry in list
     \let\v_spac_indentation_normal\v_spac_indentation_current
     \spac_indentation_setup_size
   \fi}

\def\spac_indentation_apply_step_two#1%
  {\ifcsname\??indentingpreset#1\endcsname
     \spac_indentation_apply_step_two_nested
   \orelse\ifcsname\??indentingmethod#1\endcsname
     \lastnamedcs
   \else
     % case one
   \fi}

\permanent\protected\def\indenting % kind of obsolete
  {\doifelsenextoptionalcs\spac_indentation_setup_options\relax}

% use \noindentation to suppress next indentation

\installcorenamespace{indentingmethod}

\permanent\protected\def\installindentingmethod#1#2%
  {\defcsname\??indentingmethod#1\endcsname{#2}}

\installindentingmethod \v!no    {\parindent\zeropoint}
\installindentingmethod \v!not   {\parindent\zeropoint}

\installindentingmethod \v!first {\c_spac_indentation_indent_first\conditionaltrue}
\installindentingmethod \v!next  {\c_spac_indentation_indent_first\conditionalfalse}

\installindentingmethod \v!yes   {\parindent\d_spac_indentation_par\relax} % not \indent !
\installindentingmethod \v!always{\parindent\d_spac_indentation_par\relax} % not \indent !

\installindentingmethod \v!never {\parindent\zeropoint\relax     % no \indent !
                                  \c_spac_indentation_toggle_state\zerocount}

\installindentingmethod \v!odd   {\c_spac_indentation_toggle_state\plusone}
\installindentingmethod \v!even  {\c_spac_indentation_toggle_state\plustwo}

\installindentingmethod \v!normal{\ifempty\v_spac_indentation_normal\else
                                    \let\v_spac_indentation_current\v_spac_indentation_normal
                                    \spac_indentation_setup_size
                                  \fi}

\installindentingmethod \v!reset {\c_spac_indentation_indent_first\conditionaltrue
                                  \parindent\zeropoint
                                  \c_spac_indentation_toggle_state\zerocount}

\installindentingmethod \v!toggle{\parindent\ifzeropt\parindent
                                    \d_spac_indentation_par
                                  \else
                                    \zeropoint
                                  \fi\relax}

\permanent\protected\def\noindenting{\indenting[\v!no, \v!next ]}
\permanent\protected\def\doindenting{\indenting[\v!yes,\v!first]}

%D Here come the handlers (still rather messy ... we need states).

%newif\ifindentation \indentationtrue  % will become a mode

\aliased\let\checkindentation\relax

\installmacrostack\checkindentation % used in typo-del

%D Actually we can forget about indent and let everypar insert a kern or so,
%D but on the other hand it's kind of consistent to keep it and make the
%D width zero. We can do it in \LUA\ or do it natively (which actually makes
%D sense.

% \permanent\protected\def\undent
%   {\begingroup
%      % todo: check subtype too
%      \ifnum\lastnodetype=\gluenodecode
%        \unskip % we also need to check for the subtype
%      \orelse\ifnum\lastnodetype=\hlistnodecode
%        \setbox\scratchbox\lastbox % we also need to check for the subtype
%      \else
%        % forget about it
%      \fi
%    \endgroup}

\def\spac_indentation_remove
  {\ifzeropt\parindent \else
     \undent
   \fi}

\def\spac_indentation_kill_indeed
  {%\global\indentationfalse
   \spac_indentation_remove}

\permanent\protected\def\spac_indentation_do_toggle_indeed
  {%\global\indentationfalse
   \enforced\glet\checkindentation\spac_indentation_no_toggle_indeed
   \spac_indentation_remove}

\permanent\protected\def\spac_indentation_no_toggle_indeed
  {%\global\indentationtrue
   \enforced\glet\checkindentation\spac_indentation_do_toggle_indeed}

\permanent\protected\def\spac_indentation_do_indeed
  {}%\global\indentationtrue}

\permanent\protected\def\spac_indentation_do_toggle
  {\enforced\glet\checkindentation\spac_indentation_do_toggle_indeed}

\permanent\protected\def\spac_indentation_no_toggle
  {\enforced\glet\checkindentation\spac_indentation_no_toggle_indeed}

\permanent\protected\def\spac_indentation_check_toggle
  {\ifcase\c_spac_indentation_toggle_state
     % nothing
   \or
     \spac_indentation_no_toggle
   \or
     \spac_indentation_do_toggle
   \fi}

\permanent\protected\def\spac_indentation_variant_yes
  {\enforced\glet\checkindentation\spac_indentation_do_indeed}

\permanent\protected\def\spac_indentation_no_next_check
  {\spac_indentation_remove
   \enforced\glet\checkindentation\spac_indentation_do_indeed}

\permanent\protected\def\spac_indentation_variant_no % made global
  {\ifinpagebody \else
     %\global\indentationfalse
     \enforced\glet\checkindentation\spac_indentation_no_next_check
   \fi}

\permanent\protected\def\nonoindentation % bv bij floats
  {\ifinpagebody \else
     %\global\indentationtrue
     \enforced\glet\checkindentation\spac_indentation_do_indeed
   \fi}

\permanent\protected\def\spac_indentation_variant_force
  {\ifvmode \ifzeropt\parindent \else
     % was : \hskip\parindent
     % can be: \indent
     % but we test:
     \noindent\hskip\parindent % hm, we cannot undent this one % TODO: indent skip
   \fi \fi}

% public:

\aliased\let\indentation  \spac_indentation_variant_force
\aliased\let\noindentation\spac_indentation_variant_no    % public
\aliased\let\doindentation\spac_indentation_variant_yes   % public

\permanent\protected\def\dontrechecknextindentation  % public (in macros)
  {\global\enforced\let\dorechecknextindentation\relax}

\aliased\let\dorechecknextindentation\relax % public (in macros)

% \permanent\protected\def\spac_indentation_check_next_indentation
%   {\global\enforced\let\dorechecknextindentation\relax
%    \doifelsenextchar\par\donothing\spac_indentation_variant_no} % messy check as next is seldom \par

\permanent\protected\def\spac_indentation_check_next_indentation
  {\global\enforced\let\dorechecknextindentation\relax
   \begingroup
   \autoparagraphmode\zerocount
   \doifelsenextchar\par\endgroup{\endgroup\spac_indentation_variant_no}} % messy check as next is seldom \par

\def\spac_indentation_variant_auto
  {\global\enforced\let\dorechecknextindentation\spac_indentation_check_next_indentation}

%D This one sets up the local indentation behaviour (i.e. either or not
%D a next paragraph will be indented).

\installcorenamespace{indentnext}

\permanent\protected\def\checknextindentation[#1]%
  {\begincsname\??indentnext#1\endcsname}

\permanent\protected\def\useindentnextparameter#1% new, the more efficient variant
  {\edef\p_indentnext{#1\c!indentnext}%
   \ifempty\p_indentnext\else
     \begincsname\??indentnext\p_indentnext\endcsname
   \fi}

\letcsname\??indentnext       \endcsname\donothing
\letcsname\??indentnext\v!yes \endcsname\spac_indentation_variant_yes
\letcsname\??indentnext\v!no  \endcsname\spac_indentation_variant_no
\letcsname\??indentnext\v!auto\endcsname\spac_indentation_variant_auto

%D An example of usage:
%D
%D \starttyping
%D \setupindenting[small,yes]
%D
%D \setupitemize [indentnext=auto]
%D \setuptyping  [indentnext=auto]
%D \setupformulas[indentnext=auto]
%D
%D \input tufte \startitemize \item itemize \stopitemize
%D \input tufte \startitemize \item itemize \stopitemize
%D \input tufte \startitemize \item itemize \stopitemize
%D
%D \page
%D
%D \input tufte
%D \starttyping
%D verbatim
%D \stoptyping
%D
%D \input tufte
%D \starttyping
%D verbatim
%D \stoptyping
%D
%D \input tufte
%D \starttyping
%D verbatim
%D \stoptyping
%D
%D \page
%D
%D \input tufte \startformula a = b \stopformula
%D \input tufte \startformula a = b \stopformula
%D \input tufte \startformula a = b \stopformula
%D \stoptyping

% maybe an everyforgetparindent

\permanent\protected\def\forgetparindent
  {\c_spac_indentation_indent_first\conditionaltrue % recently added
   \d_spac_indentation_par\zeropoint
   \parindent\zeropoint
   \let\v_spac_indentation_current\v!none}

\appendtoks
    \forgetparindent
\to \everyforgetall

\permanent\protected\def\forgethorizontalstretch
  {\emergencystretch\zeropoint}

\appendtoks
    \forgethorizontalstretch
\to \everyforgetall % needed in pagebody

%D Helper:

\permanent\protected\def\softbreak
  {\relax\ifhmode\hskip\parfillskip\break\fi}

%D \macros
%D   {frenchspacing,nonfrenchspacing}
%D
%D Somehow \type{\frenchspacing} can lead to hyphenation between dashes so we now
%D have \type {\newfrenchspacing} (moved from \type {syst-chr}). Maybe it's not
%D needed any more.

%D Hm ... todo:

\installcorenamespace{spacecodemethod}

% \sfcode\rightparentasciicode \zerocount % hm
% \sfcode\rightbracketasciicode\zerocount % hm hm
% \sfcode\singlequoteasciicode \zerocount % hm hm hm

%D We always had:

% \def\spac_spacecodes_set_fixed#1%
%   {\sfcode\periodasciicode         #1%
%    \sfcode\commaasciicode          #1%
%    \sfcode\questionmarkasciicode   #1%
%    \sfcode\exclamationmarkasciicode#1%
%    \sfcode\colonasciicode          #1%
%    \sfcode\semicolonasciicode      #1}

% \def\spac_spacecodes_set_stretch
%   {\sfcode\periodasciicode         \plusthreethousand
%    \sfcode\commaasciicode          \plustwelvehundredfifty
%    \sfcode\questionmarkasciicode   \plusthreethousand
%    \sfcode\exclamationmarkasciicode\plusthreethousand
%    \sfcode\colonasciicode          \plustwothousand
%    \sfcode\semicolonasciicode      \plusfifteenhundred}

% \permanent\protected\def\frenchspacing   {\spac_spacecodes_set_fixed\plusthousand}
% \permanent\protected\def\newfrenchspacing{\spac_spacecodes_set_fixed\plusthousandfifty}
% \permanent\protected\def\nonfrenchspacing{\spac_spacecodes_set_stretch}

%D Instead we now use:

% Musical timestamp: Archive – Full Orchestral FM4 Radio Session (2026,
% released end Feb / begin Mar, eqNYOHrbSoM). So good!

\spcode\periodasciicode          1 % 3000
\spcode\commaasciicode           2 % 1250
\spcode\questionmarkasciicode    3 % 3000
\spcode\exclamationmarkasciicode 3 % 3000
\spcode\colonasciicode           4 % 2000
\spcode\semicolonasciicode       5 % 1500

\spcode\rightparentasciicode     6 % 0 for Jim Diamond
\spcode\rightbracketasciicode    6 % idem
\spcode\singlequoteasciicode     6 % idem

% frenchspacing == fixed

% options \constantspecificationoptioncode

\specificationdef \nospacingmap \textspacing 0

\specificationdef \nonfrenchspacingmap \textspacing 6 constant
    \plusthreethousand      \zerocount % .
    \plustwelvehundredfifty \zerocount % ,
    \plusthreethousand      \zerocount % ! ?
    \plustwothousand        \zerocount % :
    \plusfifteenhundred     \zerocount % ;
    \zerocount              \zerocount % ) ] '
\relax

\specificationdef \frenchspacingmap \textspacing 6 constant
    \plusthousand \zerocount % .
    \plusthousand \zerocount % ,
    \plusthousand \zerocount % ! ?
    \plusthousand \zerocount % :
    \plusthousand \zerocount % ;
    \zerocount    \zerocount % ) ] '
\relax

\specificationdef \newfrenchspacingmap \textspacing 6 constant
    \plusthousandfifty \zerocount % .
    \plusthousandfifty \zerocount % ,
    \plusthousandfifty \zerocount % ! ?
    \plusthousandfifty \zerocount % :
    \plusthousandfifty \zerocount % ;
    \zerocount         \zerocount % ) ] '
\relax

\specificationdef \penalizedspacingmap \textspacing 6 constant
    \plusthousand -\plusfifty % .
    \plusthousand -\plusfifty % ,
    \plusthousand -\plusfifty % ! ?
    \plusthousand -\plusfifty % :
    \plusthousand -\plusfifty % ;
    \zerocount     \zerocount % ) ] '
\relax

\specificationdef \nonpenalizedspacingmap \textspacing 6 constant
    \plusthreethousand      -\plusfifty % .
    \plustwelvehundredfifty -\plusfifty % ,
    \plusthreethousand      -\plusfifty % ! ?
    \plustwothousand        -\plusfifty % :
    \plusfifteenhundred     -\plusfifty % ;
    \zerocount               \zerocount % ) ] '
\relax

\permanent\protected\def\nonfrenchspacing   {\textspacing\nonfrenchspacingmap   }
\permanent\protected\def\frenchspacing      {\textspacing\frenchspacingmap      }
\permanent\protected\def\newfrenchspacing   {\textspacing\newfrenchspacingmap   }
\permanent\protected\def\nonpenalizedspacing{\textspacing\nonpenalizedspacingmap}
\permanent\protected\def\penalizedspacing   {\textspacing\penalizedspacingmap   }

\newinteger \pbsppenalty \pbsppenalty\plusfifty

\permanent\protected\def\pbsp{\hskip\interwordspace penalty \pbsppenalty\relax}

%D The installer:

\permanent\protected\def\installspacingmethod#1#2{\defcsname\??spacecodemethod#1\endcsname{#2}}

\installspacingmethod \empty    {}                  % keep values
\installspacingmethod \v!fixed  {\frenchspacing   } % equal spaces everywhere
\installspacingmethod \v!packed {\newfrenchspacing} % slighly more after punctuation
\installspacingmethod \v!broad  {\nonfrenchspacing} % more depending on what punctuation

\installspacingmethod {\v!fixed:\v!small} {\penalizedspacing}
\installspacingmethod {\v!broad:\v!small} {\nonpenalizedspacing}

\permanent\tolerant\protected\def\setupspacing[#1]%
  {\ifarguments\or
     \begincsname\??spacecodemethod#1\endcsname
   \fi
   \updateraggedskips}

% test test\fsp. test % beats frenchspacing

\permanent\protected\def\fsp#1% fixed space puncuation
  {#1%
   \ifchknum`#1\or
    \spacefactor\plusthousand
   \fi}

%D Experimental (see periods-001.tex):
%D
%D \startbuffer
%D Watch this            {S.           Bernhard} dog carry a can of drink.
%D Watch this  \periodic {S.           Bernhard} dog carry a can of drink.
%D Watch this  \Periodic {S.           Bernhard} dog carry a can of drink.
%D Watch this            {St.          Bernhard} dog carry a can of drink.
%D Watch this  \periodic {St.          Bernhard} dog carry a can of drink.
%D Watch this  \Periodic {St.          Bernhard} dog carry a can of drink.
%D Watch this            {Prof. Dr. S. Bernhard} dog carry a can of drink.
%D Watch this  \periodic {Prof. Dr. S. Bernhard} dog carry a can of drink.
%D Watch this  \Periodic {Prof. Dr. S. Bernhard} dog carry a can of drink.
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlines
%D \getbuffer
%D \stoplines

\permanent\protected\def\overloadspacefactor
  {\bitwiseflip\glyphoptions\spacefactoroverloadglyphoptioncode}

\newinteger\periodicshrink \periodicshrink 250

\permanent\protected\def\Periodic
  {\groupedcommand
     {\overloadspacefactor
      \spacefactoroverload\periodicshrink}%
     \relax}

\permanent\protected\def\periodic
  {\groupedcommand
     {\overloadspacefactor
      \spacefactoroverload\periodicshrink
      \sfcode\periodasciicode\periodicshrink}%
     \relax}

%D Here's a tweak .. if needed one can configure it in the configuration
%D so that initialization happens more efficient.
%D
%D \starttyping
%D \startoverlay
%D     {
%D         \green
%D         \enabledirectives[characters.spaceafteruppercase=normal]%
%D         \vbox{\hsize 5em x. X\par x.\ X\par X. X\par X.\ X\par}
%D     } {
%D         \blue
%D         \enabledirectives[characters.spaceafteruppercase=traditional]%
%D         \vbox{\hsize 5em x. X\par x.\ X\par X. X\par X.\ X\par}
%D     }
%D \stopoverlay
%D \stoptyping

% This is not needed, as \updateraggedskips is taking care of it:

\permanent\protected\def\synchronizespacecodes{\updateraggedskips}

% \dorecurse{100}{\recurselevel\spacefactor 800 \space} \par
% \dorecurse{100}{\recurselevel\spacefactor1200 \space} \par
% \dorecurse{100}{\recurselevel\spacefactor 800 \normalspaceprimitive} \par
% \dorecurse{100}{\recurselevel\spacefactor1200 \normalspaceprimitive} \par

% When we don't add the % here, we effectively get \<endlinechar> and
% since we have by default \def\^^M{\ } we get into a loop.

\aliased\let\normalspaceprimitive=\ % space-comment is really needed

%D As the \type{\ } is convenient in:
%D
%D \starttyping
%D \TEX\space x\crlf
%D \TEX\      x\crlf
%D \TEX{}     x\crlf
%D \stoptyping
%D
%D from now on we treat it as a normal space and not as a space with \type
%D {sfcode} 1000.

% \permanent\protected\def\specialspaceprimitive
%   {\begingroup
%    % so, no fancy extra spacing after: foo i.e.\ bar
%    \nonfrenchspacing\normalspaceprimitive
%    \endgroup}

\permanent\protected\def\specialspaceprimitive
  {% is a current state, set explicitly or when a character is appended
   \ifhmode
     \spacefactor\plusthousand
   \else
     \dontleavehmode
   \fi
   \normalspaceprimitive}

% \permanent\protected\def\normalnotobeyedspace
%   {\mathortext\normalspaceprimitive\specialspaceprimitive} % no \dontleavehmode\space (else no frenchspacing)

\permanent\protected\def\normalnotobeyedspace
  {\ifmmode\normalspaceprimitive\else\specialspaceprimitive\fi} % no \dontleavehmode\space (else no frenchspacing)

\pushoverloadmode

\overloaded\let\ =\normalnotobeyedspace % so we redefine the primitive!

\popoverloadmode

% Because I strip spaces at the end of lines (in the editor) we need a bit of
% a trick to define slash+newline, so \space and \<newline> are the same

% We need to be careful with \ and \space and the definition of ~ which uses \ as
% we need to associate unicode spacing with it. There is some messy aspect that
% I forgot to note down so I will revision the \ once I ran into it again.

% \ruledhbox spread 10pt {\frenchspacing    xx xx\ X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx xx\ X}
% \ruledhbox spread 10pt {\frenchspacing    xx xx X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx xx X}
% \ruledhbox spread 10pt {\frenchspacing    xx xx~X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx xx~X}

% \ruledhbox spread 10pt {\frenchspacing    xx dr.\ X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx dr.\ X}
% \ruledhbox spread 10pt {\frenchspacing    xx dr. X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx dr. X}
% \ruledhbox spread 10pt {\frenchspacing    xx dr.~X}
% \ruledhbox spread 10pt {\nonfrenchspacing xx dr.~X}

\permanent\protected\def\nonbreakablespace{\penalty\plustenthousand\normalspaceprimitive} % no space in math

\letcatcodecommand \ctxcatcodes \tildeasciicode \nonbreakablespace % overloaded later

\permanent\protected\def\removelastspace{\ifhmode\unskip\fi}
\permanent\protected\def\nospace        {\removelastspace\ignorespaces}

\permanent\protected\def\nospacing{\normalnospaces\plusone}
\permanent\protected\def\dospacing{\normalnospaces\zerocount}

\ifdefined\softhyphen \else
    \let\softhyphen\explicitdiscretionary
\fi

%D We can do this:
%D
%D starttyping
%D \nospaces\plusthree
%D \spacechar\underscoreasciicode
%D \hccode\underscoreasciicode\underscoreasciicode
%D Where are the spaces?
%D \stoptyping
%D
%D But that should not bleed into the page builder or nested constructs, so:

\appendtoks
    \nospaces \zerocount
    \spacechar\asciispacechar % not needed as one sets it locally
\to \everyforgetall

%D This is a rubish approach vbecause it redefines \typ {\csname \endcsname} to
%D \type {\space} so we need to fix that.

\expandafter\let\expandafter\next\csname\endcsname
\cldcontext{"\string\\protected\string\\def\string\\\string\n{\string\\space}"}
\expandafter\let\csname\endcsname\next

%D Here is an example from \type {newlines-001.tex}:
%D
%D \starttyping
%D \def\TestA#1%
%D   {\writestatus{Test A}{#1}%
%D    \ctxlua{str = [[#1]] print(str) context(str) io.savedata("temp.tmp",str)}}
%D
%D \def\TestB#1%
%D   {\writestatus{Test B}{#1}%
%D    \ctxlua{str = [[\detokenize{#1}]] print(str) context(str) io.savedata("temp.tmp",str)}}
%D
%D \def\TestC#1%
%D   {\writestatus{Test C}{#1}%
%D    \edef\temp{#1}%
%D    \ctxlua{str = [[\detokenize\expandafter{\temp}]] print(str) context(str) io.savedata("temp.tmp",str)}%
%D    \typefile{temp.tmp}}
%D
%D \TestA{Test\
%D A}
%D
%D \TestB{Test\
%D B}
%D
%D \TestC{Test\
%D C}
%D
%D Test\
%D D
%D
%D \section{Test\
%D E}
%D
%D Test F\footnote{Note\
%D F}
%D \stoptyping

% in tables we need:
%
% \def\fixedspace   {\hskip.5em\relax}
%
% but, since not all fonts have .5em digits:

\permanent\protected\def\fixedspace
  {\setbox\scratchbox\hpack{\mathortext{0}{0}}% was \hbox
   \hskip\wd\scratchbox\relax}

\permanent\protected\def\fixedspaces
  {\letcatcodecommand \ctxcatcodes \tildeasciicode\fixedspace
  %\enforced\let~\fixedspace} % we need to renew it
   \enforced\letcharcode\tildeasciicode\fixedspace} % why this

\appendtoks
   %\enforced\let~\space
    \enforced\letcharcode\tildeasciicode\space
    \enforced\let\ \space
\to \everysimplifycommands

% \newsignal\d_spac_keep_unwanted_space_signal
%
% % \parindentmode\plusone
%
% \permanent\protected\def\keepunwantedspaces
%   {\ifhmode
%      \ifdim\lastskip=\d_spac_keep_unwanted_space_signal\else
%         \hskip\d_spac_keep_unwanted_space_signal\relax
%      \fi
%    \fi}
%
% \permanent\protected\def\removeunwantedspaces
%   {\ifhmode
%      \expandafter \spac_helpers_remove_unwantedspace
%    \fi}
%
% \def\spac_helpers_remove_unwantedspace
%   {\ifnum\lastnodetype=\gluenodecode\relax
%      \ifnum\lastnodesubtype=\indentskipsubtypecode\relax
%        % keep parindent
%      \orelse\ifdim\lastskip=\d_spac_keep_unwanted_space_signal\relax
%         \unskip
%      \else
%         \unskip
%         \doubleexpandafter\spac_helpers_remove_unwantedspace
%      \fi
%    \fi}

\newboundary\c_spac_keepspaces_boundary

\permanent\protected\def\keepunwantedspaces
  {\ifhmode\ifnum\lastboundary=\c_spac_keepspaces_boundary\else
     \boundary\c_spac_keepspaces_boundary
   \fi\fi}

\permanent\protected\def\removeunwantedspaces
  {\ifhmode
     \expandafter \spac_helpers_remove_unwantedspace
   \fi}

\def\spac_helpers_remove_unwantedspace
  {\ifnum\lastboundary=\c_spac_keepspaces_boundary
     \expandafter\unboundary
   \orunless\ifnum\lastnodetype=\gluenodecode
     % no skip
   \orelse\ifnum\lastnodesubtype=\indentskipsubtypecode
     % keep parindent
   \else
      \unskip
      \expandafter\spac_helpers_remove_unwantedspace
   \fi}

\permanent\protected\def\onlynonbreakablespace
  {\ifdim\lastskip=\interwordspace
     \unskip
     \nonbreakablespace
   \fi
   \ignorespaces}

% \startbuffer
% \startlines \tt \fixedspaces
%  0~1~~2~~~3~~~~4~~~~~5
%  0~~~~~~~~~~~~~~~~~~~5
% $0~1~~2~~~3~~~~4~~~~~5$
% $0~~~~~~~~~~~~~~~~~~~5$
% \stoplines
%
% \starttabulate[|~|]
% \NC  0~1~~2~~~3~~~~4~~~~~5  \NC \NR \NC  0~~~~~~~~~~~~~~~~~~~5  \NC \NR
% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \NR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \NR
% \stoptabulate
%
% \starttable[||]
% \NC  0~1~~2~~~3~~~~4~~~~~5  \NC \AR \NC  0~~~~~~~~~~~~~~~~~~~5  \NC \AR
% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \AR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \AR
% \stoptable
% \stopbuffer
%
% \setupbodyfont[cmr] \getbuffer
% \setupbodyfont[lbr] \getbuffer

%D A couple of plain macros:

\ifdefined\enspace \else \permanent\protected\def\enspace{\kern .5\emwidth}       \fi
\ifdefined\emspace \else \permanent\protected\def\emspace{\kern   \emwidth}       \fi

\ifdefined\quad    \else \permanent\protected\def\quad   {\hskip  \emwidth\relax} \fi
\ifdefined\enskip  \else \permanent\protected\def\enskip {\hskip.5\emwidth\relax} \fi
\ifdefined\qquad   \else \permanent\protected\def\qquad  {\hskip 2\emwidth\relax} \fi

\permanent\protected\def\negenspace{\kern-.5\emwidth}
\permanent\protected\def\negemspace{\kern-  \emwidth}

% \aliased\let\emspace\quad

\permanent\protected\def\charspace{ } % the unexpandable \space (as space can also be delimiter for numbers)

\permanent\tolerant\protected\def\quads[#1]% we do robust checking
  {\dontleavehmode
   \begingroup
  %\scratchcounter\ifparameter#1\or#1\else\plusthree\fi
   \scratchcounter\ifchknumber#1\or\lastchknumber\else\plusthree\fi
   \zwj\dorecurse\scratchcounter{\hskip\emwidth\zwj}%
   \endgroup}

% Suggested by GB (not the name) so we keep it for sentimental reasons:

\permanent\protected\def\rapfillskip{.5\hsize plus .092\hsize minus .5\hsize} % D.A.'s value

% Bovendien definieren we enkele extra \fill's:

\newgluespec\s_spac_fi         \s_spac_fi        \zeropoint \s!plus 1\s!fi   \relax
\newgluespec\s_spac_fil        \s_spac_fil       \zeropoint \s!plus 1\s!fil  \relax
\newgluespec\s_spac_fill       \s_spac_fill      \zeropoint \s!plus 1\s!fill \relax
\newgluespec\s_spac_filll      \s_spac_filll     \zeropoint \s!plus 1\s!filll\relax

\newgluespec\s_spac_neg_fi     \s_spac_neg_fi    \zeropoint \s!plus-1\s!fi  \relax
\newgluespec\s_spac_neg_fil    \s_spac_neg_fil   \zeropoint \s!plus-1\s!fil  \relax
\newgluespec\s_spac_neg_fill   \s_spac_neg_fill  \zeropoint \s!plus-1\s!fill \relax
\newgluespec\s_spac_neg_filll  \s_spac_neg_filll \zeropoint \s!plus-1\s!filll\relax

\permanent\protected\untraced\def\hfilll   {\hskip\s_spac_filll\relax}
\permanent\protected\untraced\def\vfilll   {\vskip\s_spac_filll\relax}

\permanent\protected\untraced\def\hfillneg {\hskip\s_spac_neg_fill \relax}
\permanent\protected\untraced\def\hfilllneg{\hskip\s_spac_neg_filll\relax}
\permanent\protected\untraced\def\vfillneg {\vskip\s_spac_neg_fill \relax}
\permanent\protected\untraced\def\vfilllneg{\vskip\s_spac_neg_filll\relax}

\permanent\protected\def\tfskip    {\begingroup\tf\hskip\emwidth\endgroup}
\permanent\protected\def\dotfskip#1{\begingroup\tf\hskip      #1\endgroup} % used elsewhere

% maybe we should hash the analysis

\installcorenamespace{narrower}
\installcorenamespace{narrowermethod}

\newgluespec\s_spac_narrower_left
\newgluespec\s_spac_narrower_right
\newgluespec\s_spac_narrower_middle

\installcommandhandler \??narrower {narrower} \??narrower

\setupnarrower
  [\c!before=\endgraf,
   \c!after=\endgraf,
   \c!left=1.5\emwidth,
   \c!right=1.5\emwidth,
   \c!middle=1.5\emwidth,
   \c!default=\v!middle]

\appendtoks
   \protected\frozen\instance\edefcsname\e!start\currentnarrower\endcsname{\spac_narrower_start[\currentnarrower]}%
   \protected\frozen\instance\edefcsname\e!stop \currentnarrower\endcsname{\spac_narrower_stop}%
\to \everydefinenarrower

\permanent\protected\def\installnarrowermethod#1#2%
  {\defcsname\??narrowermethod#1\endcsname{#2}}

\protected\def\spac_narrower_method_analyze#1%
  {\ifcsname\??narrowermethod#1\endcsname
     \lastnamedcs
   \else
     \global\advanceby\s_spac_narrower_middle#1\relax
   \fi}

\def\spac_narrower_initialize[#1]% hm, can be dorepeat directly
  {\dorepeatwithcommand[#1]\spac_narrower_method_analyze}

\installnarrowermethod  \v!left   {\global\advanceby\s_spac_narrower_left   \narrowerparameter\c!left  \relax}
\installnarrowermethod  \v!middle {\global\advanceby\s_spac_narrower_middle \narrowerparameter\c!middle\relax}
\installnarrowermethod  \v!right  {\global\advanceby\s_spac_narrower_right  \narrowerparameter\c!right \relax}
\installnarrowermethod{-\v!left  }{\global\advanceby\s_spac_narrower_left  -\narrowerparameter\c!left  \relax}
\installnarrowermethod{-\v!middle}{\global\advanceby\s_spac_narrower_middle-\narrowerparameter\c!middle\relax}
\installnarrowermethod{-\v!right }{\global\advanceby\s_spac_narrower_right -\narrowerparameter\c!right \relax}
\installnarrowermethod  \v!reset  {\global          \s_spac_narrower_left   \zeroskip
                                   \global          \s_spac_narrower_middle \zeroskip
                                   \global          \s_spac_narrower_right  \zeroskip\relax}
\installnarrowermethod \v!none    {}
\installnarrowermethod \v!reverse {} % never seen

\permanent\overloaded\tolerant\protected\def\spac_narrower_start[#1]#*[#2]%
  {\begingroup
   \cdef\currentnarrower{#1}%
   \ifparameter#2\or
     \spac_narrower_start_apply{#2}%
   \else
     \spac_narrower_start_apply{\narrowerparameter\v!default}%
   \fi}

\newgluespec   \s_spac_narrower_left_last
\newgluespec   \s_spac_narrower_right_last
\newconditional\s_spac_narrower_last_swap

\def\spac_narrower_start_apply#1%
  {\narrowerparameter\c!before
   \global\s_spac_narrower_left  \zeroskip
   \global\s_spac_narrower_right \zeroskip
   \global\s_spac_narrower_middle\zeroskip
   \edef\scratchstringone{#1}%
   \ifx\scratchstringone\v!reverse
     \ifconditional\s_spac_narrower_last_swap
       \frozen\leftskip \s_spac_narrower_right_last
       \frozen\rightskip\s_spac_narrower_left_last
       \s_spac_narrower_last_swap\conditionalfalse
     \else
       \frozen\leftskip \s_spac_narrower_left_last
       \frozen\rightskip\s_spac_narrower_right_last
       \s_spac_narrower_last_swap\conditionaltrue
     \fi
   \else
     \expanded{\processcommalistwithparameters[\scratchstringone]}\spac_narrower_initialize
     \frozen\advanceby\leftskip {\s_spac_narrower_left +\s_spac_narrower_middle}%
     \frozen\advanceby\rightskip{\s_spac_narrower_right+\s_spac_narrower_middle}%
   \fi
   \seteffectivehsize
   \dostarttagged\t!narrower\currentnarrower}

\permanent\protected\def\spac_narrower_stop
  {\dostoptagged
   \narrowerparameter\c!after
   \expanded{%
      \endgroup
      \s_spac_narrower_left_last \the\leftskip \relax
      \s_spac_narrower_right_last\the\rightskip\relax
      \ifconditional\s_spac_narrower_last_swap
        \s_spac_narrower_last_swap\conditionalfalse
      \else
        \s_spac_narrower_last_swap\conditionaltrue
      \fi
   }}

\permanent\tolerant\protected\def\startnarrower[#1]%
  {\begingroup
   \lettonothing\currentnarrower
   \ifparameter#1\or
     \spac_narrower_start_apply{#1}%
   \else
     \spac_narrower_start_apply{\narrowerparameter\v!default}%
   \fi}

\aliased\let\stopnarrower\spac_narrower_stop

\permanent\tolerant\protected\def\startnarrow[#S#1]#*[#S#2]% current how
  {\begingroup
   \ifnum\lastarguments=\plustwo
      \expandafter\spac_narrower_start_named_two
   \else
      \expandafter\spac_narrower_start_named_one
   \fi[#1][#2]}

% we can combine these:

\def\spac_narrower_start_named_one[#S#1]%
  {\doifelseassignment{#1}\spac_narrower_start_named_one_yes\spac_narrower_start_named_one_nop[#1]}

\def\spac_narrower_start_named_one_yes[#S#1][#2]% [settings] []
  {\setupcurrentnarrower[#1]%
   \spac_narrower_start_apply{\narrowerparameter\v!default}}

\def\spac_narrower_start_named_one_nop[#1][#2]% [tag] []
  {\cdef\currentnarrower{#1}%
   \spac_narrower_start_apply{\narrowerparameter\v!default}}

\def\spac_narrower_start_named_two[#S#1]%
  {\doifelseassignment{#1}\spac_narrower_start_named_settings_how\spac_narrower_start_named_tag_unknown[#1]}

\def\spac_narrower_start_named_settings_how[#S#1][#2]% [settings] [how]
  {\setupcurrentnarrower[#1]%
   \spac_narrower_start_apply{#2}}

\def\spac_narrower_start_named_tag_unknown[#1][#S#2]% [tag] [...]
  {\doifelseassignment{#2}\spac_narrower_start_named_tag_settings\spac_narrower_start_named_tag_how[#1][#2]}

\def\spac_narrower_start_named_tag_settings[#1][#S#2]% [tag] [settings]
  {\cdef\currentnarrower{#1}%
   \setupcurrentnarrower[#2]%
   \spac_narrower_start_apply{\narrowerparameter\v!default}}

\def\spac_narrower_start_named_tag_how[#1][#2]% [tag] [how]
  {\cdef\currentnarrower{#1}%
   \spac_narrower_start_apply{#2}}

\aliased\let\stopnarrow\spac_narrower_stop

\newdimension\d_spac_effective_hsize     \permanent\protected\def\effectivehsize    {\hsize}
\newdimension\d_spac_effective_leftskip  \permanent\protected\def\effectiveleftskip {\leftskip}
\newdimension\d_spac_effective_rightskip \permanent\protected\def\effectiverightskip{\rightskip}

\permanent\protected\def\seteffectivehsize
  {\setlocalhsize
   \d_spac_effective_hsize     \localhsize
   \d_spac_effective_leftskip 1\leftskip
   \d_spac_effective_rightskip1\rightskip
   \enforced\let\effectivehsize    \d_spac_effective_hsize
   \enforced\let\effectiveleftskip \d_spac_effective_leftskip
   \enforced\let\effectiverightskip\d_spac_effective_rightskip}

\installcorenamespace{skipadaptionleft}
\installcorenamespace{skipadaptionright}

\newgluespec\leftskipadaption
\newgluespec\rightskipadaption

\defcsname\??skipadaptionleft \v!yes\endcsname{\ifzeropt\d_spac_indentation_par\narrowerparameter\c!left\else\d_spac_indentation_par\fi}
\letcsname\??skipadaptionleft \v!no \endcsname\zeropoint % \zeroskip
\letcsname\??skipadaptionleft \empty\endcsname\zeropoint % \zeroskip
\defcsname\??skipadaptionright\v!yes\endcsname{\narrowerparameter\c!right}
\letcsname\??skipadaptionright\v!no \endcsname\zeropoint % \zeroskip
\letcsname\??skipadaptionright\empty\endcsname\zeropoint % \zeroskip

\letcsname\??skipadaptionleft \v!standard\expandafter\endcsname\csname\??skipadaptionleft \v!yes\endcsname
\letcsname\??skipadaptionright\v!standard\expandafter\endcsname\csname\??skipadaptionright\v!yes\endcsname

\permanent\protected\def\dosetleftskipadaption #1{\leftskipadaption \glueexpr\ifcsname\??skipadaptionleft #1\endcsname\lastnamedcs\else#1\fi\relax}
\permanent\protected\def\dosetrightskipadaption#1{\rightskipadaption\glueexpr\ifcsname\??skipadaptionright#1\endcsname\lastnamedcs\else#1\fi\relax}

\permanent\protected\def\doadaptleftskip #1{\expanded{\dosetleftskipadaption {#1}}\frozen\advanceby\leftskip \leftskipadaption }
\permanent\protected\def\doadaptrightskip#1{\expanded{\dosetrightskipadaption{#1}}\frozen\advanceby\rightskip\rightskipadaption}

\permanent\protected\def\forgetbothskips
  {\leftskip \zeroskip
   \rightskip\zeroskip
   \relax}

\appendtoks
    \forgetbothskips
\to \everyforgetall

%D In \type {spac-ver.mkiv} we define \type {\forgetparskip} and do this:
%D
%D \starttyping
%D \appendtoks
%D     \forgetparskip
%D \to \everyforgetall
%D \stoptyping

%D Tolerance (can also be set with align):

\installcorenamespace{tolerancemethods}

\mutable\lettonothing\bottomtolerance % why not zero (not used annyway, but for now we keep it)

\permanent\protected\def\installtolerancemethod#1#2#3%
  {\defcsname\??tolerancemethods#1:#2\endcsname{#3}}

\installtolerancemethod \v!vertical   \v!verystrict   {\lettonothing\bottomtolerance} % why not zero
\installtolerancemethod \v!vertical   \v!strict       {\def\bottomtolerance{.050}}
\installtolerancemethod \v!vertical   \v!tolerant     {\def\bottomtolerance{.075}}
\installtolerancemethod \v!vertical   \v!verytolerant {\def\bottomtolerance{.100}}

\installtolerancemethod \v!horizontal \v!stretch      {\emergencystretch\bodyfontsize\relax}
\installtolerancemethod \v!horizontal \v!space        {\spaceskip.5em\s!plus.25em\s!minus.25em\relax}
\installtolerancemethod \v!horizontal \v!verystrict   {\tolerance\plustwohundred}
\installtolerancemethod \v!horizontal \v!strict       {\tolerance1500 }
\installtolerancemethod \v!horizontal \v!tolerant     {\tolerance3000 }
\installtolerancemethod \v!horizontal \v!verytolerant {\tolerance4500 }

\appendetoks
     \pretolerance\plushundred
     \tolerance   \plustwohundred
\to\everyforgetall

\def\spac_tolerances_step_vertical  #1{\csname\??tolerancemethods\v!vertical  :#1\endcsname}
\def\spac_tolerances_step_horizontal#1{\csname\??tolerancemethods\v!horizontal:#1\endcsname}

\permanent\tolerant\protected\def\setuptolerance[#1]%
  {\ifarguments\or
     \ifinset\v!vertical{#1}%
       \processcommacommand[#1]\spac_tolerances_step_vertical
     \else
       \processcommacommand[#1]\spac_tolerances_step_horizontal
     \fi
   \fi}

% %D \macros
% %D   {pushindentation,popindentation}
% %D
% %D The pushing and popping is done by:
%
% \newbox\b_spac_indentations_a
% \newbox\b_spac_indentations_b
%
% \permanent\protected\def\pushindentation
%   {\begingroup
%    \ifhmode
%      \unskip
%      \setbox\b_spac_indentations_a\lastbox       % get \strut if present
%      \unskip
%      \setbox\b_spac_indentations_b\lastbox       % get \indent generated box
%      \unskip
%    \else
%      \dontleavehmode % was \hskip\zeroskip       % switch to horizontal mode
%      \unskip
%      \setbox\b_spac_indentations_a\lastbox       % get \indent generated box
%      \setbox\b_spac_indentations_b\emptybox
%    \fi}
%
% \permanent\protected\def\popindentation
%   {\box\b_spac_indentations_b
%    \box\b_spac_indentations_a
%    \endgroup}

%D Struts are done differently now.
%D
%D The only complication lays in \type{\strut}. In \PLAIN\ \TEX\ a \type{\strut} is
%D defined as:
%D
%D \starttyping
%D \def\strut%
%D   {\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
%D \stoptyping
%D
%D But what is a \type {\strut}? Normally it's a rule of width zero, but when made
%D visual, it's a rule and a negative skip. The mechanism for putting things in the
%D margins described here cannot handle this situation very well. One characteristic
%D of \type {\strut} is that the \type {\unhcopy} results in entering horizontal
%D mode, which in return leads to some indentation.
%D
%D To serve our purpose a bit better, the macro \type {\strut} can be redefined as:
%D \starttyping
%D \def\strut
%D   {\relax\ifmmode\else\hskip\zeroskip\fi\copy\strutbox}
%D \stoptyping
%D
%D Or more compatible:
%D
%D \starttyping
%D \def\strut
%D   {\relax\ifmmode
%D      \copy\strutbox
%D    \else
%D      \bgroup\setbox\strutbox=\hbox{\box\strutbox}\unhcopy\strutbox\egroup
%D    \fi}
%D \stoptyping
%D
%D In \CONTEXT\ however we save some processing time by putting an extra \type
%D {\hbox} around the \type {\strutbox}.
%D
%D \starttyping
%D % \setuplayout[gridgrid=yes] \showgrid
%D
%D \startbuffer
%D test 1\crlf
%D test 2\crlf
%D
%D \crlf test 3
%D
%D test 4\crlf
%D test 5
%D
%D \crlf
%D \crlf
%D \crlf
%D test 6
%D \stopbuffer
%D
%D \hbox
%D   {\hsize5em
%D    \ruledvtop{\getbuffer}\enspace
%D    \ruledvtop{\showstruts\getbuffer}\enspace
%D    \hsize15em \setuptyping[before=,after=]%
%D    \ruledvtop{\typebuffer}}
%D \stoptyping

\permanent\protected\def\justonespace{\removeunwantedspaces\space}
%permanent\protected\def\justaperiod {\removeunwantedspaces.}
%permanent\protected\def\justacomma  {\removeunwantedspaces,}

\installcorenamespace{hspace}

\permanent\protected\def\ignorecrlf
  {\enforced\let\crlf\justonespace
   \enforced\let\\\crlf}

\permanent\tolerant\protected\def\definehspace[#1]#*[#2]#*[#3]% #1 = optional namespace
  {\ifparameter#3\or
     \defcsname\??hspace#1:#2\endcsname{#3}%
   \else
     \defcsname\??hspace  :#1\endcsname{#2}%
   \fi}

\permanent\tolerant\protected\def\hspace[#1]#*[#2]%
  {\ifhmode
     \removeunwantedspaces
     \hskip % always a skip even when 0pt
       \ifparameter#2\or
         \hspaceamount{#1}{#2}%
       \orelse\ifparameter#1\or
         \hspaceamount\empty{#1}%
       \else
         \hspaceamount\empty\s!default
       \fi
     \relax
     \expandafter\ignorespaces
   \fi}

\permanent\overloaded\def\hspaceamount      #1#2{\dimexpr\ifcsname\??hspace#1:#2\endcsname\lastnamedcs\else\zeropoint\fi\relax}
\permanent\overloaded\def\directhspaceamount  #1{\dimexpr\ifcsname\??hspace  :#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}

% no installhspace here (this is already an old command)

\definehspace [\v!small]   [.25\emspaceamount]
\definehspace [\v!medium]  [.5\emspaceamount]
\definehspace [\v!big]     [1\emspaceamount]
\definehspace [\v!normal]  [1\spaceamount]
\definehspace [\v!default] [\spaceamount]
\definehspace [\v!none]    [\zeropoint] % \zeroskip

%D Taken from Taco's math module (cq. \AMS\ macros), but %D adapted to \type
%D {\hspace}:

\permanent\protected\def\textormathspace         #1#2#3{\ifmmode\mskip#1#2\else\kern #1\hspaceamount\empty{#3}\fi\relax}
\permanent\protected\def\textormathspacecommand  #1#2#3{\ifmmode\mskip#1#2\else#3\fi\relax}
\permanent\protected\def\breakabletextormathspace#1#2#3{\ifmmode\mskip#1#2\else\hskip#1\hspaceamount\empty{#3}\fi\relax}

\overloaded\permanent\protected \def\hairspace    {\textormathspace+\hairmuskip{.5}}
\overloaded\permanent\protected \def\thinspace    {\textormathspace+\thinmuskip 1}
%overloaded\permanent\protected \def\medspace     {\textormathspace+\medmuskip  2}      % 4/18 em
\overloaded\permanent\protected \def\thickspace   {\textormathspace+\thickmuskip3}
\overloaded\permanent\protected \def\neghairspace {\textormathspace-\thinmuskip{.5}}
\overloaded\permanent\protected \def\negthinspace {\textormathspace-\thinmuskip 1}
\overloaded\permanent\protected \def\negmedspace  {\textormathspace-\medmuskip  2}
\overloaded\permanent\protected \def\negthickspace{\textormathspace-\thickmuskip3}
\overloaded\permanent\protected\edef\medspace     {\textormathspacecommand+\medmuskip{\tocharacter"205F}}

% maybe

% \protected\def\breakablethinskip      {\breakabletextormathspace+\thinmuskip1}
% \protected\def\twoperemskip           {\hskip\dimexpr\emwidth/2\relax} % == \enspace
% \protected\def\threeperemskip         {\hskip\dimexpr\emwidth/3\relax}
% \protected\def\fourperemskip          {\hskip\dimexpr\emwidth/4\relax}
% \protected\def\fiveperemskip          {\hskip\dimexpr\emwidth/5\relax} % goodie
% \protected\def\sixperemskip           {\hskip\dimexpr\emwidth/6\relax}
% \protected\def\figureskip             {\begingroup\setbox\scratchbox\hbox{0}\hskip\wd\scratchbox\endgroup} % there is a command for this
% \protected\def\punctuationskip        {\begingroup\setbox\scratchbox\hbox{.}\hskip\wd\scratchbox\endgroup}
% \protected\def\ideographicskip        {\hskip\dimexpr\emwidth/1\relax}
% \protected\def\ideographichalffillskip{\hskip\dimexpr\emwidth/2\relax}
% \protected\def\nobreakskip            {\penalty\plustenthousand\kern\interwordspace}
% \protected\def\narrownobreakskip      {\penalty\plustenthousand\thinspace}
% \protected\def\zerowidthnobreakskip   {\penalty\plustenthousand\kern\zeropoint}
% \protected\def\zerowidthskip          {\hskip\zeroskip}

\definehspace[.5][.1250\emwidth] % hair
\definehspace[1] [.1667\emwidth] % thin
\definehspace[2] [.2222\emwidth] % med
\definehspace[3] [.2777\emwidth] % thick

% These will be redefined anyway in math-ini:

\suggestedalias \, \thinspace
\suggestedalias \: \medspace
\suggestedalias \; \thickspace
\suggestedalias \! \negthinspace

% plain ...
%
% \ifdefined\> \else \protected\def\>{\mskip \medmuskip  }                                \fi
% \ifdefined\* \else \protected\def\*{\discretionary{\thinspace\the\textfont2\char2}{}{}} \fi

\permanent\def\flexiblespaceamount#1#2#3%
         {#1\interwordspace
   \s!plus#2\interwordstretch
  \s!minus#3\interwordshrink}

\permanent\def\fixedspaceamount#1%
  {#1\interwordspace}

% moved from page-lin
%
% the following code is used in startlines\stoplines
%
% do we need \normalspaceprimitive here?

\installcorenamespace{spacemethods}

\permanent\protected\def\installspacemethod#1#2% needs to set \obeyedspace
  {\defcsname\??spacemethods#1\endcsname{#2}}

\permanent\def\activatespacehandler#1%
  {\csname\??spacemethods\ifcsname\??spacemethods#1\endcsname#1\else\v!off\fi\endcsname}

\permanent\protected\def\spac_spaces_checked_control{\mathortext\normalspace{\dontleavehmode{\tt\controlspace}}}%
\permanent\protected\def\spac_spaces_checked_normal {\mathortext\normalspace{\dontleavehmode\normalspace}}%
\permanent\protected\def\spac_spaces_checked_fixed  {\mathortext\normalspace{\dontleavehmode\fixedspace}}%

% hm, order matters when we \let in \obeyspaces

\installspacemethod \v!on
  {\obeyspaces
   \enforced\let\obeyedspace\spac_spaces_checked_control
   \enforced\let\ =\obeyedspace}

\installspacemethod \v!yes
  {\obeyspaces
   \enforced\let\obeyedspace\spac_spaces_checked_normal
   \enforced\let\ =\obeyedspace}

\installspacemethod \v!off % == default
  {\normalspaces
   \enforced\let\obeyedspace\normalspace
   \enforced\let\ =\normalspaceprimitive} % was \normalspace

\installspacemethod \v!fixed
  {\obeyspaces
   \enforced\let\obeyedspace\spac_spaces_checked_fixed
   \enforced\let\ =\obeyedspace}

\appendtoks
   \normalspaces % to be sure
\to \everybeforeoutput

%D A more robust variant of the \MKII\ one:
%D
%D \startbuffer
%D bla \TEX\autoinsertnextspace bla
%D bla \TEX\autoinsertnextspace (bla)
%D bla (\TEX\autoinsertnextspace) bla
%D bla \TEX\autoinsertnextspace\ bla
%D \stopbuffer
%D
%D \typebuffer \getbuffer

% \autoinsertnextspace % defined at the lua end

%D Moved from bib module:

\permanent\protected\def\outdented#1%
  {\hskip-\hangindent#1\relax}

%D Beware: due to char-def this becomes an active character but that might change
%D sometime when we will replace all these specials to node insertions. We might
%D even expand it to utf then as it then can be used in string comparison (not that
%D much needed anyway).

% \chardef\zwnj="200C
% \chardef\zwj ="200D

% TODO (but used in languages):

\def\spac_glues_text_or_math#1#2%
  {\begingroup
   \ifmmode
     \mskip#1%
   \else
     \scratchdimen#1\hspaceamount\empty{#2}%
     \scratchskip\scratchdimen\s!plus.5\scratchdimen\s!minus.3\scratchdimen
     \hskip\scratchskip
   \fi
   \endgroup}

\permanent\protected\def\thinglue {\spac_glues_text_or_math\thinmuskip \v!small}
\permanent\protected\def\medglue  {\spac_glues_text_or_math\medmuskip  \v!medium}
\permanent\protected\def\thickglue{\spac_glues_text_or_math\thickmuskip\v!big}

%D A rather unknown one:

\permanent\protected\def\widened % moved from cont-new
  {\doifelsenextoptionalcs\spac_widened_yes\spac_widened_nop}

\def\spac_widened_yes[#1]#2{\hbox \s!spread       #1{\hss#2\hss}}
\def\spac_widened_nop    #1{\hbox \s!spread \emwidth{\hss#1\hss}}

%D For the moment here (used in page-txt):

\permanent\protected\def\ignoredlinebreak{\unskip\space\ignorespaces}

%D \macros
%D   {startignorespaces}
%D
%D I'll probably forget that this one exists:
%D
%D \starttyping
%D \ruledhbox
%D   {\startignorespaces
%D      \def\oeps{a}
%D      \startignorespaces
%D        \def\oeps{a}
%D      \stopignorespaces
%D      \def\oeps{a}
%D    \stopignorespaces
%D    \oeps}
%D \stoptyping

% \newsignal \d_spac_ignore_spaces_signal
% \newinteger\c_spac_ignore_spaces
%
% \permanent\protected\def\startignorespaces
%   {\advanceby\c_spac_ignore_spaces\plusone
%    \ifcase\c_spac_ignore_spaces\or \ifhmode
%      \hskip\d_spac_ignore_spaces_signal
%    \fi \fi
%    \ignorespaces}
%
% \permanent\protected\def\stopignorespaces
%   {\ifcase\c_spac_ignore_spaces \or
%      \ifhmode
%        \doloop\spac_ignore_spaces_body
%      \fi
%    \fi
%    \advanceby\c_spac_ignore_spaces\minusone}
%
% \def\spac_ignore_spaces_body
%   {\ifzeropt\lastskip
%      \exitloop
%    \orelse\ifdim\lastskip=\d_spac_ignore_spaces_signal
%      \unskip
%      \exitloop
%    \else
%      \unskip
%    \fi}

\permanent\protected\def\startignorespaces
  {\pushmacro\nospaces
   \nospaces\plusone}

\permanent\protected\def\stopignorespaces
  {\popmacro\nospaces}

%D \macros
%D   {obeyfollowingtoken}

\permanent\def\obeyfollowingtoken{{}}  % end \cs scanning

%D Something new:

\permanent\protected\def\interwordspacebefore{\wordboundary\zwnj\hskip\interwordspace\relax}
\permanent\protected\def\interwordspaceafter {\hskip\interwordspace\relax\zwnj\wordboundary}

\permanent\protected\def\interwordspacesbefore#1{\dofastloopcs{#1}\interwordspacebefore} % todo: native loop
\permanent\protected\def\interwordspacesafter #1{\dofastloopcs{#1}\interwordspaceafter} % todo: native loop
\permanent\protected\def\interwordspaces      #1{\wordboundary\zwnj\dofastloopcs{#1+\minusone}\interwordspaceafter}  % todo: native loop

%D For mp:

\installcorenamespace{mplocation}

\defcsname\??mplocation\v!left \endcsname{1}
\defcsname\??mplocation\v!right\endcsname{2}
\defcsname\??mplocation\v!inner\endcsname{3}
\defcsname\??mplocation\v!outer\endcsname{4}

\permanent\def\mplocation#1{\ifcsname\??mplocation#1\endcsname\lastnamedcs\else0\fi}
%permanent\def\mplocation#1{\csname\??mplocation\ifcsname\??mplocation#1\endcsname#1\else\v!left\fi\endcsname}

% new: \lateindent \lateundent

% \parinitleftskip1cm \parindent 1cm \indent test \par
% \parinitleftskip1cm \parindent 1cm \undent test \par
% \parinitleftskip1cm \parindent 1cm \indent \undent test \par
% \parinitleftskip1cm \parindent 1cm \indent \strut \undent test \par
% \parinitleftskip1cm \parindent 1cm \strut \lateindent 2cm test \par
% \parinitleftskip1cm \parindent 1cm \strut \lateindent 2cm test \lateundent \par

\protect \endinput
