%D \module
%D   [       file=core-env, % was core-new
%D        version=1995.01.01, % wrong
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=New ones,
%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 Core Macros / Environments}

\installcorenamespace{setup} % is referenced in the lmt file:

\registerctxluafile{core-env}{autosuffix}

\unprotect

%D Modes:
%D
%D \starttyping
%D \enablemode[screen,paper,bound]
%D
%D \doifmodeelse {paper}        {this} {that}
%D \doifmode     {paper,screen} {this}
%D \doifnotmode  {paper,bound}  {that}
%D
%D \startmode [list]
%D \stopmode
%D
%D \startnotmode [list]
%D \stopnotmode
%D \stoptyping
%D
%D system modes have a * as prefix
%D
%D Sometimes, we want to prevent a mode for being set. Think of situations where a
%D style enables a mode, but an outer level style does not want that. Preventing can
%D be considered a permanent disabling on forehand.

\aliased\let\systemmodeprefix\wildcardsymbol

% we will have \installcorenamespace{mode} but need some hackery at the lua end then

% TODO: make them mutable, also at the lua end

\installcorenamespace{modestack}

\immutable\def\??mode{mode>} % special namespace, also used at lua end

\permanent\protected\def\newmode              #1{\ifcsname                            \??mode#1\endcsname\else\resetmode{#1}\fi}
\permanent\protected\def\setmode              #1{\expandafter       \integerdef\csname\??mode#1\endcsname\plusone}
\permanent\protected\def\resetmode            #1{\expandafter       \integerdef\csname\??mode#1\endcsname\zerocount}
\permanent\protected\def\globalsetmode        #1{\global\expandafter\integerdef\csname\??mode#1\endcsname\plusone}
\permanent\protected\def\globalresetmode      #1{\global\expandafter\integerdef\csname\??mode#1\endcsname\zerocount}

\permanent\protected\def\newsystemmode        #1{\ifcsname                            \??mode\systemmodeprefix#1\endcsname\else\resetsystemmode{#1}\fi}
\permanent\protected\def\setsystemmode        #1{\expandafter       \integerdef\csname\??mode\systemmodeprefix#1\endcsname\plusone}
\permanent\protected\def\resetsystemmode      #1{\expandafter       \integerdef\csname\??mode\systemmodeprefix#1\endcsname\zerocount}
\permanent\protected\def\globalsetsystemmode  #1{\global\expandafter\integerdef\csname\??mode\systemmodeprefix#1\endcsname\plusone}
\permanent\protected\def\globalresetsystemmode#1{\global\expandafter\integerdef\csname\??mode\systemmodeprefix#1\endcsname\zerocount}

\expandafter \appendtoks
    \expandafter\integerdef\csname\??mode\systemmodeprefix trialtypesetting\endcsname\plusone
    \luacopyinputnodes\plusone
\to \everysettrialtypesetting

\expandafter \appendtoks
    \expandafter\integerdef\csname\??mode\systemmodeprefix trialtypesetting\endcsname\zerocount
    \luacopyinputnodes\zerocount
\to \everyresettrialtypesetting

\pushoverloadmode \newsystemmode{trialtypesetting} \popoverloadmode

\the\everyresettrialtypesetting

% user ones

\mutable\let\syst_mode_prefix\relax

\permanent\protected\def\preventmode{\unprotect\syst_modes_prevent}
\permanent\protected\def\enablemode {\unprotect\syst_modes_enable }
\permanent\protected\def\disablemode{\unprotect\syst_modes_disable}

\permanent\protected\def\globalpreventmode{\let\syst_mode_prefix\global\unprotect\syst_modes_prevent}
\permanent\protected\def\globalenablemode {\let\syst_mode_prefix\global\unprotect\syst_modes_enable }
\permanent\protected\def\globaldisablemode{\let\syst_mode_prefix\global\unprotect\syst_modes_disable}

