%D \module
%D   [       file=buff-ini,
%D        version=2011.11.22, % previous big effort 2000.01.05,
%D          title=\CONTEXT\ Buffer Macros,
%D       subtitle=Buffers,
%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 Buffer Macros / Buffers}

\registerctxluafile{buff-ini}{autosuffix}

\unprotect

%D There have been several iterations in \MKIV\ but here we only show the currently
%D used one. One can always look back (and maybe learn some). It will never look
%D pretty and never be efficient but it has served us for ages (conceptually it's
%D as in \MKII).

\mutable\lettonothing\currentbuffer

% \doifelsebuffer      {#1} % expandable
% \doifelsebufferempty {#1} % non expandable

\aliased\let\doifbufferelse\doifelsebuffer

\permanent\tolerant\protected\def\resetbuffer[#1]{\clf_erasebuffer{#1}} % todo: use public implementor

\permanent\protected\defcsname\e!start\v!buffer\endcsname
  {\begingroup % (3)
   \obeylines
   \buff_start}

\tolerant\def\buff_start[#1]#*[#2]%
  {\buff_start_indeed{}{#1}{\e!start\v!buffer}{\e!stop\v!buffer}}

\def\buff_start_indeed#1#2#3#4%
  {\normalexpanded{\buff_pickup
     {#2}%
     {#3}%
     {#4}%
     {}%
     {\buff_stop{#4}}%
     \ifcstok{\namedbufferparameter{#1}\c!strip}\v!no\zerocount\else\plusone\fi}}

\permanent\protected\def\grabbufferdatadirect % name start stop
  {\begingroup % (6)
   \buff_start_indeed\empty}

\permanent\protected\def\grabbufferdata % was: \dostartbuffer
  {\begingroup % (4)
   \obeylines
   \buff_grab_direct}

\tolerant\def\buff_grab_direct[#1]#*[#2]#*[#3]#*[#4]% [category] [name] [start] [stop]
  {\ifnum\lastarguments=\plusfour
     \expandafter\buff_start_indeed
   \else
     \expandafter\buff_start_indeed_default
   \fi{#1}{#2}{#3}{#4}}

\def\buff_start_indeed_default#1#2#3#4{\buff_start_indeed\empty{#1}{#2}{#3}}

\let\buff_finish\relax
%let\buff_gobble\relax

\protected\def\buff_pickup#1#2#3#4#5#6% name, startsequence, stopsequence, before, after, undent
  {\begingroup % (1)
   #4%
   \begingroup % (2)
   \scratchcounterone\catcodetable
   \scratchcountertwo#6\relax
   \clf_erasebuffer{#1}%
   \setcatcodetable\vrbcatcodes
   \protected\def\buff_finish
     {\endgroup % (1)
      \endgroup % (2)
      #5}%
   % todo: we need to skip the first lineending which is an active character
   % but sometimes we have something different ... this is a side effect of
   % checking for optional arguments i.e. the next token is already tokenized
   % and for that reason we had the \relax as well as the \string
   \clf_pickupbuffer
     {#1}%
     {#2}%
     {#3}%
   % {\string\dofinishpickupbuffer}%
     \buff_finish
   % \ifnum#6=\plusone\s!true\else\s!false\fi
   % \expandafter\relax\string} % dirty trick
     \scratchcounterone
     % better than \string but still a dirty trick to avoid \par mess in blocks
     \expandafter\scratchcountertwo\detokenized} % the bare token (so not \detokened !)

\protected\def\buff_stop#1%
  {\endgroup % (3 & 4 & 5 & 6)
   \begincsname#1\endcsname}

\permanent\protected\lettonothing\endbuffer

\permanent\tolerant\protected\def\setbuffer[#1]#:#2\endbuffer % seldom used so we just pass #2
  {\clf_assignbuffer{#1}{\detokenize{#2}}\catcodetable\relax}

% Beware, never adapt the global buffer settings, actually we might introduce
% a broken parent chain for this purpose but on the other hand it's not that
% different from framed cum suis.

\installcorenamespace{buffer}

\installcommandhandler \??buffer {buffer} \??buffer

\setupbuffer
  [\c!before=,
   \c!after=,
   \c!define=\v!yes]

\newinteger\c_buff_n_of_defined

\mutable\let\currentdefinedbuffer\s!dummy

\appendtoks
    \global\advanceby\c_buff_n_of_defined\plusone
    \setexpandedbufferparameter\c!number{\the\c_buff_n_of_defined}%
    \cdef\currentdefinedbuffer{def-\the\c_buff_n_of_defined}%
    \ifcstok{\bufferparameter\c!define}\v!yes
      \frozen\instance\protected\edefcsname\e!start\currentbuffer\endcsname
        {\buff_start_defined{\currentbuffer}{\currentdefinedbuffer}{\e!start\currentbuffer}{\e!stop\currentbuffer}}%
      \frozen\instance\protected\edefcsname\e!get  \currentbuffer\endcsname
        {\buff_get_stored   {\currentbuffer}{\currentdefinedbuffer}}%
    \fi
\to \everydefinebuffer

\protected\def\buff_start_defined
  {\begingroup % (5)
   \buff_start_indeed}

\permanent\def\thebuffernumber #1{\namedbufferparameter{#1}\c!number}
\permanent\def\thedefinedbuffer#1{def-\namedbufferparameter{#1}\c!number}

\permanent\def\getbufferdata[#1]% expandable
  {\clf_getbuffer{#1}}

\permanent\tolerant\protected\def\getbuffer[#1]% [namelist]
  {\namedbufferparameter\empty\c!before\relax
   \clf_getbuffer{#1}%
   \namedbufferparameter\empty\c!after\relax}

\protected\def\buff_get_stored#1#2%
  {\namedbufferparameter{#1}\c!before\relax
   \clf_getbuffer{#2}%
   \namedbufferparameter{#1}\c!after\relax}

\aliased\let\rawbuffer\clf_getbuffer % expandable

\permanent\protected\def\getdefinedbuffer[#1]%
  {\buff_get_stored{#1}{\thedefinedbuffer{#1}}}%

% We had this:
%
% \permanent\tolerant\protected\def\inlinebuffer[#1]% [name]
%   {\ifempty{#1}
%      \buff_get_stored_inline_indeed\empty
%    \else
%      \processcommalist[#1]\buff_get_stored_inline_indeed
%    \fi}
%
% \protected\def\buff_get_stored_inline_indeed#1%
%   {\ignorespaces\clf_getbuffer{#1}\removeunwantedspaces}
%
% but it makes no sense to ignore spaces in between and we now do the
% list at the \LUA\ end anyway:

\permanent\tolerant\protected\def\inlinebuffer[#1]% [name]
  {\ignorespaces\clf_getbuffer{#1}\removeunwantedspaces}

\definebuffer
  [\v!hiding]

\setupbuffer
  [\v!hiding]
  [\c!before=,
   \c!after=]

%D \starttyping
%D \startbuffer[x]
%D x y z
%D \stopbuffer
%D
%D \savebuffer[x]      [temp]     % gets name: jobname-temp.tmp
%D \savebufferinfile[x][temp.log] % gets name: temp.log
%D \stoptyping

\installcorenamespace{savebuffer}
\installcorenamespace{savebuffercounter}

\installcommandhandler \??savebuffer {savebuffer} \??savebuffer

\setupsavebuffer
  [\c!list=,
   \c!file=,
   \c!directory=,
   \c!prefix=\v!yes]

\permanent\tolerant\protected\def\savebuffer[#S#1]#*[#2]%
  {\begingroup
   \ifhastok={#1}%
     \setupcurrentsavebuffer[#1]%
   \else
     \setupcurrentsavebuffer[\c!list={#1},\c!file=#2]%
   \fi
   \clf_savebuffer % will become key/value
     {\savebufferparameter\c!list}%
     {\savebufferparameter\c!file}%
     {\savebufferparameter\c!prefix}%
     {\savebufferparameter\c!option}%
     {\savebufferparameter\c!directory}%
   \endgroup}

%D \starttyping
%D \definesavebuffer[slide]
%D
%D \starttext
%D     \startslide
%D         \starttext
%D     \stopslide
%D     \startslide
%D         slide 1
%D     \stopslide
%D     text 1 \par
%D     \startslide
%D         slide 2
%D     \stopslide
%D     text 2 \par
%D     \startslide
%D         \stoptext
%D     \stopslide
%D \stoptext
%D \stoptyping

% We can keep the counter at the lua end and explicitly reset it when we
% save.

\appendtoks
    \ifcsname\e!stop\currentsavebuffer\endcsname\else
      \definebuffer[\currentsavebuffer]%
      \expandafter\newinteger\csname\??savebuffercounter\currentsavebuffer\endcsname
      \protected\edefcsname\e!stop\currentsavebuffer\endcsname{\buff_stop_save_buffer{\currentsavebuffer}}%
      \setsavebufferparameter\c!file{\currentsavebuffer.tex}%
    \fi
\to \everydefinesavebuffer

\protected\def\buff_stop_save_buffer#1%
  {\cdef\currentsavebuffer{#1}%
   \global\advanceby\csname\??savebuffercounter\currentsavebuffer\endcsname\plusone
   \clf_savebuffer % will become key/value
     {\thedefinedbuffer{\currentsavebuffer}}%
     {\savebufferparameter\c!file}%
     {\savebufferparameter\c!prefix}%
     {\ifnum\csname\??savebuffercounter\currentsavebuffer\endcsname>\plusone\v!append\fi}%
     {\savebufferparameter\c!directory}}

%D Experimental: no expansion of commands in buffer!

% \startbuffer[what]
%     context("WHAT")
% \stopbuffer
% \startbuffer
%     context("JOBNAME")
% \stopbuffer
%
% \ctxluabuffer[what] \ctxluabuffer

\permanent\tolerant\protected\def\processTEXbuffer[#1]#;#=% keep case, maybe also lower
  {\pushcatcodetable
   \catcodetable\ctxcatcodes % \setcatcodetable
   \clf_getbuffer{#1#2}%
   \popcatcodetable}

\permanent\tolerant\protected\def\ctxluabuffer[#1]#;#={\clf_getbufferctxlua{#1#2}} % todo: use public implementor
\permanent\tolerant\protected\def\mkvibuffer  [#1]#;#={\clf_getbuffermkvi  {#1#2}} % todo: use public implementor
\permanent\tolerant\protected\def\texbuffer   [#1]#;#={\clf_getbuffertex   {#1#2}} % todo: use public implementor

% maybe still used elsewhere

% \aliased\doprocesstexbuffer\mkvibuffer

\aliased\let\dostartbuffer\grabbufferdata % for old times sake, this will go away

% low level helper (for math manual):

% \showboxinbuffer{temp}<boxnumber><detail> % defined in lua, detail cf \shownodedetails 0|1|2

%D \starttyping
%D \setbox\scratchbox\hbox{$fff$}
%D \showboxinbuffer{temp}\scratchbox\plusone
%D \typebuffer[temp][option=TEX]
%D \stoptyping
%D
%D More extensive multistep cases can do this:
%D
%D \starttyping
%D \pushlogfile{oeps-1.txt}
%D \setbox0\hbox{A}\showbox0
%D \pushlogfile{oeps-2.txt}
%D \setbox0\hbox{B}\showbox0
%D \poplogfile
%D \setbox0\hbox{C}\showbox0
%D \poplogfile
%D
%D % \resetlogfile{oeps-1.txt}
%D \pushlogfile{oeps-1.txt}
%D \setbox0\hbox{A}\showbox0
%D \pushlogfile{oeps-2.txt}
%D \setbox0\hbox{B}\showbox0
%D \poplogfile
%D \setbox0\hbox{C}\showbox0
%D \poplogfile
%D \stoptyping
%D
%D But in the end that was overkill and we don't really need a stepwise verbatim
%D because we need to add comments in between anyway.

\protect \endinput

