%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%
  {\ctxcommand{doifelsebuffer("#1")}}

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

\def\buff_reset[#1]%
  {\ctxcommand{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% \donothing needed !
  {\normalexpanded{\buff_pickup{#2}{#3}{#4}{}{\buff_stop{#4}}}}

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

\unexpanded\def\buff_pickup#1#2#3#4#5% name, startsequence, stopsequence, before, after
  {\begingroup % (1)
   #4%
   \begingroup % (2)
   \edef\catcodetableofbuffer{\number\catcodetable}%
   \ctxcommand{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)}% space ?
      \buff_gobble
      \buff_finish}%
   \buff_gobble}

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

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

\let\endbuffer\relax

\def\buff_set[#1]#2\endbuffer % seldom used so we just pass #2
  {\ctxcommand{assignbuffer("#1",\!!bs\detokenize{#2}\!!es,\number\catcodetable)}}

% 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%
  {\ctxcommand{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
   \doifassignmentelse{#1}
     {\setupcurrentsavebuffer[#1]}%
     {\setupcurrentsavebuffer[\c!list={#1},\c!file=#2]}%
   \ctxcommand{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]{\ctxcommand{getbufferctxlua("#1")}}
\def\buff_mkvi  [#1]{\ctxcommand{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
