%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
%D method uses the \TEX\ input file locator of kpse. At least we need to
%D use that way of loading when we haven't yet define our own code, which
%D we keep outside the format. We will keep code outside \TEX\ files as
%D much as possible.

\ifdefined\setnaturalcatcodes \else \let\setnaturalcatcodes\relax \fi
\ifdefined\obeylualines       \else \let\obeylualines      \relax \fi
\ifdefined\obeyluatokens      \else \let\obeyluatokens     \relax \fi

%D A few more goodies:

\let\stoplua    \relax % tex catcodes
\let\stopluacode\relax % lua catcodes

% It might makes sense to have a \type {\directelua} so that we can avoid
% the \type {\normalexpanded} around \type {\directlua}. Something to discuss
% in the team.

\normalprotected\def\startlua % \stoplua
  {\begingroup
   \obeylualines
   \luat_start_lua_indeed}

\def\luat_start_lua_indeed#1\stoplua
  {\normalexpanded{\endgroup\noexpand\directlua{#1}}} % \zerocount is default

\normalprotected\def\startluacode % \stopluacode
  {\begingroup
   \obeylualines
   \obeyluatokens
   \luat_start_lua_code_indeed}

\def\luat_start_lua_code_indeed#1\stopluacode
  {\normalexpanded{\endgroup\noexpand\directlua{#1}}} % \zerocount is default

%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

\let\obeylualines\relax

\newtoks\everyluacode

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

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

\normalprotected\def\obeyluatokens
  {\setcatcodetable\luacatcodes
   \the\everyluacode}

\edef\luamajorversion{\ctxwrite{_MINORVERSION}}
\edef\luaminorversion{\ctxwrite{_MAJORVERSION}}

%D We need a way to pass strings safely to \LUA\ without the
%D need for tricky 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[}
\edef\!!es{]\luastringsep]}

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

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

% seldom used so no need for speedy variants:

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

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

%D A handy helper:

\def\luaexpanded#1{\luaescapestring\expandafter{\normalexpanded{#1}}}

%D Experimental:

\normalprotected\def\startluaparameterset[#1]%
  {\begingroup
   \obeylualines
   \obeyluatokens
   \luat_start_lua_parameter_set{#1}}

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

\let\stopluaparameterset\relax

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

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

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

\normalprotected\def\ctxluacode
  {\begingroup
   \obeylualines
   \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
  {\normalexpanded{\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}

\normalprotected\def\startctxfunctiondefinition #1 %
  {\begingroup \obeylualines \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
   \expandafter\edef\csname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}

\normalprotected\def\setctxluafunction#1#2% experiment
  {\expandafter\chardef\csname\??luafunction#1\endcsname#2\relax
   \expandafter\edef\csname#1\endcsname{\noexpand\luafunction\csname\??luafunction#1\endcsname}}

\let\stopctxfunctiondefinition\relax

\normalprotected\def\startctxfunction #1 %
  {\begingroup \obeylualines \obeyluatokens \luat_start_lua_function_indeed{#1}}

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

\let\stopctxfunction\relax

\def\ctxfunction#1%
  {\csname\??ctxfunction#1\endcsname}

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

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

% This is a forward definition:

\def\checkedstrippedcsname#1% this permits \strippedcsname{\xxx} and \strippedcsname{xxx}
  {\expandafter\syst_helpers_checked_stripped_csname\string#1}

\def\syst_helpers_checked_stripped_csname#1%
  {\if\noexpand#1\letterbackslash\else#1\fi}

\normalprotected\def\installctxfunction#1#2%
  {\edef\m_syst_name{\checkedstrippedcsname#1}%
   \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxfunction("#2",true)}\relax
   \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}

\normalprotected\def\installctxscanner#1#2%
  {\edef\m_syst_name{\checkedstrippedcsname#1}%
   \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\ctxcommand{ctxscanner("\m_syst_name","#2",true)}\relax
   \expandafter\xdef\csname\m_syst_name\endcsname{\noexpand\luafunction\csname\??luafunction\m_syst_name\endcsname}}

\normalprotected\def\resetctxscanner#1%
  {\edef\m_syst_name{\checkedstrippedcsname#1}%
   \global\expandafter\chardef\csname\??luafunction\m_syst_name\endcsname\zerocount
   \global\expandafter\let\csname\m_syst_name\endcsname\relax}

\protect \endinput
