%D \module
%D   [       file=strc-lnt,
%D        version=2002.05.10,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Line Notes,
%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.

% todo: mkvi #

\writestatus{loading}{ConTeXt Structure Macros / Line Notes}

%D This module loads on top of the footnote and line numbering macros.

\unprotect

\installcorenamespace{linenote}

\let\setuplinenote\setupnote

\newcount\c_strc_linenotes
\newtoks\everydefinelinenote

\unexpanded\def\definelinenote
  {\dotripleempty\strc_linenotes_define}

\def\strc_linenotes_define[#1][#2][#3]%
  {\ifcsname\??linenote#1\endcsname
     % there might be files that define the default 'linenote'
     \ifthirdargument
       \setupnote[#1][#3]%
     \else\ifsecondargument
       \setupnote[#1][#2]%
     \fi\fi
   \else
     \ifthirdargument
       \definenote[#1][#2][#3]%
     \else\ifsecondargument
       \definenote[#1][#2]%
     \else
       \definenote[#1]%
     \fi\fi
     \pushmacro\currentnote
     \edef\currentnote{#1}
     \expandafter\let\csname\??linenote\currentnote\expandafter\endcsname\csname\currentnote\endcsname % use copy command
     \setuevalue        {\currentnote}{\strc_linenotes_direct{\currentnote}}%
     \setuevalue{\e!start\currentnote}{\strc_linenotes_start {\currentnote}}%
     \setuevalue{\e!stop \currentnote}{\strc_linenotes_stop                }%
     \the\everydefinelinenote
     \popmacro\currentnote
   \fi}

\unexpanded\def\strc_linenotes_direct#1#2%
  {\global\advance\c_strc_linenotes\plusone
   \strc_linenotes_indeed{#1}{\the\c_strc_linenotes}{#2}%
   \strc_linenotes_traced\empty
   \normalexpanded{\someline[\the\c_strc_linenotes]}}

\unexpanded\def\strc_linenotes_start#1[#2]#3%
  {\global\advance\c_strc_linenotes\plusone
   \keepunwantedspaces
   \strc_linenotes_indeed{#1}{#2}{#3}%
   \strc_linenotes_traced{#2}%
   \startline[#2]}

\unexpanded\def\strc_linenotes_stop[#1]%
  {\stopline[#1]}

\let\m_page_lines_previous_to  \relax
\let\m_page_lines_previous_from\relax

\let\m_page_lines_current_to   \relax
\let\m_page_lines_current_from \relax

\newconditional\c_page_lines_current_to
\newconditional\c_page_lines_current_from

\installcorenamespace{linenotespreviousfrom}
\installcorenamespace{linenotespreviousto}

\letvalue\??linenotespreviousfrom\empty
\letvalue\??linenotespreviousto  \empty

% maybe do this in lua

\def\page_lines_in_from{\in[lr:b:\currentlinenotereference]}
\def\page_lines_in_to  {\in[lr:e:\currentlinenotereference]}

\unexpanded\def\strc_linenotes_range_normal#1% order
  {\doifelsereferencefound{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
   \ifconditional\c_page_lines_current_from
      \xdef\m_page_lines_current_from{\currentreferencelinenumber}%
      \doifelsereferencefound{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
      \ifconditional\c_page_lines_current_to
        \xdef\m_page_lines_current_to{\currentreferencelinenumber}%
        \page_lines_in_from
        \ifx\m_page_lines_current_from\m_page_lines_current_to \else
          \endash
          \page_lines_in_to
        \fi
      \else
        \page_lines_in_from
      \fi
   \else
     \page_lines_in_from
   \fi}

\unexpanded\def\strc_linenotes_range_sparse#1% order
  {\doifelsereferencefound{lr:b:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_from
   \ifconditional\c_page_lines_current_from
     \xdef\m_page_lines_current_from{\currentreferencelinenumber}%
     \doifelsereferencefound{lr:e:\currentlinenotereference}\settrue\setfalse\c_page_lines_current_to
     \ifconditional\c_page_lines_current_to
       \xdef\m_page_lines_current_to{\currentreferencelinenumber}%
       \ifx\m_page_lines_previous_from\m_page_lines_current_from
         \ifx\m_page_lines_previous_to\m_page_lines_current_to \else
           \page_lines_in_from
           \ifx\m_page_lines_current_from\m_page_lines_current_to\else\endash\page_lines_in_to\fi
         \fi
       \else
         \page_lines_in_from
         \ifx\m_page_lines_current_from\m_page_lines_current_to\else\endash\page_lines_in_to\fi
       \fi
     \else
       \page_lines_in_from
     \fi
   \else
     \ifx\m_page_lines_previous_from\m_page_lines_current_from \else
       \page_lines_in_from
     \fi
   \fi}

\let\currentlinenotereference\empty

\unexpanded\def\strc_linenotes_indeed#1#2#3%
  {\begingroup
   % we keep things local so we can use it as regular note too
   \edef\currentnotation{#1}%
   \edef\currentlinenotereference{#2}%
   \xdef\m_page_lines_previous_from{\begincsname\??linenotespreviousfrom\currentnotation\endcsname}%
   \xdef\m_page_lines_previous_to  {\begincsname\??linenotespreviousto  \currentnotation\endcsname}%
   \strc_linenotes_check_compression
   \let\currentnote\currentnotation
   \letnotationparameter\c!numbercommand\linenotelinenumber% todo: deep hook
   \letnoteparameter    \c!textcommand  \gobbleoneargument % todo: deep hook
   \csname\??linenote\currentnotation\endcsname{#3}%
   \expandafter\glet\csname\??linenotespreviousfrom\currentnotation\endcsname\m_page_lines_current_from
   \expandafter\glet\csname\??linenotespreviousto  \currentnotation\endcsname\m_page_lines_current_to
   \endgroup}

% compression

\installcorenamespace{linenotescompressmethod}

% compress=yes|no
% compressmethod=separator|stopper

\def\c!compressdistance{compressdistance}
\def\c!compressmethod  {compressmethod}
\def\c!compressstopper {compressstopper} % c
\def\v!compressstopper {compressstopper} % v

\def\v!separator {separator} % v

\setvalue{\??linenotescompressmethod\v!separator}%
  {\edef\p_compressseparator{\noteparameter\c!compressseparator}%
   \scratchskip\noteparameter\c!compressdistance\relax
   \ifx\p_compressseparator\empty
     \hskip\scratchskip
   \else
     \hskip.5\scratchskip
     \p_compressseparator
     \hskip.5\scratchskip
   \fi}

\setvalue{\??linenotescompressmethod\v!stopper}%
  {\edef\p_compressstopper{\noteparameter\c!compressstopper}%
   \scratchskip\noteparameter\c!compressdistance\relax
   \ifx\p_compressstopper\empty
     \hskip\scratchskip
   \else
     \p_compressstopper
     \hskip.5\scratchskip
   \fi}

\setvalue{\??linenotescompressmethod\v!space}%
  {\hskip\noteparameter\c!compressdistance\relax}

\def\strc_linenotes_check_compression
%   {\edef\p_linenotes_compress      {\notationparameter\c!compress}%
%    \edef\p_linenotes_compressmethod{\notationparameter\c!compressmethod}%
  {\edef\p_linenotes_compress      {\noteparameter\c!compress}%
   \edef\p_linenotes_compressmethod{\noteparameter\c!compressmethod}%
   \ifx\p_linenotes_compress\v!yes
     \let\linenotelinenumber\strc_linenotes_range_sparse
   \else
     \let\linenotelinenumber\strc_linenotes_range_normal
   \fi
   \ifcsname\??linenotescompressmethod\p_linenotes_compressmethod\endcsname \else
      \let\p_linenotes_compressmethod\v!space
   \fi}

\def\strc_linenotes_inbetween % \ifcsname\??linenote\currentnote\expandafter\endcsname
  {\csname\??linenotescompressmethod\p_linenotes_compressmethod\endcsname}

\def\strc_notes_compress_distance{\emwidth \s!plus .5\emwidth \s!minus .25\emwidth}

\setupnotes
  [%c\compress=\v!no,
   \c!compressdistance=\strc_notes_compress_distance,
   \c!compressseparator=\symbol{\v!compressseparator},
   \c!compressstopper=\symbol{\v!compressstopper}]

\appendtoks
    \letnoteparameter\c!inbetween\strc_linenotes_inbetween
\to \everydefinelinenote

% where to hook this one in? resetcounter has no hook:

\unexpanded\def\doresetlinenotecompression#1% \strc_linenotes_reset_previous
  {\expandafter\glet\csname\??linenotespreviousfrom#1\endcsname\empty
   \expandafter\glet\csname\??linenotespreviousto  #1\endcsname\empty}

\definesymbol
  [\v!compressseparator]
  [\hbox{\vl\thinspace\vl}] % \space removed

\definesymbol
  [\v!compressstopper]
  [,]

% \setupnotations
%   [%c\compress=\v!no,
%    \c!compressseparator=\symbol\v!compressseparator]

\let\strc_linenotes_traced\gobbleoneargument

\def\strc_linenotes_traced_indeed#1%
  {\iftracelinenotes
     \hbox to \zeropoint
       {\forgetall
        \hsize\zeropoint
        \hss
        \vbox to \strutheight{\llap{\red\infofont\setstrut\the\c_strc_linenotes}\vss}%
        {\color[blue]{\vl}}%
        \vbox to \strutheight{\rlap{\red\infofont\setstrut#1}\vss}%
        \hss}%
      \prewordbreak
   \fi}

\unexpanded\def\tracelinenotes
  {\let\strc_linenotes_traced\strc_linenotes_traced_indeed}

% We predefine one, namely \type {\linenote} cum suis.

\definelinenote[\v!linenote]

%D Use these when not properly nested:

\let\fromlinenote\startlinenote
\let\tolinenote  \stoplinenote

% beware: line numbers are added later on so grouping setups is a bad idea
%
% \startbuffer[test]
% \startlinenumbering[100]
% test \linenote {oeps 1} test test test test test test
% test \startlinenote [well] {oeps X} test test test test test test
% test \linenote {oeps 2} test test test test test test
% test \linenote {oeps 3} test test test test test test
% test \linenote {oeps 4} test test test test test test
% test \linenote {oeps 5} test test test test test test
% test \stoplinenote [well] test test test test test test
% \stoplinenumbering
% \stopbuffer
%
% \typebuffer[test] \getbuffer[test] \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [align=flushleft]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup,test] \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [width=4em,
%    distance=1em,
%    align=flushright]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup,test] \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [width=4em,
%    align=flushleft]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup,test] \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [width=2em,
%    distance=.5em,
%    align=middle]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup,test] \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [conversion=romannumerals,
%    start=1,
%    step=1,
%    location=text,
%    style=slanted,
%    color=blue,
%    width=1.5em]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup] \startnarrower\getbuffer[test]\stopnarrower \page
%
% \startbuffer[setup]
% \setuplinenumbering
%   [width=4em,
%    left=--,
%    right=--,
%    align=middle]
% \stopbuffer
%
% \typebuffer[setup] \getbuffer[setup,test] \page
%
% \startbuffer[setup-1]
% \setuplinenumbering
%   [style=\bfxx,
%    command=\WatchThis]
% \stopbuffer
%
% \startbuffer[setup-2]
% \def\WatchThis#1%
%   {\ifodd\linenumber
%      \definecolor[linecolor][red]%
%    \else
%      \definecolor[linecolor][green]%
%    \fi
%    \inframed
%      [offset=1pt,frame=off,background=color,backgroundcolor=linecolor]
%      {#1}}
% \stopbuffer
%
% \typebuffer[setup-1,setup-2] \getbuffer[setup-1,setup-2,test] \page
%
% \startbuffer[setup-1]
% \setuplinenumbering
%   [location=inright,
%    style=\bfxx,
%    command=\WatchThis]
% \stopbuffer
%
% \typebuffer[setup-1] \getbuffer[setup-1,setup-2,test] \page

\protect \endinput
