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

\aliased\let\setuplinenote\setupnote

\newinteger\c_strc_linenotes
\newtoks   \everydefinelinenote

\permanent\tolerant\protected\def\definelinenote[#1]#*[#S#2]#*[#S#3]%
  {\ifarguments
     % error
   \orelse\ifcsname\??linenote#1\endcsname
     % there might be files that define the default 'linenote'
     \ifparameters\or\or
       \setupnote[#1][#2]%
     \or
       \setupnote[#1][#3]%
     \fi
   \else
     \ifparameters\or
       \definenote[#1]%
     \or
       \definenote[#1][#2]%
     \or
       \definenote[#1][#2][#3]%
     \fi
     \pushmacro\currentnote
     \cdef\currentnote{#1}
     \letcsname\??linenote\currentnote\expandafter\endcsname\csname\currentnote\endcsname % use copy command
     \frozen\instance\protected\edefcsname        \currentnote\endcsname{\strc_linenotes_direct{\currentnote}}%
     \frozen\instance\protected\edefcsname\e!start\currentnote\endcsname{\strc_linenotes_start {\currentnote}}%
     \frozen\instance\protected\edefcsname\e!stop \currentnote\endcsname{\strc_linenotes_stop                }%
     \expand\everydefinelinenote
     \popmacro\currentnote
   \fi}

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

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

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

\mutable\lettonothing\currentlinenotereference

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

\protected\def\strc_linenotes_range_normal#1% order
  {\doifelsereferencefound{lr:b:\currentlinenotereference}%
     {\c_page_lines_current_from\conditionaltrue}%
     {\c_page_lines_current_from\conditionalfalse}%
   \ifconditional\c_page_lines_current_from
      \xdef\m_page_lines_current_from{\currentreferencelinenumber}%
      \doifelsereferencefound{lr:e:\currentlinenotereference}%
        {\c_page_lines_current_to\conditionaltrue}%
        {\c_page_lines_current_to\conditionalfalse}%
      \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}

\protected\def\strc_linenotes_range_sparse#1% order
  {\doifelsereferencefound{lr:b:\currentlinenotereference}%
     {\c_page_lines_current_from\conditionaltrue}%
     {\c_page_lines_current_from\conditionalfalse}%
   \ifconditional\c_page_lines_current_from
     \xdef\m_page_lines_current_from{\currentreferencelinenumber}%
     \doifelsereferencefound{lr:e:\currentlinenotereference}%
       {\c_page_lines_current_to\conditionaltrue}%
       {\c_page_lines_current_to\conditionalfalse}%
     \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}

\lettonothing\currentlinenotereference

\mutable\let\linenotelinenumber\relax

\protected\def\strc_linenotes_indeed#1#2#3%
  {\begingroup
   % we keep things local so we can use it as regular note too
   \cdef\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, beware: should be mutable
   \letnoteparameter    \c!textcommand  \gobbleoneargument  % todo: deep hook
   \csname\??linenote\currentnotation\endcsname{#3}%
   \gletcsname\??linenotespreviousfrom\currentnotation\endcsname\m_page_lines_current_from
   \gletcsname\??linenotespreviousto  \currentnotation\endcsname\m_page_lines_current_to
   \endgroup}

% compression

\installcorenamespace{linenotescompressmethod}

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

\defcsname\??linenotescompressmethod\v!separator\endcsname
  {\edef\p_compressseparator{\noteparameter\c!compressseparator}%
   \scratchskip\noteparameter\c!compressdistance\relax
   \ifempty\p_compressseparator
     \hskip\scratchskip
   \else
     \hskip.5\scratchskip
     \begingroup\p_compressseparator\endgroup
     \hskip.5\scratchskip
   \fi}

\defcsname\??linenotescompressmethod\v!stopper\endcsname
  {\edef\p_compressstopper{\noteparameter\c!compressstopper}%
   \scratchskip\noteparameter\c!compressdistance\relax
   \ifempty\p_compressstopper
     \hskip\scratchskip
   \else
     \begingroup\p_compressstopper\endgroup
     \hskip.5\scratchskip
   \fi}

\defcsname\??linenotescompressmethod\v!space\endcsname
  {\hskip\noteparameter\c!compressdistance\relax}

\def\strc_linenotes_check_compression
  {\edef\p_linenotes_compressmethod{\noteparameter\c!compressmethod}%
   \ifcstok{\noteparameter\c!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
  {\begingroup
   \strc_linenotes_check_compression
   \begincsname\??linenotescompressmethod\p_linenotes_compressmethod\endcsname
   \endgroup}

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

\permanent\protected\def\doresetlinenotecompression#1% \strc_linenotes_reset_previous
  {\gletcsname\??linenotespreviousfrom#1\endcsname\empty
   \gletcsname\??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%
  {\hpack to \zeropoint
     {\forgetall
      \hsize\zeropoint
      \hss
      \vpack to \strutheight{\llap{\red\infofont\setstrut\the\c_strc_linenotes}\vss}%
      {\color[blue]{\vl}}%
      \vpack to \strutheight{\rlap{\red\infofont\setstrut#1}\vss}%
      \hss}%
   \prewordbreak}

\permanent\protected\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:

\aliased\let\fromlinenote\startlinenote
\aliased\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