\def\syst_modes_prevent[#1]{\protect\fastprocesscommacommand[#1]\syst_modes_prevent_indeed\let\syst_mode_prefix\relax}
\def\syst_modes_enable [#1]{\protect\fastprocesscommacommand[#1]\syst_modes_enable_indeed \let\syst_mode_prefix\relax}
\def\syst_modes_disable[#1]{\protect\fastprocesscommacommand[#1]\syst_modes_disable_indeed\let\syst_mode_prefix\relax}

\def\syst_modes_prevent_indeed#1%
  {\ifcsname\??mode#1\endcsname\else\setmode{#1}\fi
   \syst_mode_prefix\expandafter\integerdef\lastnamedcs\plustwo}

\def\syst_modes_enable_indeed#1% we can speed it up by moving the new outside
  {\ifcsname\??mode#1\endcsname\else\setmode{#1}\fi
   \ifnum\lastnamedcs=\plustwo\else
     \syst_mode_prefix\expandafter\integerdef\lastnamedcs\plusone
   \fi}

\def\syst_modes_disable_indeed#1%
  {\ifcsname\??mode#1\endcsname\else\setmode{#1}\fi
   \ifnum\lastnamedcs=\plustwo\else
     \syst_mode_prefix\expandafter\integerdef\lastnamedcs\zerocount
   \fi}

%D If you do a lot of mode testing, it makes sense to define modes (or disable them
%D explicitly if unset. This makes testing twice as fast. Often one enables modes
%D beforehand, in which case \type {\definemode} would reset the mode. The optional
%D second argument \type {keep} will prevent changing the already set mode but defines
%D it when undefined.

\permanent\protected\def\definemode
  {\unprotect
   \syst_modes_define}

\tolerant\def\syst_modes_define[#1]#*[#2]%
  {\protect
   \edef\m_modes_asked{#2}%
   \fastprocesscommacommand[#1]\syst_modes_define_indeed}

\def\syst_modes_define_indeed#1%
  {\ifcsname\??mode#1\endcsname
     % already set
   \else
     \newmode{#1}%
   \fi
   \ifx\m_modes_asked\v!keep
     % not changes, disabled when undefined
   \orelse\ifx\m_modes_asked\v!yes
     \setmode{#1}%
   \else
     \resetmode{#1}%
   \fi}

% handy for mp

\permanent\def\booleanmodevalue#1%
  {\ifcsname\??mode#1\endcsname
     \ifcase\lastnamedcs
       \s!false
     \or
       \s!true
     \else
       \s!false
     \fi
   \else
     \s!false
   \fi}

% check macros

\newconditional\c_checked_mode

% one

\def\syst_modes_check_indeed#1%
  {\ifcsname\??mode#1\endcsname
     \ifcase\lastnamedcs\else
       \let\syst_modes_check_step\gobbleoneargument
     \fi
   \fi}

\def\syst_modes_check_nop#1#2#3%
  {\let\syst_modes_check_step\syst_modes_check_indeed
   \fastprocesscommacommand[#3]\syst_modes_check_step
   \ifx\syst_modes_check_step\gobbleoneargument
     \expandafter#1%
   \else
     \expandafter#2%
   \fi}

\def\syst_modes_check_yes#1#2#3%
  {\ifcase\lastnamedcs
     \expandafter#2%
   \or
     \expandafter#1%
   \else
     \expandafter#2%
   \fi}

\def\syst_modes_check_lr#1#2#3%
  {\ifcsname\??mode#3\endcsname
     \expandafter\syst_modes_check_yes
   \else
     \expandafter\syst_modes_check_nop
   \fi#1#2{#3}}

% \def\syst_modes_check_ss#1#2[#3]%
%   {\ifcsname\??mode#3\endcsname
%      \expandafter\syst_modes_check_yes
%    \else
%      \expandafter\syst_modes_check_nop
%    \fi#1#2{#3}}

% all

\let\syst_modes_check_all_step\gobbleoneargument

\def\syst_modes_check_all_indeed#1%
  {\ifcsname\??mode#1\endcsname
     \ifcase\lastnamedcs
       \let\syst_modes_check_all_step\gobbleoneargument
     \or
       % enabled
     \else
       \let\syst_modes_check_all_step\gobbleoneargument
     \fi
   \else
     \let\syst_modes_check_all_step\gobbleoneargument
   \fi}

% \def\syst_modes_check_all_lr#1#2#3%
%   {\let\syst_modes_check_all_step\syst_modes_check_all_indeed
%    \fastprocesscommacommand[#3]\syst_modes_check_all_step
%    \ifx\syst_modes_check_all_step\gobbleoneargument
%      \expandafter#2%
%    \else
%      \expandafter#1%
%    \fi}

% \def\syst_modes_check_all_ss#1#2[#3]%
%   {\let\syst_modes_check_all_step\syst_modes_check_all_indeed
%    \fastprocesscommacommand[#3]\syst_modes_check_all_step
%    \ifx\syst_modes_check_all_step\gobbleoneargument
%      \expandafter#2%
%    \else
%      \expandafter#1%
%    \fi}

% \enablemode[foomode]
% \enablemode[oofmode]
%
% \ifmode          {foomode}          YES  \else  NOP \fi \par
% \ifmodes         {oofmode,foomode}  YES  \else  NOP \fi \par
% \ifallmodes      {oofmode,foomode}  YES  \else  NOP \fi \par
% \doifelsemode    {foomode}         {YES}       {NOP}    \par
% \doifelsemode    {oofmode,foomode} {YES}       {NOP}    \par
% \doifelseallmodes{oofmode,foomode} {YES}       {NOP}    \par

% \permanent\protected\def\doifelsemode    {\syst_modes_check_lr    \firstoftwoarguments    \secondoftwoarguments}
% \permanent\protected\def\doifmode        {\syst_modes_check_lr    \firstofoneargument     \gobbleoneargument}
% \permanent\protected\def\doifnotmode     {\syst_modes_check_lr    \gobbleoneargument      \firstofoneargument}
% \permanent\protected\def\startmode       {\syst_modes_check_ss    \donothing              \syst_modes_stop_yes}
% \permanent\protected\def\startnotmode    {\syst_modes_check_ss    \syst_modes_stop_nop    \donothing}
% \permanent\protected\def\doifelseallmodes{\syst_modes_check_all_lr\firstoftwoarguments    \secondoftwoarguments}
% \permanent\protected\def\doifallmodes    {\syst_modes_check_all_lr\firstofoneargument     \gobbleoneargument}
% \permanent\protected\def\doifnotallmodes {\syst_modes_check_all_lr\gobbleoneargument      \firstofoneargument}
% \permanent\protected\def\startallmodes   {\syst_modes_check_all_ss\donothing              \syst_modes_stop_all_yes}
% \permanent\protected\def\startnotallmodes{\syst_modes_check_all_ss\syst_modes_stop_all_nop\donothing}
%
% \aliased\let\doifmodeelse    \doifelsemode
% \aliased\let\doifallmodeselse\doifelseallmodes
%
% \permanent\protected\def\stopmode       {} % no relax
% \permanent\protected\def\stopnotmode    {} % no relax
% \permanent\protected\def\stopallmodes   {} % no relax
% \permanent\protected\def\stopnotallmodes{} % no relax
%
% \def\syst_modes_stop_yes    #-\stopmode       {}
% \def\syst_modes_stop_nop    #-\stopnotmode    {}
% \def\syst_modes_stop_all_yes#-\stopallmodes   {}
% \def\syst_modes_stop_all_nop#-\stopnotallmodes{}

\permanent\protected\def\doifelsemode    #1{\ifmodes   {#1}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\permanent\protected\def\doifmode        #1{\ifmodes   {#1}\expandafter\firstofoneargument \else\expandafter\gobbleoneargument   \fi}
\permanent\protected\def\doifnotmode     #1{\ifmodes   {#1}\expandafter\gobbleoneargument  \else\expandafter\firstofoneargument  \fi}
\permanent\protected\def\doifelseallmodes#1{\ifallmodes{#1}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\permanent\protected\def\doifallmodes    #1{\ifallmodes{#1}\expandafter\firstofoneargument \else\expandafter\gobbleoneargument   \fi}
\permanent\protected\def\doifnotallmodes #1{\ifallmodes{#1}\expandafter\gobbleoneargument  \else\expandafter\firstofoneargument  \fi}

% \permanent\protected\def\startmode       [#1]{\ifmodes   {#1}\else\expandafter\ignoreupto\expandafter\stopmode       \fi}
% \permanent\protected\def\startallmodes   [#1]{\ifallmodes{#1}\else\expandafter\ignoreupto\expandafter\stopallmodes   \fi}
% \permanent\protected\def\startnotmode    [#1]{\ifmodes   {#1}\expandafter     \ignoreupto\expandafter\stopnotmode    \fi}
% \permanent\protected\def\startnotallmodes[#1]{\ifallmodes{#1}\expandafter     \ignoreupto\expandafter\stopnotallmodes\fi}

\permanent\protected\def\startmode       [#1]{\ifmodes   {#1}\else\expandafter\ignorenestedupto\expandafter\startmode       \expandafter\stopmode       \fi}
\permanent\protected\def\startallmodes   [#1]{\ifallmodes{#1}\else\expandafter\ignorenestedupto\expandafter\startallmodes   \expandafter\stopallmodes   \fi}
\permanent\protected\def\startnotmode    [#1]{\ifmodes   {#1}\expandafter     \ignorenestedupto\expandafter\startnotmode    \expandafter\stopnotmode    \fi}
\permanent\protected\def\startnotallmodes[#1]{\ifallmodes{#1}\expandafter     \ignorenestedupto\expandafter\startnotallmodes\expandafter\stopnotallmodes\fi}

\permanent\protected\def\stopmode       {} % no relax
\permanent\protected\def\stopnotmode    {} % no relax
\permanent\protected\def\stopallmodes   {} % no relax
\permanent\protected\def\stopnotallmodes{} % no relax

\aliased\let\doifmodeelse    \doifelsemode
\aliased\let\doifallmodeselse\doifelseallmodes

%D Pushing/popping:

\permanent\protected\def\pushmode[#1]{\expandafter\pushmacro\csname\??mode#1\endcsname}
\permanent\protected\def\popmode [#1]{\expandafter\popmacro \csname\??mode#1\endcsname}

\permanent\protected\def\pushsystemmode#1{\expandafter\pushmacro\csname\??mode\systemmodeprefix#1\endcsname}
\permanent\protected\def\popsystemmode #1{\expandafter\popmacro \csname\??mode\systemmodeprefix#1\endcsname}

%D Here is a relatively new variant of mode checking:
%D
%D \starttyping
%D \enablemode[two]
%D
%D \startmodeset
%D     [one]     {1}
%D     [two]     {2}
%D     [two]     {2}
%D     [three]   {3}
%D     [default] {?}
%D \stopmodeset
%D
%D \startmodeset
%D     [one]     {1}
%D     [three]   {3}
%D     [default] {?}
%D \stopmodeset
%D
%D \startmodeset
%D     [one] {
%D         \input tufte
%D     }
%D     [two] {
%D         \startmodeset
%D             [one]     {1}
%D             [two]     {2}
%D             [two]     {2}
%D             [three]   {3}
%D             [default] {?}
%D         \stopmodeset
%D     }
%D     [three] {
%D         \input zapf
%D     }
%D     [default] {
%D         \input ward
%D     }
%D \stopmodeset
%D \stoptyping

\newconditional\c_syst_modes_set_done % conditionals can be pushed/popped

\installmacrostack\c_syst_modes_set_done

\permanent\protected\def\startmodeset
  {\push_macro_c_syst_modes_set_done
   \c_syst_modes_set_done\conditionalfalse
   \syst_modes_set_start}

\permanent\protected\lettonothing\stopmodeset

\tolerant\def\syst_modes_set_start#.[#1]% skip spaces and pars
  {\edef\m_mode_case{#1}%
   \ifempty\m_mode_case
     \expandafter\syst_modes_set_quit
   \orunless\ifx\m_mode_case\s!default
     \expandafter\syst_modes_set_check
   \orelse\ifconditional\c_syst_modes_set_done
     \expandafter\syst_modes_set_quit
   \else
     \expandafter\syst_modes_set_yes
   \fi}

\def\syst_modes_set_check
  {\syst_modes_check_lr\syst_modes_set_yes\syst_modes_set_nop\m_mode_case}

\tolerant\def\syst_modes_set_yes#1%
  {\c_syst_modes_set_done\conditionaltrue
   #1%
   \syst_modes_set_start}

\tolerant\def\syst_modes_set_nop#1%
  {\syst_modes_set_start}

\def\syst_modes_set_quit#-\stopmodeset
  {\pop_macro_c_syst_modes_set_done}

%D Lets now set a few modes:

\enablemode[mkiv] \newsystemmode{mkiv} \setsystemmode{mkiv} % also mkxl
\enablemode[lmtx] \newsystemmode{lmtx} \setsystemmode{lmtx}

%D Setups:

% \installcorenamespace{setup} % we can probably get rid of some :'s later on

% \protected\def\startsetups{} % to please dep checker
% \protected\def\stopsetups {} % to please dep checker
%
% \protected\def\setups{\doifelsenextbgroup\syst_setups_a\syst_setups_b} % {..} or [..]
% \protected\def\setup {\doifelsenextbgroup\syst_setups  \syst_setups_c} % {..} or [..]
%
% \def\syst_setups_a  #1{\processcommacommand[#1]\syst_setups} % {..}
% \def\syst_setups_b[#1]{\processcommacommand[#1]\syst_setups} % [..]
% \def\syst_setups_c[#1]{\syst_setups{#1}} % [..]

\permanent\protected\tolerant\def\setups[#1]#;#2{\processcommacommand[#1#2]\syst_setups} % {..} or [..]
\permanent\protected\tolerant\def\setup [#1]#;#2{\syst_setups{#1#2}} % {..} or [..]

\letcsname\??setup:\??empty\endcsname\gobbleoneargument

\permanent\def\syst_setups#1% the grid option will be extended to other main modes
  {\begincsname\??setup
     \ifgridsnapping
       \ifcsname\??setup\v!grid:#1\endcsname\v!grid:#1\else:\ifcsname\??setup:#1\endcsname#1\else\??empty\fi\fi
     \else
                                                           :\ifcsname\??setup:#1\endcsname#1\else\??empty\fi
     \fi
   \endcsname\empty} % takes one argument

% no checking and we assume it being defined:

\permanent\def\fastsetup                     #1{\begincsname\??setup:#1\endcsname\empty}
\permanent\def\fastsetupwithargument         #1{\begincsname\??setup:#1\endcsname}    % swapped per 2015-08-30
\permanent\def\fastsetupwithargumentswapped#1#2{\begincsname\??setup:#2\endcsname{#1}}% swapped per 2015-09-05

%D The next one is meant for \c!setups situations, hence the check for a
%D shortcut.

\lettonothing\m_syst_setups_asked

\permanent\protected\def\doprocesslocalsetups#1% sort of public, fast local variant
  {\edef\m_syst_setups_asked{#1}%
   \ifempty\m_syst_setups_asked\else
     \expandafter\syst_setups_process_local
   \fi}

\permanent\protected\def\usesetupsparameter#1%
  {\edef\m_syst_setups_asked{#1\c!setups}%
   \ifempty\m_syst_setups_asked\else
     \expandafter\syst_setups_process_local
   \fi}

% setups=S1
% setups=lua(S2)
% setups=S3
% setups={S1,lua(S2),xml(test{123}),S3}

\def\syst_setups_process_local
  {\clf_autosetups{\m_syst_setups_asked}%
   \relax} % let's prevent lookahead

\permanent\def\autosetups#1{\clf_autosetups{#1}} % todo: public implementor

%% \permanent\edef\setupwithargument#1% saves a few expansions and is faster
%%   {\noexpand\csname\??setup:\noexpand\ifcsname\??setup:#1\endcsname#1\noexpand\else\??empty\noexpand\fi\endcsname}
%%
%% \permanent\edef\setupwithargumentswapped#1#2% saves a few expansions (can be \let)
%%   {\noexpand\csname\??setup:\noexpand\ifcsname\??setup:#2\endcsname#2\noexpand\else\??empty\noexpand\fi\endcsname{#1}}

%D We can gain a bit more but as usual it's not noticeable at all in production runs. We use
%D this one a lot in the \XML\ code.

% \permanent\def\setupwithargument          #1{\futurecsname\gobbleoneargument\??setup:#1\endcsname}
% \permanent\def\setupwithargumentswapped #1#2{\futurecsname\gobbleoneargument\??setup:#2\endcsname{#1}}

\permanent\edef\setupwithargument         #1{\noexpand\futurecsname\noexpand\gobbleoneargument\??setup:#1\endcsname}
\permanent\edef\setupwithargumentswapped#1#2{\noexpand\futurecsname\noexpand\gobbleoneargument\??setup:#2\endcsname{#1}}

\aliased\let\directsetup\syst_setups
\aliased\let\texsetup   \syst_setups % nicer than \directsetup and more en par with xmlsetup and luasetup

\permanent\protected\def\doifelsesetups#1% to be done: grid
  {\ifcsname\??setup:#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifsetupselse\doifelsesetups

\permanent\protected\def\doifsetups#1% to be done: grid
  {\ifcsname\??setup:#1\endcsname
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotsetups#1% to be done: grid
  {\ifcsname\??setup:#1\endcsname
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

% maybe some day:
%
% \protected\def\fastsetupfallback#1#2%
%   {\ifcsname\??setup:#1\endcsname
%      \expandafter\lastnamedcs
%    \else
%      \csname\??setup:#2\expandafter\endcsname
%    \fi}
%
% or
%
% \protected\def\fastsetupfallback#1#2#3% prefix preferred fallback
%   {\ifcsname\??setup:#1#2\endcsname
%      \expandafter\lastnamedcs
%    \else
%      \csname\??setup:#1#3\expandafter\endcsname
%    \fi}

% \startluasetups oeps
%     context("DONE")
%     a = 1
%     b = 1
% \stopluasetups
%
% \luasetup{oeps}
%
% \startsetups xxx
%     ziezo
% \stopsetups
%
% \directsetup{xxx}
%
% \startxmlsetups zzz
%     [[#1]]
% \stopxmlsetups
%
% \xmlsetup{123}{zzz}
%
% \startbuffer[what]
%     context("DONE")
% \stopbuffer
%
% \startbuffer
%     context("MORE")
% \stopbuffer
%
% \ctxluabuffer[what]
%
% \ctxluabuffer

\newtoks\t_syst_setups_tex \appendtoks
    \catcode\endoflineasciicode \ignorecatcode
\to \t_syst_setups_tex

\newtoks\t_syst_setups_loc \appendtoks
    \catcode\endoflineasciicode \ignorecatcode
\to \t_syst_setups_loc

\newtoks\t_syst_setups_raw \appendtoks
    % nothing
\to \t_syst_setups_raw

\newtoks\t_syst_setups_xml \appendtoks
    \catcode\endoflineasciicode\ignorecatcode
    \catcode\barasciicode      \othercatcode
\to \t_syst_setups_xml

\newtoks\t_syst_setups_lua \appendtoks
    \obeyluatokens
\to \t_syst_setups_lua

% Is doglobal still relevant? Maybe always global? Or never? Anyway, it will become obsolete.

\permanent\protected\def\startluasetups  {\begingroup\doifelsenextoptionalcs\syst_setups_start_lua_yes\syst_setups_start_lua_nop} \permanent\protected\lettonothing\stopluasetups
\permanent\protected\def\startxmlsetups  {\begingroup\doifelsenextoptionalcs\syst_setups_start_xml_yes\syst_setups_start_xml_nop} \permanent\protected\lettonothing\stopxmlsetups
\permanent\protected\def\startrawsetups  {\begingroup\doifelsenextoptionalcs\syst_setups_start_raw_yes\syst_setups_start_raw_nop} \permanent\protected\lettonothing\stoprawsetups
\permanent\protected\def\startlocalsetups{\begingroup\doifelsenextoptionalcs\syst_setups_start_loc_yes\syst_setups_start_loc_nop} \permanent\protected\lettonothing\stoplocalsetups
\permanent\protected\def\startsetups     {\begingroup\doifelsenextoptionalcs\syst_setups_start_tex_yes\syst_setups_start_tex_nop} \permanent\protected\lettonothing\stopsetups

% \def\syst_setups_start_lua_two#1#2#+\stopluasetups  {\endgroup\dodoglobal\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_xml_two#1#2#+\stopxmlsetups  {\endgroup\dodoglobal\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_raw_two#1#2#+\stoprawsetups  {\endgroup\dodoglobal\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_loc_two#1#2#+\stoplocalsetups{\endgroup\dodoglobal\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_tex_two#1#2#+\stopsetups     {\endgroup\dodoglobal\instance\defcsname\??setup#1:#2\endcsname##1{#3}}

% \def\syst_setups_start_lua_two#1#2#+\stopluasetups  {\endgroup\instance\defcsname\??setup#1:#2\endcsname##1{#3}} % + keep braces
% \def\syst_setups_start_xml_two#1#2#+\stopxmlsetups  {\endgroup\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_raw_two#1#2#+\stoprawsetups  {\endgroup\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_loc_two#1#2#+\stoplocalsetups{\endgroup\instance\defcsname\??setup#1:#2\endcsname##1{#3}}
% \def\syst_setups_start_tex_two#1#2#+\stopsetups     {\endgroup\instance\defcsname\??setup#1:#2\endcsname##1{#3}}

\let\syst_setups_defcsname\defcsname

\permanent\protected\def\pushglobalsetups{\let\syst_setups_defcsname\gdefcsname}
\permanent\protected\def\popglobalsetups {\let\syst_setups_defcsname\defcsname }

\def\syst_setups_start_lua_two#1#2#L\startluasetups  #R\stopluasetups  #+{\endgroup\instance\syst_setups_defcsname\??setup#1:#2\endcsname##1{#3}} % + keep braces
\def\syst_setups_start_xml_two#1#2#L\startxmlsetups  #R\stopxmlsetups  #+{\endgroup\instance\syst_setups_defcsname\??setup#1:#2\endcsname##1{#3}}
\def\syst_setups_start_raw_two#1#2#L\startrawsetups  #R\stoprawsetups  #+{\endgroup\instance\syst_setups_defcsname\??setup#1:#2\endcsname##1{#3}}
\def\syst_setups_start_loc_two#1#2#L\startlocalsetups#R\stoplocalsetups#+{\endgroup\instance\syst_setups_defcsname\??setup#1:#2\endcsname##1{#3}}
\def\syst_setups_start_tex_two#1#2#L\startsetups     #R\stopsetups     #+{\endgroup\instance\syst_setups_defcsname\??setup#1:#2\endcsname##1{#3}}

\tolerant\def\syst_setups_start_lua_yes[#1]#*[#2]%
  {\expand\t_syst_setups_lua
   \ifarguments\expandafter\syst_setups_start_lua_one
   \or         \expandafter\syst_setups_start_lua_one
   \else       \expandafter\syst_setups_start_lua_two
   \fi{#1}{#2}}

\tolerant\def\syst_setups_start_xml_yes[#1]#*[#2]%
  {\expand\t_syst_setups_xml
   \ifarguments\expandafter\syst_setups_start_xml_one
   \or         \expandafter\syst_setups_start_xml_one
   \else       \expandafter\syst_setups_start_xml_two
   \fi{#1}{#2}}

\tolerant\def\syst_setups_start_raw_yes[#1]#*[#2]%
  {\expand\t_syst_setups_raw
   \ifarguments\expandafter\syst_setups_start_raw_one
   \or         \expandafter\syst_setups_start_raw_one
   \else       \expandafter\syst_setups_start_raw_two
   \fi{#1}{#2}}

\tolerant\def\syst_setups_start_loc_yes[#1]#*[#2]%
  {\expand\t_syst_setups_loc
   \ifarguments\expandafter\syst_setups_start_loc_one
   \or         \expandafter\syst_setups_start_loc_one
   \else       \expandafter\syst_setups_start_loc_two
   \fi{#1}{#2}}

\tolerant\def\syst_setups_start_tex_yes[#1]#*[#2]%
  {\expand\t_syst_setups_tex
   \ifarguments\expandafter\syst_setups_start_tex_one
   \or         \expandafter\syst_setups_start_tex_one
   \else       \expandafter\syst_setups_start_tex_two
   \fi{#1}{#2}}

\def\syst_setups_start_lua_nop#1 {\expand\t_syst_setups_lua\syst_setups_start_lua_two{}{#1}} % space delimited
\def\syst_setups_start_xml_nop#1 {\expand\t_syst_setups_xml\syst_setups_start_xml_two{}{#1}} % space delimited
\def\syst_setups_start_raw_nop#1 {\expand\t_syst_setups_raw\syst_setups_start_raw_two{}{#1}} % space delimited
\def\syst_setups_start_loc_nop#1 {\expand\t_syst_setups_loc\syst_setups_start_loc_two{}{#1}} % space delimited
\def\syst_setups_start_tex_nop#1 {\expand\t_syst_setups_tex\syst_setups_start_tex_two{}{#1}} % space delimited

\def\syst_setups_start_lua_one#1#2{\syst_setups_start_lua_two{}{#1}} % [..]
\def\syst_setups_start_xml_one#1#2{\syst_setups_start_xml_two{}{#1}} % [..]
\def\syst_setups_start_raw_one#1#2{\syst_setups_start_raw_two{}{#1}} % [..]
\def\syst_setups_start_loc_one#1#2{\syst_setups_start_loc_two{}{#1}} % [..]
\def\syst_setups_start_tex_one#1#2{\syst_setups_start_tex_two{}{#1}} % [..]

\permanent\def\luasetup#1{\ctxlua{\syst_setups{#1}}}

%D System setups:

\aliased\let\systemsetupsprefix\wildcardsymbol

\permanent\def\systemsetups#1{\syst_setups{\systemsetupsprefix#1}}

\permanent\tolerant\protected\def\resetsetups[#1]#;#2%
  {\ifcsname\??setup\ifgridsnapping\v!grid\fi:#1#2\endcsname
     \dodoglobal\undefinevalue{\??setup\ifgridsnapping\v!grid\fi:#1#2}%
   \else
     \dodoglobal\undefinevalue{\??setup:#1#2}%
   \fi}

\permanent\tolerant\protected\def\copysetups[#1]#*[#2]%
  {\ifcsname\??setup:#2\endcsname
      \letcsname\??setup:#1\expandafter\endcsname\lastnamedcs
   \fi}

\permanent\protected\def\showsetupsdefinition[#1]%
  {\showvalue{\??setup:#1}} % temp hack for debugging

%D \macros
%D   {setvariables,getvariable,getvariabledefault}
%D
%D \starttyping
%D \setvariables[xx][title=]
%D \setvariables[xx][title=test test]
%D \setvariables[xx][title=test $x=1$ test]   % fatal error reported
%D \setvariables[xx][title=test {$x=1$} test]
%D \setvariables[xx][title]                   % fatal error reported
%D \setvariables[xx][titletitel=e]
%D \stoptyping

\installcorenamespace{variables}

\permanent\protected\def\setvariables {\syst_variables_set\getparameters }
\permanent\protected\def\setevariables{\syst_variables_set\geteparameters}
\permanent\protected\def\setgvariables{\syst_variables_set\getgparameters}
\permanent\protected\def\setxvariables{\syst_variables_set\getxparameters}

\mutable\lettonothing\currentvariableclass

\tolerant\def\syst_variables_set#1#*[#2]#*[#S#3]% tricky, test on s-pre-60
  {\ifcstok{#2}\currentvariableclass
     #1[\??variables#2:][#3]%
   \else
     \pushmacro\currentvariableclass
     \cdef\currentvariableclass{#2}%
     \getvariable{#2}\s!reset
     #1[\??variables#2:][#3]%
     \getvariable{#2}\s!set
     \popmacro\currentvariableclass
   \fi}

\permanent\protected\def\setvariable #1#2#3{\defcsname \??variables#1:#2\endcsname{#3}}
\permanent\protected\def\setevariable#1#2#3{\edefcsname\??variables#1:#2\endcsname{#3}}
\permanent\protected\def\setgvariable#1#2#3{\defcsname \??variables#1:#2\endcsname{#3}}
\permanent\protected\def\setxvariable#1#2#3{\xdefcsname\??variables#1:#2\endcsname{#3}}

\permanent          \def\getvariable #1#2{\begincsname\??variables#1:#2\endcsname}
\permanent\protected\def\showvariable#1#2{\showvalue{\begincsname\??variables#1:#2\endcsname}}

%D \macros
%D   {checkvariables}
%D
%D I'll probably forget that this on exists.

% \lettonothing\m_syst_variables_temp
%
% \permanent\tolerant\def\checkvariables[#1]#*[#2]%
%   {\dogetparameters\syst_variables_check_value[#1][#2]}
%
% \def\syst_variables_check_value#1#2#3%
%   {\ifcsname\??variables#1:#2\endcsname
%      \edef\m_syst_variables_temp{\lastnamedcs}%
%      \ifempty\m_syst_variables_temp
%        \defcsname\??variables#1:#2\endcsname{#3}%
%      \fi
%    \else
%      \defcsname\??variables#1:#2\endcsname{#3}%
%    \fi}

\permanent\protected\def\checkvariables[#1]#*[#S#2]%
  {\cdef\m_syst_parameter{#1}%
   \syst_variables_check_value#2\ignorearguments\ignorearguments}

\tolerant\def\syst_variables_check_value#*#1=#S#2,#M,%
  {\ifarguments
     \expandafter\gobbleoneargument
   \or
     \mult_interfaces_get_parameters_error_indeed\m_syst_parameter{#1}%
   \orunless\ifcsname\??variables\m_syst_parameter:#1\endcsname
     \defcsname\??variables\m_syst_parameter:#1\endcsname{#2}%
   \orelse\ifempty{\lastnamedcs}%
     \defcsname\??variables\m_syst_parameter:#1\endcsname{#2}%
   \fi
   \syst_variables_check_value}

%D \macros
%D   {doifelsevariable,doifvariable,doifnotvariable}
%D
%D A few trivial macros:

\permanent\protected\def\doifelsevariable#1#2%
  {\ifcsname\??variables#1:#2\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifvariableelse\doifelsevariable

\permanent\protected\def\doifvariable#1#2%
  {\ifcsname\??variables#1:#2\endcsname
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotvariable#1#2%
  {\ifcsname\??variables#1:#2\endcsname
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

%D A few more (we could use a public test variable so that we only need to expand
%D once, assuming expandable variables):

\letcsname\??variables:\endcsname\empty

\permanent\protected\def\doifelseemptyvariable#1#2%
  {\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
   \ifempty\m_syst_string_one
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifemptyvariableelse\doifelseemptyvariable

\permanent\protected\def\doifemptyvariable#1#2%
  {\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
   \ifempty\m_syst_string_one
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotemptyvariable#1#2%
  {\edef\m_syst_string_one{\begincsname\??variables#1:#2\endcsname}%
   \ifempty\m_syst_string_one
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\def\getvariabledefault#1#2% #3% can be command
  {\ifcsname\??variables#1:#2\endcsname
     \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\tolerant\protected\def\setupenv
  {\syst_variables_set\getparameters[\s!environment]}

\permanent\protected\def\doifelseenv{\doifelsevariable  \s!environment}
\permanent\protected\def\doifenv    {\doifvariable      \s!environment}
\permanent\protected\def\doifnotenv {\doifnotvariable   \s!environment}
\permanent          \def\env        {\getvariable       \s!environment}
\permanent          \def\envvar     {\getvariabledefault\s!environment}

\aliased\let\doifenvelse\doifelseenv

%D \macros
%D   {defineselector,setupselector,select,directselect}
%D
%D \starttyping
%D \defineselector[caption][max=2,n=2]
%D
%D \start
%D     \setupselector[caption][n=1]
%D     \placelist[figure][criterium=all]
%D \stop
%D
%D \starttext
%D     \placefigure
%D       {\select{caption}{zapf}{\input zapf \relax}}
%D       {}
%D \stoptext
%D \stoptyping

\installcorenamespace{selector}

\permanent\tolerant\protected\def\defineselector[#1]#*[#2]{\getparameters[\??selector#1][\c!max=\plusone,\c!n=\plusone,#2]}
\permanent\tolerant\protected\def\setupselector [#1]#*[#2]{\getparameters[\??selector#1][#2]}

\permanent\def\directselect#1% expandable
  {\expandafter\filterfromnext
     \csname\??selector\ifcsname\??selector#1\c!max\endcsname#1\fi\c!max\expandafter\endcsname
     \csname\??selector\ifcsname\??selector#1\c!n  \endcsname#1\fi\c!n  \endcsname}

\permanent\protected\let\select\directselect % we promote to protected

\letcsname\??selector\c!max\endcsname\plusone
\letcsname\??selector\c!n  \endcsname\plusone

\protect \endinput

