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

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

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

\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 na 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)
   \csname#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
   \doifelsenothing{#1}
     {\buff_get_stored_indeed\empty}
     {\processcommalist[#1]\buff_get_stored_indeed}%
   \namedbufferparameter\empty\c!after}

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

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

\installsetuponlycommandhandler \??savebuffer {savebuffer}

\setupsavebuffer
  [\c!list=,
   \c!file=,
   \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{\directsavebufferparameter\c!list}{\directsavebufferparameter\c!file}{\directsavebufferparameter\c!prefix}%
   \endgroup}

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

%D This is a weird one, moved from cont-new. Do we really need it? If not
%D it will go away.

\bgroup \permitcircumflexescape

\obeylines % don't remove %'s !

\gdef\collapsedspace#1%
  {\ifx#1^^M%
     \expandafter\collapsedspace
   \else
     \space
     \expandafter#1%
   \fi}

\unexpanded\gdef\collapsespaces
  {\prependtoksonce\relax\to\everyeof%
   \ignorelines%
   \ignoretabs%
   \let\obeyedspace\collapsedspace%
   \obeyspaces}

\egroup

\protect \endinput
