%D \module
%D   [       file=buff-ini, % was core-buf, % blocks are moved to core-blk
%D        version=2000.01.05,
%D          title=\CONTEXT\ Buffer Macros,
%D       subtitle=Buffers,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%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}

% todo:
%
% \startluacode
%     local locations = { }
%     function document.set_number(name)
%         locations[name] = {
%             line = status.linenumber,
%             file = status.filename
%         }
%     end
%     function document.add_number(name)
%         local b, l = buffers.raw(name), locations[name]
%         if b and l then
%             for i=1,#b do
%                 b[i] = string.gsub(b[i],"# line: <number>","# line: " .. l.line + 2)
%             end
%         end
%     end
% \stopluacode
%
% \starttext
%
% \ctxlua{document.set_number("oeps")}
% \startbuffer[oeps]
% # line: <number>
%
% test
% test
% \stopbuffer
% \ctxlua{document.add_number("oeps")}
%
% \typebuffer[oeps]
%
% \stoptext

\ifdefined\doinitializeverbatim \else% temp hack
    \ifdefined\mkinitializeverbatim
        \let\doinitializeverbatim\mkinitializeverbatim
    \else
        \def\doinitializeverbatim{\tttf}
    \fi
\fi

\unprotect

\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested

\newif\ifsegmentatebuffer
\newif\ifemptybufferline

\def\currentbuffer{\jobname}

\def\setcurrentbuffer#1%
  {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}

\def\resetbuffer
  {\dosingleempty\doresetbuffer}

