%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}{}

\unprotect

% number is messy and not needed as we store the number anyway
% we can get rid of \c!number

\let\currentbuffer\empty

           \def\doifelsebuffer     #1{\clf_doifelsebuffer     {#1}}
\unexpanded\def\doifelsebufferempty#1{\clf_doifelsebufferempty{#1}}

\let\doifbufferelse\doifelsebuffer

\unexpanded\def\resetbuffer
  {\dosingleempty\buff_reset}

\def\buff_reset[#1]%
  {\clf_erasebuffer{#1}}

\setuvalue{\e!start\v!buffer}%
  {\begingroup % (3)
   \obeylines
   \dodoubleempty\buff_start}

\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#5% \donothing needed ! #5=undent)
%   {\normalexpanded{\buff_pickup{#2}{#3}{#4}{}{\buff_stop{#4}}\plusone}}

% \def\buff_start_indeed#1#2#3#4%
%   {\normalexpanded{\buff_pickup{#2}{#3}{#4}{}{\buff_stop{#4}}\plusone}}

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

\unexpanded\def\grabbufferdata % was: \dostartbuffer
  {\begingroup % (4)
   \obeylines
   \doquadrupleempty\buff_grab_direct_indeed}

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

\def\buff_grab_direct_indeed % [category] [name] [start] [stop]
  {\iffourthargument
     \expandafter\buff_grab_direct_indeed_a
   \else
     \expandafter\buff_grab_direct_indeed_b
   \fi}

\def\buff_grab_direct_indeed_a[#1][#2][#3][#4]{\buff_start_indeed  {#1}{#2}{#3}{#4}}
\def\buff_grab_direct_indeed_b[#1][#2][#3][#4]{\buff_start_indeed\empty{#1}{#2}{#3}}

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

% \unexpanded\def\buff_pickup#1#2#3#4#5#6% name, startsequence, stopsequence, before, after, undent
%   {\begingroup % (1)
%    #4%
%    \begingroup % (2)
%    \edef\catcodetableofbuffer{\number\catcodetable}%
%    \clf_erasebuffer{#1}%
%    \setcatcodetable\vrbcatcodes
%    \def\buff_finish
%      {\endgroup % (1)
%       \endgroup % (2)
%       #5}%
%    \def\buff_gobble##1#3% is detokenize needed? TEST
%     %{\ctxcommand{grabbuffer("#1","#2","#3",\!!bs\detokenize{##1}\!!es)} % space ?
%      {\ctxcommand{grabbuffer("#1","#2","#3",\!!bs>##1\!!es,\catcodetableofbuffer,\ifnum#6=\plusone true\else false\fi)}% space ?
%       \buff_gobble
%       \buff_finish}%
%    \buff_gobble}

% % \def\startgrab
% %   {\begingroup
% %    \setcatcodetable\vrbcatcodes
% %    \ctxlua{tokens.pickup("\\startgrab","\\stopgrab") context("\\endgroup")}}
% %
% % \def\stopgrab
% %   {}

\unexpanded\def\buff_pickup#1#2#3#4#5#6% name, startsequence, stopsequence, before, after, undent
  {\begingroup % (1)
   #4%
   \begingroup % (2)
   \scratchcounter\catcodetable
   \clf_erasebuffer{#1}%
   \setcatcodetable\vrbcatcodes
   \unexpanded\def\dofinishpickupbuffer
     {\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 have the \relax as well as the \string
   \clf_pickupbuffer
     {#1}%
     {#2}%
     {#3}%
     {\string\dofinishpickupbuffer}%
     \scratchcounter
     \ifnum#6=\plusone\s!true\else\s!false\fi
 % \relax}
   \expandafter\relax\string} % maybe \normalexpanded{\relax\utfchar{7}}} signal

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

% \installctxfunction\dopickupbuffer{commands.dopickupbuffer}

\unexpanded\def\setbuffer
  {\dosingleempty\buff_set}

\let\endbuffer\relax

\def\buff_set[#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=]

\newcount\c_buff_n_of_defined

\let\currentdefinedbuffer\s!dummy

\appendtoks
    \global\advance\c_buff_n_of_defined\plusone
    \setexpandedbufferparameter\c!number{\number\c_buff_n_of_defined}%
    \edef\currentdefinedbuffer{def-\number\c_buff_n_of_defined}%
    \setuevalue{\e!start\currentbuffer}{\buff_start_defined{\currentbuffer}{\currentdefinedbuffer}{\e!start\currentbuffer}{\e!stop\currentbuffer}}%
    \setuevalue{\e!get  \currentbuffer}{\buff_get_stored   {\currentbuffer}{\currentdefinedbuffer}}%
\to \everydefinebuffer

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

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

\unexpanded\def\getbuffer % no [settings yet]
  {\dosingleempty\buff_get}

\unexpanded\def\buff_get[#1]% [name]
  {\namedbufferparameter\empty\c!before\relax
   \doifelsenothing{#1}
     {\buff_get_stored_indeed\empty}
     {\processcommalist[#1]\buff_get_stored_indeed}%
   \namedbufferparameter\empty\c!after\relax}

% \installcommalistprocessorcommand \buff_get_stored_list \empty \buff_get_stored_indeed
%
% \unexpanded\def\buff_get[#1]% [name]
%   {\namedbufferparameter\empty\c!before\relax
%    \doifelsenothing{#1}
%      {\buff_get_stored_indeed\empty}
%      {\buff_get_stored_list[#1]}%
%    \namedbufferparameter\empty\c!after\relax}

\unexpanded\def\buff_get_stored#1#2%
  {\namedbufferparameter{#1}\c!before\relax
   \buff_get_stored_indeed{#2}%
   \namedbufferparameter{#1}\c!after\relax}

\unexpanded\def\buff_get_stored_indeed#1%
  {\clf_getbuffer{#1}}

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

\unexpanded\def\inlinebuffer
  {\dosingleempty\buff_get_inline}

\unexpanded\def\buff_get_inline[#1]% [name]
  {\doifelsenothing{#1}
     {\buff_get_stored_inline_indeed\empty}
     {\processcommalist[#1]\buff_get_stored_inline_indeed}}

\unexpanded\def\buff_get_stored_inline_indeed#1%
  {\ignorespaces\clf_getbuffer{#1}\removeunwantedspaces}

\def\rawbuffer#1% expandable
  {\clf_getbuffer{#1}}

\definebuffer
  [\v!hiding]

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

\unexpanded\def\processTEXbuffer % keep case, maybe also lower
  {\dosingleempty\buff_process_tex}

\def\buff_process_tex[#1]%
  {\pushcatcodetable
   \catcodetable\ctxcatcodes % \setcatcodetable
   \buff_get_stored_indeed{#1}%
   \popcatcodetable}

% only mkiv:
%
% \startbuffer[x]
% x
% \stopbuffer
%
% \savebuffer[x]      [temp]     % gets name: jobname-temp.tmp
% \savebufferinfile[x][temp.log] % gets name: temp.log

\installcorenamespace{savebuffer}
\installcorenamespace{savebuffercounter}

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

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

\unexpanded\def\savebuffer
  {\dodoubleempty\buff_save}

\def\buff_save[#1][#2]%
  {\begingroup
   \doifelseassignment{#1}
     {\setupcurrentsavebuffer[#1]}%
     {\setupcurrentsavebuffer[\c!list={#1},\c!file=#2]}%
   \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

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

\protected\def\buff_stop_save_buffer#1%
  {\edef\currentsavebuffer{#1}%
   \global\advance\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

\unexpanded\def\ctxluabuffer {\dosingleempty\buff_ctxlua}
\unexpanded\def\mkvibuffer   {\dosingleempty\buff_mkvi}
% what was:    \mkvibufferraw

\def\buff_ctxlua[#1]{\clf_getbufferctxlua{#1}}
\def\buff_mkvi  [#1]{\clf_getbuffermkvi  {#1}}

% used elsewhere

\unexpanded\def\doprocesstexbuffer#1{\buff_process_tex[#1]} % still used?

\let\dostartbuffer\grabbufferdata % for old times sake

% new (expandable):

\def\getbufferdata[#1]{\buff_get_stored_indeed{#1}}

\protect \endinput

