%D \module
%D   [       file=luat-ini,
%D        version=2005.08.11,
%D          title=\CONTEXT\ Lua Macros,
%D       subtitle=Initialization,
%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 Lua Macros / Initialization}

\unprotect

%D Loading lua code can be done using \type {startup.lua}. The following method uses
%D the \TEX\ input file locator of kpse. At least we need to use that way of loading
%D when we haven't yet define our own code, which we keep outside the format. We
%D will keep code outside \TEX\ files as much as possible. The solutions evolved
%D with the engine but one can find some history in the \MKIV\ files and articles.

\ifdefined\obeyluatokens \else \let\obeyluatokens\relax \fi

%D A few more goodies:

\permanent\protected\lettonothing\stoplua     % tex catcodes
\permanent\protected\lettonothing\stopluacode % lua catcodes

%D In the meantime the \LUATEX\ interface has become stable but we still see traces
%D of old here (needs checking).

\permanent\protected\def\startlua % \stoplua
  {\begingroup
   \luat_start_lua_indeed}

\def\luat_start_lua_indeed#1\stoplua
  {\expanded{\endgroup\noexpand\directlua{#1}}}

\permanent\protected\def\startluacode % \stopluacode
  {\begingroup
   \obeyluatokens
   \luat_start_lua_code_indeed}

\def\luat_start_lua_code_indeed#1\stopluacode
 %{\expanded{\endgroup\noexpand\directlua{#1}}}
  {\directlua{#1\beginlocalcontrol\endgroup\endlocalcontrol}}

%D Some delayed definitions:

\ifdefined\obeylines   \else \let\obeylines   \relax \fi
\ifdefined\obeyedline  \else \let\obeyedline  \relax \fi
\ifdefined\obeyspaces  \else \let\obeyspaces  \relax \fi
\ifdefined\obeyedspace \else \let\obeyedspace \relax \fi

\newtoks\everyluacode

%D It is nicer for checking with \type {s-system-macros} if we have some meaning:

\pushoverloadmode

    % We anyway need this:

    \permanent\protected\def\superexplicitdiscretionary
      {\begingroup
       \hyphenationmode\explicithyphenationcode\explicitdiscretionary
       \endgroup}

    % Conceptually the best:

    \aliased\let\-\explicitdiscretionary

    % But we could do this to be compatible:

  % \permanent\protected\def\-{\begingroup\hyphenationmode\explicithyphenationmodecode\explicitdiscretionary\endgroup}

    % Or maybe even this:

  % \aliased\let\lang_explicit_discretionary_nop\explicitdiscretionary
  %
  % \permanent\protected\def\lang_explicit_discretionary_yes-%
  %   {\superexplicitdiscretionary}
  %
  % \permanent\protected\def\-%
  %   {\doifelsenextcharcs-\lang_explicit_discretionary_yes\lang_explicit_discretionary_nop}

\popoverloadmode

\ifdefined\n \else \mutable\def\n{n} \fi \ifdefined\r \else \mutable\def\r{r} \fi
\ifdefined\f \else \mutable\def\f{f} \fi \ifdefined\t \else \mutable\def\t{t} \fi
\ifdefined\a \else \mutable\def\a{a} \fi \ifdefined\b \else \mutable\def\b{b} \fi
\ifdefined\v \else \mutable\def\v{v} \fi \ifdefined\s \else \mutable\def\s{s} \fi

\ifdefined\+ \else \mutable\def\+{+} \fi \ifdefined\- \else \mutable\def\-{-} \fi

\ifdefined\? \else \mutable\def\?{?} \fi \ifdefined\! \else \mutable\def\!{!} \fi % bonus

\ifdefined\1 \else \mutable\def\1{1} \fi \ifdefined\2 \else \mutable\def\2{2} \fi
\ifdefined\3 \else \mutable\def\3{3} \fi \ifdefined\4 \else \mutable\def\4{4} \fi
\ifdefined\5 \else \mutable\def\5{5} \fi \ifdefined\6 \else \mutable\def\6{6} \fi
\ifdefined\7 \else \mutable\def\7{7} \fi \ifdefined\8 \else \mutable\def\8{8} \fi
\ifdefined\9 \else \mutable\def\9{9} \fi \ifdefined\0 \else \mutable\def\0{0} \fi

\permanent\cdef\lua_letter_backslash{\string\\}
\permanent\cdef\lua_letter_bar      {\string\|} \permanent\cdef\lua_letter_dash     {\string\-}
\permanent\cdef\lua_letter_lparent  {\string\(} \permanent\cdef\lua_letter_rparent  {\string\)}
\permanent\cdef\lua_letter_lbrace   {\string\{} \permanent\cdef\lua_letter_rbrace   {\string\}}
\permanent\cdef\lua_letter_squote   {\string\'} \permanent\cdef\lua_letter_dquote   {\string\"}
\permanent\cdef\lua_letter_n        {\string\n} \permanent\cdef\lua_letter_r        {\string\r}
\permanent\cdef\lua_letter_f        {\string\f} \permanent\cdef\lua_letter_t        {\string\t}
\permanent\cdef\lua_letter_a        {\string\a} \permanent\cdef\lua_letter_b        {\string\b}
\permanent\cdef\lua_letter_v        {\string\v} \permanent\cdef\lua_letter_s        {\string\s}
\permanent\cdef\lua_letter_one      {\string\1} \permanent\cdef\lua_letter_two      {\string\2}
\permanent\cdef\lua_letter_three    {\string\3} \permanent\cdef\lua_letter_four     {\string\4}
\permanent\cdef\lua_letter_five     {\string\5} \permanent\cdef\lua_letter_six      {\string\6}
\permanent\cdef\lua_letter_seven    {\string\7} \permanent\cdef\lua_letter_eight    {\string\8}
\permanent\cdef\lua_letter_nine     {\string\9} \permanent\cdef\lua_letter_zero     {\string\0}

\everyluacode {% \appendtoks
   \enforced\let\\\lua_letter_backslash
   \enforced\let\|\lua_letter_bar       \enforced\let\-\lua_letter_dash
   \enforced\let\(\lua_letter_lparent   \enforced\let\)\lua_letter_rparent
   \enforced\let\{\lua_letter_lbrace    \enforced\let\}\lua_letter_rbrace
   \enforced\let\'\lua_letter_squote    \enforced\let\"\lua_letter_dquote
   \enforced\let\n\lua_letter_n         \enforced\let\r\lua_letter_r
   \enforced\let\f\lua_letter_f         \enforced\let\t\lua_letter_t
   \enforced\let\a\lua_letter_a         \enforced\let\b\lua_letter_b
   \enforced\let\v\lua_letter_v         \enforced\let\s\lua_letter_s
   \enforced\let\1\lua_letter_one       \enforced\let\2\lua_letter_two
   \enforced\let\3\lua_letter_three     \enforced\let\4\lua_letter_four
   \enforced\let\5\lua_letter_five      \enforced\let\6\lua_letter_six
   \enforced\let\7\lua_letter_seven     \enforced\let\8\lua_letter_eight
   \enforced\let\9\lua_letter_nine      \enforced\let\0\lua_letter_zero
} % \to \everyluacode

\permanent\protected\def\obeyluatokens
  {\setcatcodetable\luacatcodes
   \expand\everyluacode}

\permanent\cdef\luamajorversion{\ctxwrite{LUAMINORVERSION}}
\permanent\cdef\luaminorversion{\ctxwrite{LUAMAJORVERSION}}

%D We need a way to pass strings safely to \LUA\ without the need for tricky
%D escaping. Compare:
%D
%D \starttyping
%D \ctxlua {something("anything tricky can go here")}
%D \ctxlua {something([\luastringsep[anything tricky can go here]\luastringsep])}
%D \stoptyping

\def\luastringsep{===}       % this permits \typefile{self} otherwise nested b/e sep problems

\edef\!!bs{[\luastringsep[}  % later redefined as mutable
\edef\!!es{]\luastringsep]}

%D We have a the following available as primitive so there is no need for it:
%D
%D \starttyping
%D \edef\luaescapestring#1{\!!bs#1\!!es}
%D \stoptyping

\permanent\protected\def\setdocumentfilename       #1#2{\clf_setdocumentfilename{#1}{#2}}
\permanent          \def\getdocumentfilename         #1{\clf_getdocumentfilename{#1}}
\permanent\protected\def\setdocumentargument       #1#2{\clf_setdocumentargument{#1}{#2}}
\permanent          \def\getdocumentargument         #1{\clf_getdocumentargument{#1}{}}
\permanent\protected\def\setdocumentargumentdefault#1#2{\clf_setdocumentdefaultargument{#1}{#2}}
\permanent          \def\getdocumentargumentdefault#1#2{\clf_getdocumentargument{#1}{#2}}

% seldom used so no need for speedy variants:

\permanent\def\doifelsedocumentargument    #1{\doifelsesomething{\clf_getdocumentargument{#1}}}
\permanent\def\doifdocumentargument        #1{\doifsomething    {\clf_getdocumentargument{#1}}}
\permanent\def\doifnotdocumentargument     #1{\doifnothing      {\clf_getdocumentargument{#1}}}
\permanent\def\doifelsedocumentfilename    #1{\doifelsesomething{\clf_getdocumentfilename{#1}}}
\permanent\def\doifdocumentfilename        #1{\doifsomething    {\clf_getdocumentfilename{#1}}}
\permanent\def\doifnotdocumentfilename     #1{\doifnothing      {\clf_getdocumentfilename{#1}}}

\aliased\let\doifdocumentargumentelse\doifelsedocumentargument
\aliased\let\doifdocumentfilenameelse\doifelsedocumentfilename

%D A handy helper:

\permanent\def\luaexpanded#1{\luaescapestring\expandafter{\expanded{#1}}}

%D Experimental:

\permanent\protected\def\startluaparameterset[#1]% \stopluaparameterset
  {\begingroup
   \obeyluatokens
   \luat_start_lua_parameter_set{#1}}

\def\luat_start_lua_parameter_set#1#2\stopluaparameterset
  {\ctxlua{parametersets["#1"]={#2}}%
   \endgroup}

\permanent\protected\lettonothing\stopluaparameterset

\permanent\def\luaparameterset#1#2{\ctxlua{parametersets["#1"]={#2} context("#1")}}

% todo: \mergeparameterset

% usage:
%
% \startluaparameterset [u3d:myset:display:1]
%     toolbar=false,
%     tree=true
% \stopluaparameterset
%
% option=u3d:myset:display:1
%
% or:
%
% option=\luaparameterset{u3d:myset:display:1}{toolbar=false,tree=true}

%D A Handy helper:

\permanent\def\luaconditional#1{\ifcase#1tru\else fals\fi e}

%D Goodie:
%D
%D \starttyping
%D \ctxluacode{context("%0.5f",1/3)}
%D \stoptyping

\permanent\protected\def\ctxluacode
  {\begingroup
   \obeyluatokens
   \catcode\leftbraceasciicode \plusone
   \catcode\rightbraceasciicode\plustwo
   \afterassignment\luat_lua_code
   \scratchtoks=}

% Hm, are we sure that the \* commands work out okay here? We could probably
% use \setcatcodetable\luacatcodes instead of \obeyluatokens now.

\def\luat_lua_code
  {\expanded{\endgroup\noexpand\directlua\expandafter{\the\scratchtoks}}} % \zerocount is default

% \startctxfunction MyFunctionA
%     context(" A1 ")
% \stopctxfunction
%
% \startctxfunctiondefinition MyFunctionB
%     context(" B2 ")
% \stopctxfunctiondefinition
%
% \starttext
%     \dorecurse{10000}{\ctxfunction{MyFunctionA}} \page
%     \dorecurse{10000}{\MyFunctionB} \page
%     \dorecurse{10000}{\ctxlua{context(" C3 ")}} \page
% \stoptext

\installsystemnamespace{ctxfunction}

\permanent\protected\def\startctxfunctiondefinition #1 % \stopctxfunctiondefinition
  {\begingroup \obeyluatokens \luat_start_lua_function_definition_indeed{#1}}

\installsystemnamespace{luafunction}

\def\luat_start_lua_function_definition_indeed#1#2\stopctxfunctiondefinition
  {\endgroup
   \expandafter\chardef\csname\??luafunction#1\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es)}\relax
   \edefcsname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}

\permanent\protected\def\setctxluafunction#1#2% experiment
  {\expandafter\chardef\csname\??luafunction#1\endcsname#2\relax
   \edefcsname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}

\permanent\protected\lettonothing\stopctxfunctiondefinition

\permanent\protected\def\startctxfunction #1 % \stopctxfunction
  {\begingroup \obeyluatokens \luat_start_lua_function_indeed{#1}}

\def\luat_start_lua_function_indeed#1#2\stopctxfunction
  {\endgroup\edefcsname\??ctxfunction#1\endcsname{\noexpand\luafunction\ctxcommand{ctxfunction(\!!bs#2\!!es)}\relax}}

\permanent\protected\lettonothing\stopctxfunction

\permanent\def\ctxfunction#1%
  {\begincsname\??ctxfunction#1\endcsname}

%D In theory this is faster due to the call not being wrapped in a function but in
%D practice the speedup can't be noticed. The actions called for often have lots of
%D lookups so an extra one doesn't matter much. The kind of calls differs a lot per
%D document and often there are other ways to optimize a style. For instance we can
%D gain a lot when defining a font, but when a frozen definition is used that gain
%D gets completely lost. For some calls (take list writers) it can get worse if only
%D because readability gets worse and passing is already efficient due to selective
%D flushing, while with the token scanners one has to scan all of them.

% \startctxfunctiondefinition foo commands.foo() \stopctxfunctiondefinition
%
% \installctxfunction\foo{commands.foo}

\lettonothing\m_syst_name

\permanent\protected\def\installctxfunction#1#2% expandable
  {\edef\m_syst_name{\csstring#1}%
   \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es,true)}\relax}

\permanent\protected\def\installctxscanner#1#2% expandable
  {\edef\m_syst_name{\csstring#1}%
   \global\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name",\!!bs#2\!!es,true)}\relax}

\permanent\protected\def\installprotectedctxfunction#1#2% protected
  {\edef\m_syst_name{\csstring#1}%
   \global\protected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxfunction(\!!bs#2\!!es,true)}\relax}

\permanent\protected\def\installprotectedctxscanner#1#2% protected
  {\edef\m_syst_name{\csstring#1}%
   \global\protected\expandafter\normalluadef\csname\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name",\!!bs#2\!!es,true)}\relax}

% \permanent\protected\def\resetctxscanner#1%
%   {\edef\m_syst_name{\csstring#1}%
%    \gletcsname\m_syst_name\endcsname\relax} % or better nothing

\permanent\protected\def\resetctxscanner#1%
  {\global\expandafter\lettonothing\csname\csstring#1\endcsname}

\protect \endinput