\def\doresetbuffer[#1]%
  {\begingroup
   \setcurrentbuffer{#1}%
   \ctxlua{buffers.erase("\currentbuffer")}%
   \endgroup}

\def\dostartbuffer
  {\bgroup
   \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
   \doquadrupleempty\dodostartbuffer}

\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
  {\iffourthargument
     \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
   \else
     \def\next{\dododostartbuffer  {}{#1}{#2}{#3}}%
   \fi
   \next}

\def\dododostartbuffer#1#2#3#4%
  {%\showmessage\m!systems{15}{#2}%
   \doifelsevalue{\??bu#1\c!paragraph}\v!yes
     {\segmentatebuffertrue} % todo in mkiv
     {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
   \doifvalue{\??bu#1\c!local}\v!yes
     {\chardef\buffernestmode\plustwo}% permit nesting
   \setcurrentbuffer{#2}%
   \doifelsenothing{#4}
     {\normalexpanded{\noexpand\setbuffercapsules{\e!start\v!buffer}{\e!stop\v!buffer}}%
      \letvalue\bufferstop\relax}
    %{\@EA\setbuffercapsules\@EA{\csname#3\@EA\endcsname\@EA}\@EA{\csname#4\endcsname}}% if we strip later
     {\setbuffercapsules{#3}{#4}}%
   \normalexpanded{\noexpand\dodowithbuffer
      {\currentbuffer}
      {\bufferstart}
      {\bufferstop}
      {\donothing}
      {\egroup
       \noexpand\getvalue{\bufferstop}}}}

\letvalue{\e!start\v!buffer}\dostartbuffer

\let\endbuffer\undefined % to please the dep parser

\def\dowithbuffer#1#2#3% name, startsequence, stopsequence, before, after
  {\setbuffercapsules{#2}{#3}%
   \normalexpanded{\noexpand\dodowithbuffer{#1}{\bufferstart}{\bufferstop}}}

\long\def\dodowithbuffer#1#2#3#4#5% name, startsequence, stopsequence, before, after
  {#4%
   \bgroup
   \setcatcodetable \vrbcatcodes
   \catcode`\\=12
   \ctxlua{buffers.erase("#1")}%
   \long\def\nododowithbuffer
     {\egroup
      #5}%
   \long\def\dododowithbuffer##1#3% is detokenize needed? TEST
     {\ctxlua
        {buffers.grab("#1","#2","#3",\!!bs\detokenize{##1}\!!es)}
        \dododowithbuffer
        \nododowithbuffer}%
   \dododowithbuffer}

\def\setbuffercapsules#1#2% \scantextokens not needed (had a reason at some point)
  {\edef\bufferstart{#1}\edef\bufferstart{\scantextokens\expandafter{\bufferstart}}%
   \edef\bufferstop {#2}\edef\bufferstop {\scantextokens\expandafter{\bufferstop }}}

\def\setbuffer
  {\dosingleempty\dosetbuffer}

\long\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
  {\begingroup
   \setcurrentbuffer{#1}%
   \ctxlua{buffers.set("\currentbuffer", \!!bs\detokenize{#2}\!!es)}%
   \endgroup}

\def\setupbuffer
  {\dodoubleempty\dosetupbuffer}

\def\dosetupbuffer[#1][#2]%
  {\ifsecondargument
     \getparameters[\??bu#1][#2]%
   \else
     \getparameters[\??bu][#1]%
   \fi}

\def\dodefinebuffer[#1][#2]%
  {\iffirstargument % else problems
     \doglobal\increment\nofdefinedbuffers
     \letvalue{\??bu#1\c!number   }\nofdefinedbuffers
     \letvalue{\??bu#1\c!paragraph}\v!no
     \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
     \setevalue{\e!get  #1}{\noexpand\dogetbuffer  [#1][def-\nofdefinedbuffers]}%
     \setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
     \getparameters[\??bu#1][#2]%
   \fi}

\def\definebuffer
  {\dodoubleempty\dodefinebuffer}

\def\getbuffer
  {\dodoubleempty\dogetbuffer}

\def\dogetbuffer[#1][#2]%
  {\ifsecondargument
     \dodogetbuffer[#1][#2]%
   \else
     \dodogetbuffer[][#1]%
   \fi}

\def\dogetbufferasis{\ctxlua{buffers.get("\currentbuffer")}}

\def\dodogetbuffer[#1][#2]%
  {\getvalue{\??bu#1\c!before}%
   \dobuffer{16}{#2}\dogetbufferasis
   \getvalue{\??bu#1\c!after}}

\def\typebuffer
  {\dodoubleempty\dotypebuffer}

\def\doprocessbufferverbatim
  {\doinitializeverbatim
   \ctxlua{buffers.type("\currentbuffer")}}

\def\doprocessbufferlinesverbatim#1#2#3%
  {#2%
   % todo, set up numbers
   \doinitializeverbatim
   \ctxlua{buffers.type("\currentbuffer")}
   #3}

\def\doifelsebuffer#1%
  {\ctxlua{buffers.doifelsebuffer("#1")}}

\def\dodotypebuffer#1#2#3% see dodotypefile
  {\doifelsebuffer{#3}
     {\dosometyping{#1}{#2}{#3}\doprocessbufferverbatim\doprocessbufferlinesverbatim}
     {\reporttypingerror{#3}}}

\def\dotypefilebuffer{\dodotypebuffer{\v!file}{}{\currentbuffer}}%

\def\dotypebuffer[#1][#2]%
  {\iffirstargument
     \dobuffer{17}{#1}\dotypefilebuffer
   \else
     \dobuffer{17}{#2}\dotypefilebuffer
   \fi}

\def\dobuffer#1#2#3%
  {\doifelsenothing{#2}
     {\dodobuffer#3\jobname}
     {\processcommalist[#2]{\dodobuffer#3}}}

\def\dodobuffer#1#2% command name
  {\pushmacro\currentbuffer
   \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
   #1%
   \popmacro\currentbuffer}

\def\processTEXbuffer{\getbuffer} % handy

% extras:

\def\inspectbuffer
  {\dosingleempty\doinspectbuffer}

\def\doinspectbuffer[#1]%
  {\setcurrentbuffer{#1}%
   \ctxlua{buffers.inspect("\currentbuffer")}}

% seldom used, only in a few projects that demanded more speed

\let\usememorybuffers\relax
\let\usefilebuffers  \relax

% this features is soldom used (complex examns where we need to fetch
% special parts of a text
%
% this is not yet supported in mkiv (relatively easy to do but there
% we don't have the par tags but need to grab 'm

\def\skippedbufferparagraphs{0}

\let\startbufferparagraph\relax
\let\stopbufferparagraph \par   % \relax

\newcount\currentbufferparagraph

\def\getbufferparagraphs
  {\dodoubleempty\dogetbufferparagraphs}

\def\dosetbufferoffset#1%
  {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
     {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
     {\currentbufferparagraph \zerocount}%
   \relax}

\def\dogetbufferparagraphs[#1][#2]%
  {\iffirstargument
     \ifsecondargument
       \dosetbufferoffset{#1}%
       \doifelse{#2}\v!all
         {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
         {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
       \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
       \def\next{\getparagraphedbuffer[#1]}%
     \else
       \dosetbufferoffset\empty
       \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
       \def\stopbufferparagraph{\dostopbufferparagraph{}}%
       \def\next{\getparagraphedbuffer[]}%
     \fi
   \else
     \dosetbufferoffset\empty
     \def\startbufferparagraph{\normalbufferparagraph{}}%
     \def\stopbufferparagraph{\dostopbufferparagraph{}}%
     \def\next{\getparagraphedbuffer[]}%
   \fi
   \next}

\def\dotypeparagraphbuffer{\ctxlua{buffers.get("\currentbuffer")}}

\def\getparagraphedbuffer[#1]%
  {\dobuffer{16}{#1}\dotypeparagraphbuffer}

\def\dostopbufferparagraph#1%
  {\getvalue{\??bu#1\c!after}\par}

\def\dostartbufferparagraph#1%
  {\par\getvalue{\??bu#1\c!before}}

\def\normalbufferparagraph
  {\advance\currentbufferparagraph \plusone
   \ifnum\currentbufferparagraph>\zerocount
     \expandafter\dostartbufferparagraph
   \else
     \expandafter\gobbleoneargument
   \fi}

\def\filterbufferparagraph#1#2%
  {\advance\currentbufferparagraph \plusone
   \ifcase\currentbufferparagraph
     \@EA\gobblebufferparagraph
   \else
     \doifinsetelse{\the\currentbufferparagraph}{#2}
       {\@EA\dostartbufferparagraph}
       {\@EA\fakebufferparagraph}%
   \fi
   {#1}}

\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
  {}

\def\fakebufferparagraph#1%
  {\bgroup
   \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
   \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}

% definitions

\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]

\setupbuffer
  [\c!paragraph=\v!no,
   \c!before=,
   \c!after=]

% only mkiv:

\def\savebuffer{\dosingleempty\dosavebuffer}
\def\dosavebuffer[#1]{\ctxlua{buffers.save("#1")}}

\protect \endinput
