%D \module
%D   [       file=file-mod, % was core-fil,
%D        version=20110701, % 1997.11.15,
%D          title=\CONTEXT\ File Macros,
%D       subtitle=Module Support,
%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 File Macros / Modules}

\unprotect

\registerctxluafile{file-mod}{autosuffix}

%D \macros
%D   {usemodule}
%D
%D Most of \CONTEXT is preloaded in the format file. Some very domain specific
%D typesetting topics are however dealt with in separate modules, e.g. typesetting
%D of chemical structure formulas. These modules are loaded by:
%D
%D \showsetup{usemodule}
%D
%D More information on the specific modules can be found in their dedicated manuals.
%D We use \type {\next} so that we can \type {\end} in modules.

% \enabledirectives[logs.errors=*]
% \enabledirectives[logs.errors=missing modules]
%
% \usemodule[letsquit]
%
% \starttext
%     test
% \stoptext

\installcorenamespace{module}

\mutable\let\currentmodule\s!unknown

\mutable\lettonothing\currentmodulecategory
\mutable\lettonothing\currentmoduleparameters

\installmacrostack\currentmodule
\installmacrostack\currentmodulecategory
\installmacrostack\currentmoduleparameters

\permanent\tolerant\protected\def\usemodules[#category]#spacer[#S#name]#spacer[#S#parameters]% category=t|m|x|p|...
  {\push_macro_currentmodule
   \push_macro_currentmodulecategory
   \push_macro_currentmoduleparameters
   \ifparameters
     \lettonothing\currentmodule
   \or
     \lettonothing\currentmodulecategory
     \cdef\currentmodule{#category}%
     \lettonothing\currentmoduleparameters
   \or
     \ifhastok={#name}%
       \lettonothing\currentmodulecategory
       \cdef\currentmodule{#category}%
       \edef\currentmoduleparameters{#name}%
     \else
       \edef\currentmodulecategory{#category}%
       \cdef\currentmodule{#name}%
       \lettonothing\currentmoduleparameters
     \fi
   \or
     \edef\currentmodulecategory  {#category}%
     \cdef\currentmodule          {#name}%
     \def \currentmoduleparameters{#parameters}%
   \fi
   \processcommacommand[\currentmodule]{\strc_modules_use\currentmodulecategory}%
   \pop_macro_currentmoduleparameters
   \pop_macro_currentmodulecategory
   \pop_macro_currentmodule}

\def\strc_modules_use#category#name%
  {\ifempty\currentmoduleparameters\else
     \scratchtoks\expandafter{\currentmoduleparameters}%
     \expanded{\getparameters[\??module#name:][\the\scratchtoks]}%
   \fi
   \clf_usemodules{#category}{#name}}

\aliased\let\usemodule   \usemodules
\aliased\let\usetexmodule\usemodules

\newinteger\c_syst_modules_nesting
\newtoks   \everysetupmodule

\permanent\tolerant\protected\def\startmodule[#1]#;#2 %
  {\global\advanceby\c_syst_modules_nesting\plusone
   \push_macro_currentmodule
   \push_macro_currentmoduleparameters
   \cdef\currentmodule{#1#2}}

\permanent\protected\def\stopmodule
  {\ifcase\c_syst_modules_nesting
     \writestatus\m!system{module wrapping error in '\currentmodule'}%
   \else
     \pop_macro_currentmoduleparameters
     \pop_macro_currentmodule
     \global\advanceby\c_syst_modules_nesting\minusone
   \fi}

\permanent\protected\def\setupmodule % to be lmtx'd
  {\ifempty\currentmoduleparameters
      \expandafter\syst_modules_setup_nop
   \else
      \expandafter\syst_modules_setup_yes
   \fi}

\tolerant\def\syst_modules_setup_nop[#S#name]#spacer[#S#parameters]%
  {\ifarguments
     % nothing
   \or
     \ifhastok={#name}%
       \getparameters[\??module\currentmodule:][#name]%
     \fi
   \or
     \getparameters[\??module#name:][#parameters]% internal (defaults)
   \fi
   \expand\everysetupmodule}

\tolerant\def\syst_modules_setup_yes[#S#name]#spacer[#S#parameters]%
  {\scratchtoks\expandafter{\currentmoduleparameters}%
   \ifparameters
     \expanded{\getparameters[\??module\currentmodule:][\the\scratchtoks]}%
   \or
     \ifhastok={#name}%
       \getparameters[\??module\currentmodule:][#name]% internal (defaults)
       \expanded{\getparameters[\??module\currentmodule:][\the\scratchtoks]}% loadtime (user)
     \else
       \expanded{\getparameters[\??module#1:][\the\scratchtoks]}% loadtime (user)
     \fi
   \or
     \getparameters[\??module#name:][#parameters]% internal (defaults)
     \expanded{\getparameters[\??module#name:][\the\scratchtoks]}% loadtime (user)
   \fi
   \lettonothing\currentmoduleparameters
   \expand\everysetupmodule}

\permanent\def\moduleparameter#name#parameter% should have been \namedmoduleparameter
  {\begincsname\??module#name:#parameter\endcsname}

\letcsname\??module\endcsname\empty % so we default to empty as with all parameters

\permanent\def\currentmoduleparameter{\moduleparameter\currentmodule} % no need for inlining

%permanent\protected\def\useluamodule[#name]{\clf_loadluamodule{#1}} % why not use useluamodule

\permanent\protected\def\useluamodule  [#name]{\clf_useluamodule{#1}}
\permanent\protected\def\luaenvironment #name {\clf_loadluamodule{#1}}

% \usemodule[newmml]
% \usemodule[newmml][a=b]
% \usemodule[x][newmml]
% \usemodule[x][newmml][a=b]
%
% \startmodule [mathml]
%   \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars will be set afterwards
%   \setupmodule[a=c] \relax [\currentmoduleparameter{a}] % user vars are now forgotten
% \stopmodule

% one can introduce test sections with:
%
% \enablemode[newmml:test:\currentmoduleparameter{test}]
% \startmode[newmml:test:yes} ... \stopmode
%
% these will be ignored unless test=yes
%
% however, a better way is:

\permanent\protected\def\startmoduletestsection
  {\begingroup
   \setupmodule % we need to make sure that the vars are set
   \ifcstok{\currentmoduleparameter\v!test}\v!yes
     \endgroup
     \writestatus\currentmodule{loading experimental code}%
   \else
     \endgroup
     \writestatus\currentmodule{skipping experimental code}%
     \expandafter\ignoreupto\expandafter\stopmoduletestsection
   \fi}

\aliased\let\stopmoduletestsection\donothing

% will become file-run

%D \macros
%D   {doifolderversionelse}
%D
%D We start with a macro specially for Aditya who wants to be able
%D to use development versions of \MKIV\ for real documents.
%D
%D \starttyping
%D \doifolderversionelse\contextversion{1010.10.10} {OLDER} {OKAY} => OLDER
%D \doifolderversionelse\contextversion{2020.20.20} {OLDER} {OKAY} => OKAY
%D \doifolderversionelse\contextversion{2020}       {OLDER} {OKAY} => OKAY
%D \stoptyping
%D
%D The version pattern is \type {yyyy.mm.dd} (with mm and dd being optional).

\permanent\protected\def\doifelseolderversion#parent#child{\clf_doifelseolderversion{#parent}{#child}}
\permanent\protected\def\doifelseoldercontext       #child{\clf_doifelseolderversion{#child}{}}

\aliased\let\doifolderversionelse\doifelseolderversion
\aliased\let\doifoldercontextelse\doifelseoldercontext

%D Relatively new (no need for a speedup here). Can't this now be done nicer?

\lettonothing\m_module_command_command
\lettonothing\m_module_command_function

\permanent\protected\def\syst_modules_direct_lua#1#2%
  {\edef\m_module_command_command {#1}%
   \edef\m_module_command_function{#2}%
   \directsetup{module:\m_module_command_command:start}%
   \ctxlua{\m_module_command_function()}%
   \directsetup{module:\m_module_command_command:stop}}

\permanent\protected\def\syst_modules_single_lua#1#2%
  {\edef\m_module_command_command {#1}%
   \edef\m_module_command_function{#2}%
   \dosingleempty\syst_modules_single_lua_indeed}

\permanent\protected\def\syst_modules_single_lua_indeed[#1]%
  {\directsetup{module:\m_module_command_command:start}%
   \ctxlua{\m_module_command_function(\!!bs#1\!!es)}%
   \directsetup{module:\m_module_command_command:stop}}

\permanent\protected\def\syst_modules_double_lua#1#2%
  {\edef\m_module_command_command {#1}%
   \edef\m_module_command_function{#2}%
   \dodoubleempty\syst_modules_double_lua_indeed}

\permanent\protected\def\syst_modules_double_lua_indeed[#1][#2]%
  {\directsetup{module:\m_module_command_command:start}%
   \ctxlua{\m_module_command_function(\!!bs#1\!!es,\!!bs#2\!!es)}%
   \directsetup{module:\m_module_command_command:stop}}

\permanent\protected\def\installmodulecommandlua      #1#2{\enforced\permanent\protected\def#1{\expanded{\syst_modules_direct_lua{\csstring#1}{#2}}}}
\permanent\protected\def\installmodulecommandluasingle#1#2{\enforced\permanent\protected\def#1{\expanded{\syst_modules_single_lua{\csstring#1}{#2}}}}
\permanent\protected\def\installmodulecommandluadouble#1#2{\enforced\permanent\protected\def#1{\expanded{\syst_modules_double_lua{\csstring#1}{#2}}}}

\protected\def\syst_modules_one_lua#1#2#3%
  {\directsetup{module:#1:start}%
   \ctxlua{#2(\!!bs#3\!!es)}%
   \directsetup{module:#1:stop}}

\protected\def\syst_modules_two_lua#1#2#3#4%
  {\directsetup{module:#1:start}%
   \ctxlua{#2(\!!bs#3\!!es,\!!bs#4\!!es)}%
   \directsetup{module:#1:stop}}

\permanent\protected\def\installmodulecommandluaone#1#2{\enforced\permanent\protected\def#1{\expanded{\syst_modules_one_lua{\csstring#1}{#2}}}}
\permanent\protected\def\installmodulecommandluatwo#1#2{\enforced\permanent\protected\def#1{\expanded{\syst_modules_two_lua{\csstring#1}{#2}}}}

%D This replaces \type {\fetchruntimecommand}:
%D
%D \starttyping
%D \fetchmodulecommand \csname {module}
%D \stoptyping

\permanent\protected\def\fetchmodulecommand#1#2%
  {\mutable\protected\def#1{\syst_fetch_module_command#1{#2}}}

\def\syst_fetch_module_command#1#2% actually a test on #1 being define would be ok as well
  {%writestatus\m!systems{fetching \string#1}%
   \usemodule[#2]%
   #1}

\aliased\let\fetchruntimecommand\fetchmodulecommand % obsolete

% \permanent\protected\def\moduleoverloaded
%   {\enforced}

\protect \endinput
