%D \module
%D   [       file=strc-lst,
%D        version=2008.10.20,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Lists,
%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 Structure Macros / Lists}

\registerctxluafile{strc-lst}{autosuffix}

% clean up in progress ...
%
% also (long term) todo:
%
% autocrossdocument
% auto refs to lists (chain)
%
% TODO: strut=yes|no
%
% \lists -> strc_lists

\unprotect

%D Lists are mostly used for tables of contents but are in fact a rather generic
%D feature of \CONTEXT. We seperate between storage and rendering and the current
%D implementation is a reworked version of all that was added in steps. As lists
%D are used frequently compatibility is an important aspect. A couple of rendering
%D alternatives are provided here but more are possible.

\installcorenamespace{list}

\installframedcommandhandler \??list {list} \??list

\aliased\let\setuplists\setuplist % yes or no

\setuplist
  [\c!height=\v!broad,
   \c!depth=\v!broad,
   \c!offset=.25\emwidth,
   \c!state=\v!start,
   \c!coupling=\v!off,
   \c!criterium=\v!local,
   \c!reference=,% was number which was sort of obsolete
   \c!width=3\emwidth,
  %\c!maxwidth=,
   \c!distance=\zeropoint,
   \c!margin=\zeropoint,
   \c!alternative=\c!b,
   \c!style=\v!normal,
  %\c!color=,
   \c!textstyle=\listparameter\c!style,   % \currentliststyleparameter (but then we need to set it in every ...)
   \c!numberstyle=\listparameter\c!style, % \currentliststyleparameter
   \c!pagestyle=\listparameter\c!style,   % \currentliststyleparameter
   \c!textcolor=\listparameter\c!color,   % \currentlistcolorparameter (but then we need to set it in every ...)
   \c!numbercolor=\listparameter\c!color, % \currentlistcolorparameter
   \c!pagecolor=\listparameter\c!color,   % \currentlistcolorparameter
   \c!numbercommand=\firstofoneargument,
   \c!textcommand=\firstofoneargument,
   \c!pagecommand=\firstofoneargument,
   \c!pagenumber=\v!yes, % better: 'first'
   \c!headnumber=\v!yes, % better: 'second'
%  \c!sectionnumber=\listparameter\c!headnumber, % use this instead
   \c!interaction=\v!all, % was \v!sectionnumber, % or make this headnumber (or accept both)
   \c!label=\v!no,
  %\c!extras=,
  %\c!aligntitle=,
  %\c!before=,
  %\c!after=,
  %\c!inbetween=,
  %\c!symbol=,
  %\c!expansion=,
   \c!limittext=\languageparameter\c!limittext] % not used currently

%D Kind of new:

\permanent\protected\tolerant\def\uselist[#1]#*[#2]#*[#3]% tag file
  {\doifelsefiledefined{#1}{}{\usefile[#1][#2]}%
   \clf_uselist{#1}{#2}{#3}}

%D Helpers:

\permanent\protected\def\usenestedliststyleandcolor#style#color% will change
  {\useliststyleandcolor#style#color%
   % how about style
   \ifempty\currentcolorparameter \else
     \resetinteractioncolor
   \fi}

\permanent\protected\def\doifelselist#tag% can also move to \installcommandhandler
  {\ifcsname\namedlisthash{#tag}\s!parent\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doiflistelse\doifelselist

%D Regular list entries are bound to a specific location in order to get the right
%D pagenumber etc.\ associated. When pushing something inbetween (in mkiv) it ends
%D up directtly in the list. This is the default because otherwise users will wonder
%D why spacing might get messed up (due to an unseen but present node). It is
%D possible to force a location by explicitly setting \type {location} to \type
%D {here}.
%D
%D Another way to force a certain order is to set the \type {order} variable when
%D placing a list. The \type {command} option only pushes commands into the right
%D order, and \type {all} orders all entries (which might be too much). In this case
%D no specific location is needed with the inbetween method. Maybe additional
%D mechanisms show up some day. See \type {inbetween-001.tex} for an example.

% command  : location=none
% userdata : location=none
% simple   : location=here

\installcorenamespace {listlocations}

\permanent\protected\def\doifelseinlistentry#1%
  {\unless\ifcsname\??listlocations#1\endcsname
     \expandafter\secondoftwoarguments
   \orelse\ifnum\lastnamedcs=\structurelistlocation\relax
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifelseincurrentlistentry
  {\doifelseinlistentry\currentlist}

\permanent\protected\def\structurelistinject[#tag]%
  {\begingroup
   \cdef\currentlist{#tag}%
   \ifcstok{\listparameter\c!state}\v!start
     \expandafter\strc_lists_inject_yes
   \else
     \expandafter\strc_lists_inject_nop
   \fi}

\tolerant\protected\def\strc_lists_inject_nop[#S#settings]#spacer[#S#userdata]%
  {\endgroup}

\def\strc_lists_inject_enhance#listindex%
  {\expandafter\clf_deferredenhancelist\number#listindex\relax}

\tolerant\protected\def\strc_lists_inject_yes[#S#settings]#spacer[#S#userdata]% can be used directly
  {\setupcurrentlist[\c!type=userdata,\c!location=\v!none,#settings]% grouped (use \let...
   \edef\p_location{\listparameter\c!location}%
   \setnextinternalreference
   \scratchcounter\clf_addtolist
        references {
            internal \locationcount
          % block    {\currentsectionblock} % needed for publications (can be get from section)
          % section  structures.sections.currentid()
          % location {\p_location}
        }
        metadata {
            kind     {\listparameter\c!type}
            name     \currentlist
          % level    structures.sections.currentlevel()
            catcodes \catcodetable
        }
        userdata {\detokenize\expandafter{\expanded{#userdata}}}
   \relax
   \edef\currentlistnumber{\the\scratchcounter}%
   \xdefcsname\??listlocations\currentlist\endcsname{\the\locationcount}%
   \ifx\p_location\v!here
     % this branch injects nodes !
     \strc_lists_inject_enhance{\currentlistnumber}%
     \clf_setinternalreference
        internal \locationcount
        view     {\interactionparameter\c!focus}%
     \relax % this will change
     \xdef\currentstructurelistattribute{\the\lastdestinationattribute}%
     \dontleavehmode\hpack attr \destinationattribute \lastdestinationattribute{}% todo
   \else
     % and this one doesn't
     \clf_enhancelist\currentlistnumber\relax
   \fi
   \endgroup}

% todo: make like \strc_references_direct_full_user ... with {}{}{}

\protected\def\strc_lists_inject_direct[#tag]% [#settings][#userdata]
  {\begingroup
   \cdef\currentlist{#tag}%
   \strc_lists_inject_yes} % [#settings][#userdata]

\permanent\protected\def\writebetweenlist[#tag]%
  {\begingroup
   \cdef\currentlist{#tag}%
   \ifcstok{\namedlistparameter{#tag}\c!state}\v!start
     \expandafter\strc_lists_write_between_yes
   \else
     \expandafter\strc_lists_write_between_nop
   \fi}

\tolerant\def\strc_lists_write_between_yes[#S#settings]#:#command%
  {\strc_lists_inject_yes[#settings,\c!type=\s!command][command={#command}]}

\tolerant\def\strc_lists_write_between_nop[#S#settings]#:#command%
  {\endgroup}

\permanent\protected\def\writedatatolist[#tag]%
  {\begingroup
   \cdef\currentlist{#tag}%
   \ifcstok{\namedlistparameter{#tag}\c!state}\v!start
     \expandafter\strc_lists_write_data_to_yes
   \else
     \expandafter\strc_lists_write_data_to_nop
   \fi}

\tolerant\def\strc_lists_write_data_to_yes[#S#settings]#spacer[#userdata]%
  {\ifparameter#userdata\or % no need to have an extra step ... used seldom
     \strc_lists_inject_yes[#settings,\c!type=\s!userdata][#userdata]%
   \else
     \strc_lists_inject_yes[\c!type=\s!userdata][#settings]%
   \fi}

\tolerant\def\strc_lists_write_data_to_nop[#S#settings]#spacer[#userdata]%
  {\endgroup}

\permanent\protected\def\writetolist[#tag]%
  {\begingroup
   \cdef\currentlist{#tag}%
   \ifcstok{\namedlistparameter{#tag}\c!state}\v!start
     \expandafter\strc_lists_write_to_yes
   \else
     \expandafter\strc_lists_write_to_nop
   \fi}

\tolerant\def\strc_lists_write_to_yes[#S#settings]#:#first#second% no \s!first because we don't expand user settings
  {\strc_lists_inject_yes[\c!location=\v!here,#settings,\c!type=\s!simple][first={#first},second={#second}]}

\tolerant\def\strc_lists_write_to_nop[#S#settings]#:#first#second%
  {\endgroup} % \strc_lists_inject_nop[][]

% \starttyping
% \installstructurelistprocessor{chapter:userdata}
%   {\startlinecorrection[blank]
%    \hfill \inframed{you really need to look at \structurelistuservariable{pagenumber}}%
%    \stoplinecorrection}
%
% \starttext
%   \placelist[chapter]
%   \chapter{one}
%   \writebetweenlist[chapter][location=here]{\blank page 4\blank}
%   \writedatatolist[chapter][location=here][pagenumber=4]
%   \writetolist[chapter]{}{It's a test}
%   \chapter{two}
% \stoptext
% \stoptyping

%D When placing a list either one or a set can be giving. This makes it possible to
%D flush for instance an nested (or merged) table of contents. Keep in mind that
%D placing a list is what we do most (think of tables of contents, figures, etc.\
%D but other usage is also possible in which case low level commands have to be
%D used.

\newtoks\everystructurelist

\permanent\tolerant\protected\def\placelist[#taglist]#spacer[#S#settings]%
  {\begingroup
   \startpacked[\v!blank]%
   \edef\m_list {#taglist}%
   \edef\m_first{\firststructureelementinlist{#taglist}}%
   \ifx\m_list\m_first
      % use settings of first
   \else
      % use settings of root
      \lettonothing\m_first
   \fi
   \strc_lists_place_indeed\m_first\m_list{#settings}%
   \stoppacked
   \endgroup}

\permanent\tolerant\protected\def\placerawlist[#tag]#spacer[#S#settings]% just one list
  {\strc_lists_place_indeed\empty{#tag}{#settings}}

\aliased\let\strc_lists_place\placelist % used in strc-flt

\def\strc_lists_place_indeed#tag#list#settings%
  {\begingroup
   \expand\t_lists_every_renderingcleanup % \lettonothing\currentlistentrylocation
   \cdef\currentlist{#tag}%
   \setupcurrentlist[#settings]%
   \expand\everystructurelist
 % \ifcstok{\listparameter\c!coupling}\v!on
 %   \startlistreferences{#tag}%
 % \fi
   \strc_lists_place_current % maybe inline
     {#list}%
     {\listparameter\c!criterium}%
     {\listparameter\c!reference}%
     {\listparameter\c!extras}%
     {\listparameter\c!order}%
     {\listparameter\c!levels}%
 % \stoplistreferences
   \par % todo: only when vertical list mode
   \endgroup
   \strc_lists_set_mode}

\def\strc_lists_set_mode
  {\ifcase\structurelistsize\relax
     \resetsystemmode\v!list
   \else
     \setsystemmode  \v!list
   \fi}

%D Complete lists are just lists but with a title. They were originally introduced
%D to minimize the number for commands in a document source but nowadays that is
%D less an issue in the sense that the extra few lines are neglectable to the rest.

\ifdefined\startnamedsection \else \let\startnamedsection\relax \fi
\ifdefined\stopnamedsection  \else \let\stopnamedsection \relax \fi
\ifdefined\headtext          \else \let\headtext         \relax \fi

\permanent\tolerant\protected\def\completelist[#tag]#spacer[#S#settings]%
  {\expanded{\startnamedsection[\v!title][\c!title=\headtext{#tag},\c!reference=#tag]}% {} around ref ?
   \strc_lists_place[#tag][#settings]%
   \stopnamedsection}

\permanent\tolerant\protected\def\strc_lists_complete[#singular]#spacer[#plural]#spacer[#S#settings]% used in strc-flt
  {\expanded{\startnamedsection[\v!title][\c!title=\headtext{#plural},\c!reference=#singular]}% {} around ref ?
   \strc_lists_place[#singular][#settings]%
   \stopnamedsection}

\permanent\tolerant\def\strc_lists_combined_complete[#tag]#spacer[#S#settings]%
  {\expanded{\startnamedsection[\v!title][\c!title={\headtext{#tag}},\c!reference=#tag]}%
   \placecombinedlist[#tag][#settings]%
   \stopnamedsection}

%D Combined list provide a nice level of abstraction.
%D
%D \starttyping
%D \definecombinedlist[whatever][a,b,c][settings]
%D \stoptyping

\permanent\tolerant\protected\def\definecombinedlist[#tag]#spacer[#list]#spacer[#S#settings]%
  {\definelist[#tag][\c!criterium=\v!local,\c!reference=,\c!alternative=,\c!list={#list},#settings]% inherits from root
   \frozen\instance\defcsname\e!setup#tag\e!endsetup\endcsname{\setupcombinedlist[#tag]}%
   \frozen\instance\defcsname\e!place#tag\endcsname{\placecombinedlist[#tag]}%
   \frozen\instance\defcsname\e!complete#tag\endcsname{\strc_lists_combined_complete[#tag]}}

\permanent\tolerant\protected\def\setupcombinedlist[#tag]#spacer[#settings]%
  {\ifarguments\or\or
     \setuplist[#tag][#settings]% we don't want to mess up the parent
   \fi}

\permanent\tolerant\protected\def\placecombinedlist[#tag]#spacer[#S#settings]% i.e. no list set in settings
  {\begingroup
   \cdef\currentlist{#tag}%
   \setupcurrentlist[#settings]%
   \edef\m_strc_list_alternative{\listparameter\c!alternative}% we only inherit alternative
   \strc_lists_place_indeed{#tag}{\listparameter\c!list}{#settings}%
   \endgroup}

%D Given that some variables are set, we can ask for some properties of
%D an entry.

\mutable\def\currentstructurelistnumber{0}     % injection
\mutable\def\currentlistmethod         {entry} % typesetting
\mutable\def\currentlistindex          {0}     % typesetting (maybe also a real counter)

\permanent\protected\def\savedlistnumber        #1#2{\clf_savedlistnumber        {#1}{#2}}
\permanent\protected\def\savedlisttitle         #1#2{\clf_savedlisttitle         {#1}{#2}}
\permanent\protected\def\savedlistprefixednumber#1#2{\clf_savedlistprefixednumber{#1}{#2}}

\newconditional\c_lists_show_realpage

\installcorenamespace {listpagenumber}

\defcsname\??listpagenumber\v!always  \endcsname{\c_lists_show_page\conditionaltrue\c_lists_has_page\conditionaltrue}
\defcsname\??listpagenumber\v!yes     \endcsname{\c_lists_show_page\conditionaltrue}
\defcsname\??listpagenumber\s!realpage\endcsname{\c_lists_show_page\conditionaltrue\c_lists_show_realpage\conditionaltrue}

\def\strc_lists_process_pagenumber#1%
  {\begincsname\??listpagenumber#1\endcsname}

\permanent\def\strc_lists_structurelistexternal{\clf_listexternal{\currentlistindex}}
\permanent\def\strc_lists_structurelistlocation{\clf_listlocation{\currentlistindex}}

\aliased\let\structurelistexternal\strc_lists_structurelistexternal
\aliased\let\structurelistlocation\strc_lists_structurelistlocation

% unformatted (the name #1 is for consistency and only makes sense for number)

\permanent\def\structurelistrawnumber        #1{\clf_listrawnumber  {#1}{\currentlistindex}}
\permanent\def\structurelistrawpagenumber    #1{\clf_listrawuserpage{#1}{\currentlistindex}}
\permanent\def\structurelistrawrealpagenumber#1{\clf_listrawrealpage{#1}{\currentlistindex}}

\permanent\def\structurelistnumber        {\clf_listrawnumber  {\currentlist}{\currentlistindex}}
\permanent\def\structurelistuserpagenumber{\clf_listrawuserpage{\currentlist}{\currentlistindex}}
\permanent\def\structurelistrealpagenumber{\clf_listrawrealpage{\currentlist}{\currentlistindex}}

\permanent\protected\def\structurelistpagenumber
  {\dostarttaggednodetail\t!listpage
   \ifconditional\c_lists_show_realpage
     \clf_listrawrealpage{\currentlist}{\currentlistindex}%
   \else
     \clf_listprefixedpage
       {\currentlist}%
       \currentlistindex
       {%
         separatorset  {\listparameter\c!pageprefixseparatorset}%
         conversionset {\listparameter\c!pageprefixconversionset}%
         set           {\listparameter\c!pageprefixset}%
         segments      {\listparameter\c!pageprefixsegments}%
         connector     {\listparameter\c!pageprefixconnector}%
       }%
       {%
         prefix        {\listparameter\c!pageprefix}%
         conversionset {\listparameter\c!pageconversionset}%
         starter       {\listparameter\c!pagestarter}%
         stopper       {\listparameter\c!pagestopper}%
       }%
     \relax
   \fi
   \dostoptagged}

\permanent\protected\def\structurelistuservariable#name%
  {\dostarttagged\t!listdata{#name}%
   \clf_listuserdata{\currentlist}\currentlistindex{#name}%
   \dostoptagged}

\permanent\def\rawstructurelistuservariable#name%
  {\clf_listuserdata{\currentlist}\currentlistindex{#name}}

\permanent\protected\def\structurelistfirst {\structurelistuservariable\s!first } % s!
\permanent\protected\def\structurelistsecond{\structurelistuservariable\s!second} % s!

\permanent\def\rawstructurelistfirst {\rawstructurelistuservariable\s!first } % s! % was \protected
\permanent\def\rawstructurelistsecond{\rawstructurelistuservariable\s!second} % s! % was \protected

\permanent\protected\def\doifelsestructurelisthaspage
  {\doifelselisthaspage{\currentlist}{\currentlistindex}}

\permanent\protected\def\doifelsestructurelisthasnumber
  {\doifelselisthasnumber{\currentlist}{\currentlistindex}}

\aliased\let\doifstructurelisthaspageelse  \doifelsestructurelisthaspage
\aliased\let\doifstructurelisthasnumberelse\doifelsestructurelisthasnumber

\permanent\protected\def\structurelistgenerictitle
  {\dostarttaggednodetail\t!listcontent
   \clf_listtitle{\currentlist}\currentlistindex\relax
   \dostoptagged}

\permanent\protected\def\structurelistgenericnumber % tricky, we need to delay tagging as we have nested lua calls
  {\dostarttaggednodetail\t!listtag
   \clf_listprefixednumber
     {\currentlist}%
     \currentlistindex
     {%
         prefix        {\listparameter\c!prefix}%
         separatorset  {\listparameter\c!prefixseparatorset}%
         conversionset {\listparameter\c!prefixconversionset}%
         starter       {\listparameter\c!prefixstarter}%
         stopper       {\listparameter\c!prefixstopper}%
         set           {\listparameter\c!prefixset}%
         segments      {\listparameter\c!prefixsegments}%
         connector     {\listparameter\c!prefixconnector}%
     }%
     {%
         separatorset  {\listparameter\c!numberseparatorset}%
         conversionset {\listparameter\c!numberconversionset}%
         starter       {\listparameter\c!numberstarter}%
         stopper       {\listparameter\c!numberstopper}%
         segments      {\listparameter\c!numbersegments}%
     }%
   \relax
   \dostoptagged}

% TODO: pass extra tag name (contents, figures, bibliography ...)

\protected\def\strc_lists_place_current#list#criterium#reference#extras#order#levels% beware, not a user command
  {\dostarttaggedchained\t!list\empty\empty\??list
   \clf_processlist
        names     {#list}
        criterium {#criterium}
        reference {#reference}
        extras    {#extras}
        order     {#order}
        levels    {#levels}
   \relax
   \dostoptagged}

\protected\def\strc_lists_analyze#list#criterium#reference%
  {\clf_analyzelist
        names     {#list}
        criterium {#criterium}
        reference {#reference}
   \relax}

\permanent\def\firststructureelementinlist#list% expandable
  {\firstinset{#list}}

\permanent\def\structurelistsize
  {\clf_listsize}

%D Depending on what kind of list we have (e.g.\ a section related one) processors
%D can be defined.

% push pop test:
%
% \starttext
%   \placelist[chapter] [after={\placelist[section][criterium=local]}]
%   \chapter{One} \section{Alpha} \section{Beta}
%   \chapter{Two} \section{First} \section{Second}
% \stoptext

\installcorenamespace{structurelistprocessor} % the topmost list handler
\installcorenamespace{listextra}              % control of that handler

\installcommandhandler \??listextra {listextra} \??listextra

\definelistextra % example
  [\v!page]
  [\c!before={\showmessage\m!system{14}{\currentlist/\currentlistindex}\page}]

% normaldef is needed for the mkvi parser

% \permanent\protected\def\installstructurelistprocessor#tag#meaning%
%   {\expandafter\normaldef\csname\??structurelistprocessor#tag\endcsname{#meaning}}

\permanent\protected\def\installstructurelistprocessor#tag#meaning%
  {\defcsname\??structurelistprocessor#tag\endcsname{#meaning}}

\permanent\def\usestructurelistprocessor#tag%
  {\begincsname\??structurelistprocessor#tag\endcsname}

\mutable\lettonothing\currentlistentrydescription

% begin of of tagging horror

\aliased\let\dotaglistlocation\relax

\def\strc_lists_prerolled_list
  {\prerolltostring{%
     \strc_lists_placement_check
     \dostartignoretagging\empty
     \doifelsetext{\labeltext\currentlist}%
       {\labeltext\currentlist}%
       {\currentlist\space}%
     \ifconditional\c_lists_show_number
       \structurelistgenericnumber
       \space :
     \fi
     \clf_listbookmark{\currentlistindex}\empty\relax
    %\structurelistgenerictitle
     \ifconditional\c_lists_has_page\relax
       \space at %
       \doifelsetext{\labeltext\v!page}%
         {\labeltext\v!page}%
         {\v!page\space}%
       \structurelistpagenumber
     \fi
     \dostopignoretagging
  }}

\def\strc_lists_add_list_description
  {\ifexporting\orelse\iflocation
     \ifnum\a_strc_lists_reference=\attributeunsetvalue\else
       \edef\tempstring{%
         %\clf_listbookmark{\currentlistindex}\empty
         \strc_lists_prerolled_list
       }%
     % \writestatus{!!!!!}{\tempstring}%
       \dotagsetreferencedescription
         \a_strc_lists_reference
         \tempstring
     \fi
   \fi}

\lettonothing\dotagmarklist

% end of tagging horror

\def\strc_lists_entry_process_default
  {no list method}

\def\strc_lists_entry_process % assume things to be set up
  {\listextraparameter\c!before
   \dostarttagged\t!listitem\currentlist
   \dotaglistlocation
   \ifcsname\??structurelistprocessor\currentlist:\currentlistmethod\endcsname\lastnamedcs\orelse
   \ifcsname\??structurelistprocessor\currentlistmethod             \endcsname\lastnamedcs\orelse
   \ifcsname\??structurelistprocessor\currentlist                   \endcsname\lastnamedcs\else
                                                         \strc_lists_entry_process_default\fi
   \dotagmarklist % here, as we need to know the attributes (assumes no grouping)
   \dostoptagged
   \listextraparameter\c!after}

\permanent\protected\def\strclistsentryprocess#tag#method#index#extra% This one is called at the lua end!
  {\clf_pushlist#index\relax
  %\lettonothing\currentlistentrylocation
   \cdef\currentlist      {#tag}%
   \edef\currentlistmethod{#method}%
   \edef\currentlistindex {#index}%
   \edef\currentlistextra {#extra}%
   \strc_lists_entry_process
   \clf_poplist}

% lists that have a number/title are kind of generic and can share code

\installstructurelistprocessor\s!default
  {\strc_lists_entry_process_default}

\installstructurelistprocessor\s!simple
  {\let\currentlistentrynumber    \structurelistfirst
   \let\currentlistentrytitle     \structurelistsecond
   \let\currentlistentrypagenumber\structurelistpagenumber
   \strc_lists_apply_renderingsetup}

\installstructurelistprocessor\s!command
  {\clf_listuserdata{\currentlist}\currentlistindex{\s!command}}

\installstructurelistprocessor{section}
  {\let\currentlistentrynumber    \structurelistgenericnumber
   \let\currentlistentrytitle     \structurelistgenerictitle
   \let\currentlistentrypagenumber\structurelistpagenumber
   \strc_lists_apply_renderingsetup}

\installstructurelistprocessor{number+title}
  {\let\currentlistentrynumber    \structurelistgenericnumber
   \let\currentlistentrytitle     \structurelistgenerictitle
   \let\currentlistentrypagenumber\structurelistpagenumber
   \strc_lists_apply_renderingsetup}

% example of usage elsewhere:
%
% \installstructurelistprocessor{pubs:userdata}
%   {\clf_listuserdata{\currentlist}\currentlistindex{bibref}}

%D List symbols are used in interactive documents where no numbers are used but
%D nevertheless structure is present. Beware, the list symbol macro gets an argument
%D passed, i.e. when this argument is not picked up, the symbol becomes a kind of
%D prefix. It's not really a user command (and might even get protected).

\permanent\protected\def\listsymbol[#tag]#number%
  {\begingroup
   \cdef\currentlist{#tag}%
   \def\currentlistentrynumber{#number}% no edef else tag problems
   \currentlistsymbol
   \endgroup}

%D For historical reasons we're stuck to symbols, so in order to generalize, we have
%D to hook it into the symbol handle. One way to deal with this is to use a
%D different key and as it makes sense to use setups instead of def's we use a new
%D key \quote {renderingsetup} which is the name of a setup.

\lettonothing\m_strc_list_dimen % bad name

\def\strc_lists_assign_dimen#dimension#key#default%
  {\edef\m_strc_list_dimen{\listparameter#key}%
   #dimension\ifinset{\m_strc_list_dimen}{\v!fit,\v!broad}#default\else\m_strc_list_dimen\fi\relax}

\definesymbol[\v!list][\v!none   ][\strc_lists_symbol_none]
\definesymbol[\v!list][\v!one    ][\strc_lists_symbol_one]
\definesymbol[\v!list][\v!two    ][\strc_lists_symbol_two]
\definesymbol[\v!list][\v!three  ][\strc_lists_symbol_three]
\definesymbol[\v!list][\s!default][\strc_lists_symbol_default]
\definesymbol[\v!list][\s!unknown][\strc_lists_symbol_unknown]

\permanent\protected\def\currentlistsymbol
  {\edef\p_symbol{\listparameter\c!symbol}%
   \doifelseinsymbolset\v!list\p_symbol
     {\directsymbol\v!list\p_symbol}
     {\directsymbol\v!list\s!default}}

\protected\def\strc_lists_symbol_none
  {\strc_lists_assign_dimen\scratchwidth\c!width{1.5\emwidth}%
   \hpack to \scratchwidth{}}

\protected\def\strc_lists_symbol_one
  {\strut\symbol[bullet]}

\protected\def\strc_lists_symbol_two
  {\vrule\s!width\emwidth\s!height\exheight\s!depth\zeropoint\relax}

\protected\def\strc_lists_symbol_three
  {\begingroup
   \strc_lists_assign_dimen\scratchwidth \c!width {1.5\emwidth}%
   \strc_lists_assign_dimen\scratchheight\c!height\exheight
   \strc_lists_assign_dimen\scratchdepth \c!depth \zeropoint
   \vrule\s!width\scratchwidth\s!height\scratchheight\s!depth\scratchdepth
   \endgroup}

\protected\def\strc_lists_symbol_unknown
  {\listparameter\c!symbol}

\installcorenamespace{listsymbollabels}

\def\strc_lists_symbol_label_unknown
  {\leftlabeltext\currentlistlabel
   \listparameter\c!starter
   \currentlistentrynumber
   \listparameter\c!stopper
   \rightlabeltext\currentlistlabel}

\mutable\let\currentlistnumber\!!zerocount

\mutable\lettonothing\currentlistlabel

\protected\def\strc_lists_symbol_default
  {\dontleavehmode
   \strut
   \begingroup
   \edef\currentlistlabel{\listparameter\c!label}% can be used in label
   \ifcsname\??listsymbollabels\currentlistlabel\endcsname
      \lastnamedcs
   \else
     \strc_lists_symbol_label_unknown
   \fi
   \endgroup}

\letcsname\??listsymbollabels\s!unknown\endcsname\strc_lists_symbol_default

\defcsname\??listsymbollabels\endcsname % default (empty)
  {\listparameter\c!starter
   \currentlistentrynumber
   \listparameter\c!stopper}

\defcsname\??listsymbollabels\v!no\endcsname % also default
  {\listparameter\c!starter
   \currentlistentrynumber
   \listparameter\c!stopper}

\defcsname\??listsymbollabels\v!none\endcsname % real minimal (as suggested by WS)
  {\currentlistentrynumber}

\defcsname\??listsymbollabels\v!yes\endcsname % auto (use value stored in tuc file)
  {\edef\currentlistlabel{\clf_listlabel\currentlistindex{\currentlistlabel}}%
   \leftlabeltext\currentlistlabel
   \listparameter\c!starter
   \currentlistentrynumber
   \listparameter\c!stopper
   \rightlabeltext\currentlistlabel}

% a : nr - tit - pag
% b : nr - tit - fill - pag
% c : nr - tit - dots - pag
% d : inline
% e : interaction
% f : interaction
% g : interaction

\installcorenamespace{listalternative} % specific ways of rendering a list
\installcorenamespace{listrenderings}  % a namespace for setups (rather local)

\installcommandhandler \??listalternative {listalternative} \??listalternative

% Commands are bound to specific list instances as often these are quite special
% and don't apply to multiple. So, being strict saves us resets.

% \installcorenamespace{listfiller}
%
% \protected\def\installlistfiller#1#2%
%   {\protected\defcsname\??listfiller#1\endcsname{#2}}
%
% \protected\def\listfiller#1%
%   {\begincsname\??listfiller#1\endcsname}
%
% \protected\def\currentlistfiller
%   {\begingroup
%    \edef\p_filler{\listalternativeparameter\c!filler}%
%    \ifcsname\??listfiller\p_filler\endcsname
%      \lastnamedcs
%    \else
%      \p_filler
%    \fi
%    \endgroup}
%
% \installlistfiller\v!sym % original one
%   {\begingroup
%    \scratchdimen.5\emwidth
%    \hskip\scratchdimen
%    \gleaders
%      \hbox to \scratchdimen
%        {\hss
%         \uselistalternativestyleandcolor\c!symstyle\c!symcolor
%         \listalternativeparameter\c!symbol
%         \hss}%
%      \hfill
%    \hskip\scratchdimen
%    \endgroup}
%
% \installlistfiller\v!symbol % new one (make that default?)
%   {\begingroup
%    \scratchdimen.5\emwidth
%    \hskip\scratchdimen
%    \gleaders
%      \hbox spread .5\scratchdimen
%        {\hss
%         \uselistalternativestyleandcolor\c!symstyle\c!symcolor
%         \listalternativeparameter\c!symbol
%         \hss}%
%      \hfill
%    \hskip\scratchdimen
%    \endgroup}
%
% \installlistfiller\v!width
%   {\hfill}
%
% \installlistfiller\v!space
%   {\hskip.25\emwidth\relax}

\setuplistalternative
  [\c!command=\directlistparameter\c!command,
   \c!symbol=.]

\permanent\protected\def\currentlistfiller
  {\checkedfiller{\listalternativeparameter\c!filler}}

\definelistalternative
  [a]
  [\c!distance=0pt,
   \c!width=2em,
   \c!stretch=10em,
   \c!filler=\hskip.25em\relax,
   \c!renderingsetup=\??listrenderings:abc]

\definelistalternative
  [b]
  [\c!distance=5em,
   \c!width=2em,
   \c!stretch=10em,
   \c!filler=\hfill,
   \c!renderingsetup=\??listrenderings:abc]

\definelistalternative
  [c]
  [\c!distance=5em,
   \c!width=0pt,
   \c!stretch=10em,
   \c!filler=\hskip.5em\gleaders\hbox to .5\emwidth{\hss.\hss}\hfill\hskip.5em\relax,
   \c!renderingsetup=\??listrenderings:abc]

\definelistalternative
  [d]
  [\c!renderingsetup=\??listrenderings:d]

\definelistalternative
  [e]
  [\c!renderingsetup=\??listrenderings:e]

\definelistalternative
  [f]
  [\c!renderingsetup=\??listrenderings:f]

\definelistalternative
  [g]
  [\c!renderingsetup=\??listrenderings:g]

\definelistalternative
  [\v!command]
  [\c!renderingsetup=\??listrenderings:command]

\definelistalternative
  [\v!none]
  [\c!renderingsetup=\??listrenderings:none]

\definelistalternative
  [\v!vertical]
  [\c!before=\ifvmode\nointerlineskip\fi,
   \c!after=\ifvmode\nointerlineskip\fi\endgraf\allowbreak,
   \c!renderingsetup=\??listrenderings:generic]

\definelistalternative
  [\v!horizontal]
  [\c!before=\noindent,
   \c!after=,
   \c!renderingsetup=\??listrenderings:generic]

% \setuplist
%   [section]
%   [alternative=MyListItem,
%    after=\blank,
%    before=\blank]
%
% \definelistplacement[MyListItem][command]#1#2#3{(#1) (#2) (#3)}
% \definelistplacement[MyListItem][command]{\whatever}
%
% this is a compatibility command, best use the regular defined with command=
% either set in the alternative or in the list

\installcorenamespace{listelementcommand} % the old plugin model

\permanent\tolerant\protected\def\definelistplacement[#tag]#spacer[#method]%
  {\edef\p_method{#method}%
   \ifempty\p_method
     \let\p_method\v!command
   \fi
   \expanded{\definelistalternative[#tag][\p_method]}[\c!command=\strc_lists_placement_command]%
   \doifelsenextbgroup
     {\strc_lists_define_placement_yes{#tag}}
     {\strc_lists_define_placement_nop{#tag}}}

% indirect definition: <three ignore arguments>: {\bla}

\def\strc_lists_define_placement_yes#tag%
  {\protected\defcsname\??listelementcommand#tag\endcsname##1##2##3}

% direct definition: <three arguments>{\bla}

\def\strc_lists_define_placement_nop#tag%
  {\protected\defcsname\??listelementcommand#tag\endcsname}

\def\strc_lists_placement_command
  {\csname\??listelementcommand\currentlistalternative\endcsname}

%D The rendering macros.

\newbox  \b_strc_lists_number
\newbox  \b_strc_lists_text
\newbox  \b_strc_lists_page

\newtoks \t_lists_every_renderingsetup
\newtoks \t_lists_every_renderingtext
\newtoks \t_lists_every_renderingsynchronize
\newtoks \t_lists_every_renderingcleanup

\newconditional\c_lists_has_number
\newconditional\c_lists_has_page
\newconditional\c_lists_show_number
\newconditional\c_lists_show_page

\mutable\lettonothing\currentlistentrylocation   % watch the 'entry' in the name
\mutable\lettonothing\currentlistentrynumber     % watch the 'entry' in the name
\mutable\lettonothing\currentlistentrytitle      % watch the 'entry' in the name
\mutable\lettonothing\currentlistentrypagenumber % watch the 'entry' in the name

\appendtoks
    \dontcomplain
  % \letinteractionparameter\c!width\zeropoint % a weird one
\to \t_lists_every_renderingsetup

\appendtoks
    % better is to use a special list entry but we keep this for compatibility
    \enforced\let\\\space
    % so expanding this token register has to come *after* the font switch
    \dontconvertfont % (**) this has to become an option (see publ)
\to \t_lists_every_renderingtext

% because these tests happen often and because we're dealing with
% rather complex composed data we have special conditionals; keep
% in mind that testing for empty fails due to tagging being applied

\def\strc_lists_placement_check
  {\c_lists_show_page\conditionalfalse % necessary?
   \processcommacommand[\listparameter\c!pagenumber]\strc_lists_process_pagenumber
   \ifconditional\c_lists_has_page \else
     \doifelsestructurelisthaspage
       {\c_lists_has_page\conditionaltrue}%
       {\c_lists_has_page\conditionalfalse}%
   \fi
   % always forces number placement (in bib we use a forced number)
   \edef\p_headnumber{\listparameter\c!headnumber}%
   \ifx\p_headnumber\v!always
     \c_lists_has_number\conditionaltrue
     \c_lists_show_number\conditionaltrue
   \else
     \doifelsestructurelisthasnumber
       {\c_lists_has_number\conditionaltrue}%
       {\c_lists_has_number\conditionalfalse}%
     \ifx\p_headnumber\v!yes
       \c_lists_show_number\conditionaltrue
     \else
       \c_lists_show_number\conditionalfalse
     \fi
   \fi}

\appendtoks
    % because we want to avoid redundant lua calls we expand the
    % location beforehand
    \ifempty\currentlistentrylocation
        \enforced\edef\currentlistentrylocation{\structurelistlocation}% needs attention
    \fi
    \strc_lists_placement_check
    \strc_lists_interaction_check
\to \t_lists_every_renderingsetup

\appendtoks
    \strc_references_flush_destination_nodes
\to \t_lists_every_renderingsynchronize

\appendtoks
   % as we don't want any interference we clear some variables
   % afterwards
   \lettonothing\currentlistentrylocation
   \lettonothing\currentlistentrynumber
   \lettonothing\currentlistentrytitle
   \lettonothing\currentlistentrypagenumber
   \c_lists_has_page\conditionalfalse
   \c_lists_has_number\conditionalfalse
   \c_lists_show_page\conditionalfalse
   \c_lists_show_realpage\conditionalfalse
   \c_lists_show_number\conditionalfalse
   % these can be reset in publ ini but we need them for e.g. lists in menus
   \enforced\let\structurelistexternal\strc_lists_structurelistexternal
   \enforced\let\structurelistlocation\strc_lists_structurelistlocation
\to \t_lists_every_renderingcleanup

\lettonothing\m_strc_list_alternative % combined

\protected\def\strc_lists_apply_renderingsetup
  {\expand\t_lists_every_renderingsetup
   % now we group
   \begingroup
   \ifempty\m_strc_list_alternative
     \edef\currentlistalternative{\listparameter\c!alternative}%
   \else
     \let\currentlistalternative\m_strc_list_alternative
   \fi
   \directsetup{\listalternativeparameter\c!renderingsetup}\relax
   \endgroup
   % till here, where we reset locals
   \expand\t_lists_every_renderingcleanup}

% todo: provide packager via attributes

\doinstallinjector\s!list

\installcorenamespace{listalternativemethods} % the general wrapper of a rendering

\startsetups[\??listrenderings:none]
    % nothing, nb we use the [] syntax here because we end with a \cs
\stopsetups

\permanent\protected\def\currentlistentrytitlesynchronize
  {\expand\t_lists_every_renderingsynchronize}

\permanent\protected\def\currentlistentrytitlerendered
  {\currentlistentrytitlesynchronize\currentlistentrytitle}

\startsetups[\??listrenderings:command]
    \edef\p_command{\listalternativeparameter\c!command}%
    \ifempty\p_command
        [\currentlist: \currentlistentrynumber\space -- \currentlistentrytitle\space -- \currentlistentrypagenumber]%
    \else
        \p_command
          \currentlistentrynumber
          \currentlistentrytitlerendered % {\currentlistentrytitlesynchronize\currentlistentrytitle}
          \currentlistentrypagenumber
    \fi
\stopsetups

% \startsetups[\??listrenderings:\v!vertical]
%     \directsetup{\??listrenderings:generic}
% \stopsetups

% \startsetups[\??listrenderings:\v!horizontal]
%     \directsetup{\??listrenderings:generic}
% \stopsetups

\startsetups[\??listrenderings:generic]
    \typo_injectors_check_list
    \listparameter\c!before % can be \hskip
    \edef\p_command{\listalternativeparameter\c!command}
    \ifempty\p_command
        \listalternativeparameter\c!before
        \vbox {
            \forgetall
            \noindent % otherwise annotations are mirrored up
            \typo_injectors_mark_list
            \hbox \strc_lists_get_reference_attribute\v!all {
                \ifconditional\c_lists_show_number
                  % \ifconditional\c_lists_has_page
                        \hbox \strc_lists_get_reference_attribute\v!number {
                            \strc_lists_set_style_color\c!numberstyle\c!numbercolor\v!number
                            \listparameter\c!numbercommand\currentlistsymbol
                        }
                  % \fi
                \fi
                \hbox \strc_lists_get_reference_attribute\v!text {
                    \strc_lists_set_style_color\c!textstyle\c!textcolor\v!text
                    \expand\t_lists_every_renderingtext
                    \expand\t_lists_every_renderingsynchronize
                    \listparameter\c!textcommand\currentlistentrytitle
                }
                \ifconditional\c_lists_show_page
                    \ifconditional\c_lists_has_page
                        \hbox \strc_lists_get_reference_attribute\v!pagenumber {
                            \strc_lists_set_style_color\c!pagestyle\c!pagecolor\v!pagenumber
                            \listparameter\c!pagecommand\currentlistentrypagenumber
                        }
                    \fi
                \fi
            }
        }
        \listalternativeparameter\c!after
   \else
        \noindent % otherwise annotations are mirrored up
        \typo_injectors_mark_list
        \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
            \p_command\currentlistentrynumber\currentlistentrytitle\currentlistentrypagenumber
        }
   \fi
   \listparameter\c!after
\stopsetups

% to be documented: align, hang

\startsetups[\??listrenderings:abc]
    \endgraf % are we grouped?
    \typo_injectors_check_list
  % \advanceby % yes or no ... \rightskip is also honored
    \leftskip{\listparameter\c!margin}\relax % after \endgraf !
    \listparameter\c!before
    \endgraf
    \edef\p_width{\listparameter\c!width}
    \scratchdistance{\listparameter\c!distance}%
    \ifx\p_width\v!fit
        \scratchwidth\zeropoint
    \orelse\ifconditional\c_lists_has_number
        \scratchwidth{\p_width}%
    \else
        \edef\p_aligntitle{\listparameter\c!aligntitle}
        \ifx\p_aligntitle\v!yes
            \scratchwidth\zeropoint
            \scratchdistance\zeropoint
        \else
            \scratchwidth{\p_width}%
        \fi
    \fi
    \noindent % otherwise annotations are mirrored up
    \typo_injectors_mark_list
    \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
        \setlocalhsize
        \hsize\localhsize
        \hbox to \hsize {
            \forgetall
            \strc_lists_set_style_color\c!style\c!color\v!all
            \scratchhsize\hsize
            \ifconditional\c_lists_has_number
                \ifconditional\c_lists_show_number
                  \setbox\b_strc_lists_number
                    \simplealignedboxplus
                        \scratchwidth
                        {\listparameter\c!numberalign}
                        {\strc_lists_get_reference_attribute\v!number}
                        {
                            \strc_lists_set_style_color\c!numberstyle\c!numbercolor\v!number
                            \listparameter\c!numbercommand\currentlistsymbol
                        }
                \else
                    \setbox\b_strc_lists_number\emptyhbox
                \fi
            \else
                \scratchwidth\zeropoint
                \scratchdistance\zeropoint
                \setbox\b_strc_lists_number\emptyhbox
            \fi
            \ifconditional\c_lists_has_page
                \ifconditional\c_lists_show_page
                    \setbox\b_strc_lists_page\hpack {
                        \scratchdimen{\listalternativeparameter\c!width}%
                        \hbox \strc_lists_get_reference_attribute\v!pagenumber \ifdim\scratchdimen>\zeropoint to \scratchdimen\fi {
                            \hfill
                            \strc_lists_set_style_color\c!pagestyle\c!pagecolor\v!pagenumber
                            \strut
                            \listparameter\c!pagecommand\currentlistentrypagenumber
                        }
                    }
                \else
                    \setbox\b_strc_lists_page\emptyhbox
                \fi
            \else
                \setbox\b_strc_lists_page\emptyhbox
            \fi
            \vbox {
                \hsize\scratchhsize
                \usealignparameter\listparameter
                \ifdim\scratchwidth<\hsize
                    % we have leftskip so we'd better just skip back instead of messing
                    % with hang*
                    \edef\p_hang{\listparameter\c!hang}
                    \hangindent{\wd\b_strc_lists_number+\scratchdistance}%
                    \hangafter\ifx\p_hang\v!no\zerocount\else\plusone\fi
                    \scratchdimen{\listalternativeparameter\c!distance}%
                    \ifzeropt\wd\b_strc_lists_page\orelse\ifdim\scratchdimen>\zeropoint\relax
                        \rightskip\scratchdimen\s!plus{\listalternativeparameter\c!stretch}\relax
                        \parfillskip-\rightskip
                    \fi
                \else
                    \scratchdistance\zeropoint
                \fi
                \parindent\zeropoint
                \dontleavehmode % this nils hang: i need to figure out why
                % % topaligned
                %
                % \scratchdimen\wd\b_strc_lists_number
                % \setbox\b_strc_lists_number\hbox to \hsize{\box\b_strc_lists_number\hss\box\b_strc_lists_page}%
                % \wd\b_strc_lists_number\scratchdimen
                %
                \box\b_strc_lists_number
                \hskip\scratchdistance\relax
                \begingroup
                \strc_lists_set_reference_attribute\v!text
                \strc_lists_set_style_color\c!textstyle\c!textcolor\v!text
                \expand\t_lists_every_renderingtext
                \expand\t_lists_every_renderingsynchronize
                \setstrut % needs checking, new here
                \begstrut
                \strc_lists_limitated_text\currentlistentrytitle
                \endstrut
                \endgroup
                \ifzeropt\wd\b_strc_lists_page\else
                    \nobreak
                    \currentlistfiller
                    \box\b_strc_lists_page
                \fi
            }
            \hss
        }
    }% new
    \endgraf % new, else problems with nointerlinespace and prevdepth
    \ifvmode\nointerlineskip\fi % anders verkeerde spatiering bij multi-line
    \endgraf
    \allowbreak
    \listparameter\c!after
\stopsetups

% % example from the context list
%
% \setuphead [part]    [page=right,placehead=yes]
% \setuplist [chapter] [alternative=d,before=\blank,after=\blank]
% \setuplist [part]    [before=\blank,after=\blank]
%
% \starttext
%   \startnarrower[2*right] \placecontent \stopnarrower
%   \blank[4*big]
%   \startsetups chapter
%     \blank \startnarrower[3*middle] \placecontent[criterium=local] \stopnarrower
%   \stopsetups
%   \placelist[part][criterium=text,after=\setups{chapter}]
%
%   \part{First part}       \chapter{Chapter one}  \chapter{Chapter two}
%   \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
%   \part{Second part}      \chapter{Chapter one}  \chapter{Chapter two}
%   \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
%   \part{Third part}       \chapter{Chapter one}  \chapter{Chapter two}
%   \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
% \stoptext

\startsetups[\??listrenderings:d]
    \ifvmode
        \advanceby\leftskip{\listparameter\c!margin}%
    \fi
    \begingroup
    \ifvmode
        \noindent
    \fi
    \begingroup
    \strc_lists_set_reference_attribute\v!all
    \strc_lists_set_style_color\c!style\c!color\v!all
    \strc_lists_get_destination_attribute
    \begingroup
    \ifconditional\c_lists_show_number
        \donetrue
        \ifconditional\c_lists_has_number \else
            \edef\p_symbol{\listparameter\c!symbol}
            \ifempty\p_symbol
                \donefalse
            \fi
        \fi
        \ifdone
            \begingroup
            \strc_lists_set_reference_attribute\v!number
            \strc_lists_set_style_color\c!numberstyle\c!numbercolor\v!number
            \listparameter\c!left
            \listparameter\c!numbercommand\currentlistsymbol
            \listparameter\c!right
            \endgroup
            \kern.5\emwidth\relax
            \nobreak
        \fi
    \fi
    \endgroup
    \begingroup
    \strc_lists_set_reference_attribute\v!text
    \strc_lists_set_style_color\c!textstyle\c!textcolor\v!text
    \expand\t_lists_every_renderingtext
    \expand\t_lists_every_renderingsynchronize
    \setstrut % needs checking, new here
    \begstrut
    \strc_lists_limitated_text\currentlistentrytitle
    \endstrut
    \endgroup
    \begingroup
    \ifconditional\c_lists_has_page
        \ifconditional\c_lists_show_page
            \nobreak
            \hskip.75\emwidth\relax
            \nobreak
            \strc_lists_set_reference_attribute\v!pagenumber
            \strc_lists_set_style_color\c!pagestyle\c!pagecolor\v!pagenumber
            \strut
            \listparameter\c!pagecommand\currentlistentrypagenumber
        \fi
    \fi
    \endgroup
    \scratchdistance{\listparameter\c!distance}%
    \ifdim\scratchdistance<\emwidth
        \hskip\emwidth\s!plus\emwidth\s!minus.25\emwidth\relax
    \else
        \hskip\scratchdistance\s!plus.5\scratchdistance\s!minus.25\scratchdistance\relax
    \fi
    \endgroup
    \endgroup
\stopsetups

\lettonothing\m_strc_lists_color % ugly hack

\startsetups[\??listrenderings:e]
    \typo_injectors_check_list
    \noindent % otherwise annotations are mirrored up
    \typo_injectors_mark_list
    \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
        \letlistparameter  \c!depth\zeropoint
        % color here is messy
        \edef\m_strc_lists_color{\listparameter\c!color}% otherwise we get no color when we have no interaction
        \resetlistparameter\c!color % pushcolor
        \inheritedlistframed {
            \letlistparameter\c!color\m_strc_lists_color % popcolor
            \letinteractionparameter\c!strut\v!no % still needed?
            \strc_lists_set_style_color\c!style\c!color\v!all
            \expand\t_lists_every_renderingtext
            \expand\t_lists_every_renderingsynchronize
            \setstrut
            \begstrut
            \strc_lists_limitated_text\currentlistentrytitle
            \endstrut
        }
    }
    \par
    \listparameter\c!inbetween
\stopsetups

\startsetups[\??listrenderings:f]
    \typo_injectors_check_list
    \noindent % otherwise annotations are mirrored up
    \typo_injectors_mark_list
    \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
        \dosetraggedhbox{\listparameter\c!align}%
        \raggedbox {
            \strc_lists_set_style_color\c!style\c!color\v!all
            \expand\t_lists_every_renderingtext
            \expand\t_lists_every_renderingsynchronize
            \setstrut
            \begstrut
            \strc_lists_limitated_text\currentlistentrytitle
            \endstrut
        }
    }
    \par
    \listparameter\c!inbetween
\stopsetups

\startsetups[\??listrenderings:g]
    \typo_injectors_check_list
    \noindent % otherwise annotations are mirrored up
    \typo_injectors_mark_list
    \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
        \midaligned {
            \strc_lists_set_style_color\c!style\c!color\v!all
            \expand\t_lists_every_renderingtext
            \expand\t_lists_every_renderingsynchronize
            \setstrut
            \begstrut
            \strc_lists_limitated_text\currentlistentrytitle
            \endstrut
        }
    }
    \par
    \listparameter\c!inbetween
\stopsetups

%D This is a new one, similar to vertical and horizontal but better suited when
%D no command is set (WS):

\definelistalternative
  [\v!interactive]
  [\c!renderingsetup=\??listrenderings:interactive,
   \c!before=\endgraf, % new per 2014-11-08
   \c!after=\endgraf]  % new per 2014-11-08

\startsetups[\??listrenderings:interactive]
    \edef\p_command{\listalternativeparameter\c!command}%
    \typo_injectors_check_list
    \listparameter\c!before
    \noindent % otherwise annotations are mirrored up
    \typo_injectors_mark_list
    \hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute {
        \ifempty\p_command
            [
                \currentlist:\space
                \currentlistentrynumber
                \space\emdash\space
                \currentlistentrytitle
                \space\emdash\space
                \currentlistentrypagenumber
            ]
        \else
            \p_command\currentlistentrynumber\currentlistentrytitle\currentlistentrypagenumber
        \fi
   }
   \listparameter\c!after
\stopsetups

%D One special for publications (as Alan loves to hangindent). No fonts and such
%D (for now). No interaction either as that is dealt with elsewhere.
%D
%D \currentlistsymbol
%D \currentlistentrynumber
%D \currentlistentrytitle
%D \currentlistentrypagenumber % not really used

\definelistalternative
  [\v!paragraph]
  [\c!filler=\v!space,
   \c!renderingsetup=\??listrenderings:\v!paragraph]

\startsetups[\??listrenderings:\v!paragraph]
    \endgraf % are we grouped?
    \typo_injectors_check_list % ?
    \listparameter\c!before
    \endgraf
    \begingroup
    \forgetall
    \noindent
    \parindent\zeropoint
    \edef\p_width{\listparameter\c!width}%
    \edef\p_distance{\listparameter\c!distance}% we are nice for bib users
    \edef\p_margin{\listparameter\c!margin}% we are nice for bib users
    \scratchdistance\ifx\p_distance\v!none\zeropoint\else{\p_distance}\fi
    \scratchoffset  \ifx\p_margin  \v!none\zeropoint\else{\p_margin  }\fi
% \scratchdistance\ifcstok{\listparameter\c!distance}\v!none\zeropoint\else{\lastnamedcs}\fi
% \scratchoffset  \ifcstok{\listparameter\c!margin  }\v!none\zeropoint\else{\lastnamedcs}\fi
    \ifx\p_width\v!fit
        \scratchwidth\zeropoint
        \leftskip\scratchoffset
    \else
        \scratchwidth{\p_width}%
        \leftskip\ifzeropt\scratchoffset{\scratchwidth+\scratchdistance}\else\scratchoffset\fi\relax
    \fi
    \usealignparameter\listparameter
    \hskip-\leftskip
    \ifconditional\c_lists_has_number
        \ifconditional\c_lists_show_number
            \setbox\scratchbox
                \simplealignedbox\scratchwidth{\listparameter\c!numberalign}
                \bgroup
                    \useliststyleandcolor\c!numberstyle\c!numbercolor
                    \currentlistsymbol
                \egroup
            \ifdim\wd\scratchbox>\zeropoint
                \box\scratchbox
                \hskip\scratchdistance\relax
            \fi
        \fi
    \fi
    \begingroup
        \useliststyleandcolor\c!textstyle\c!textcolor
        \setstrut
        \begstrut
        \currentlistentrytitle
        \endstrut
    \endgroup
    \ifconditional\c_lists_has_page
        \ifconditional\c_lists_show_page
            \nobreak
            \currentlistfiller
            \begingroup
                \useliststyleandcolor\c!pagestyle\c!pagecolor
                \currentlistentrypagenumber
            \endgroup
        \fi
    \fi
    \endgraf
    \endgroup
    \allowbreak
    \listparameter\c!after
\stopsetups

%D List elements are packaged in such a way that we can click on them in an
%D interactive document. Here are a few helpers.

\newconstant\a_strc_lists_reference
\newconstant\a_strc_lists_destination

\installcorenamespace{listinteractions}

\letcsname\??listinteractions\v!number       \endcsname\v!number
\letcsname\??listinteractions\v!sectionnumber\endcsname\v!number
\letcsname\??listinteractions\v!text         \endcsname\v!text
\letcsname\??listinteractions\v!title        \endcsname\v!text
\letcsname\??listinteractions\v!page         \endcsname\v!pagenumber
\letcsname\??listinteractions\v!pagenumber   \endcsname\v!pagenumber
\letcsname\??listinteractions\v!all          \endcsname\v!all
\letcsname\??listinteractions\v!yes          \endcsname\v!all

\permanent\def\listboxproperties       {\strc_lists_get_reference_attribute}
\permanent\def\listrenderingsetup      {\expand\t_lists_every_renderingtext}
\permanent\def\listrenderingsynchronize{\expand\t_lists_every_renderingsynchronize}

\protected\def\strc_lists_interaction_check
  {\iflocation
     \strc_lists_interaction_check_yes
   \else
     \strc_lists_interaction_check_nop
   \fi}

\lettonothing\p_interaction_backward
\lettonothing\p_interaction_forward

\def\strc_lists_interaction_check_yes_yes
  {\edef\p_interaction_forward {\listparameter\c!interaction}%
   \edef\p_interaction_backward{\namedheadparameter\currentlist\c!interaction}% \namedheadparameter !
   \ifcsname\??listinteractions\p_interaction_forward\endcsname
    %\expandafter\let\expandafter\p_interaction_forward\csname\??listinteractions\p_interaction_forward\endcsname
     \expandafter\let\expandafter\p_interaction_forward\lastnamedcs
     \ifempty{\structurelistexternal}% luacall
       \strc_references_get_simple_reference{internal(\currentlistentrylocation)}%
     \else
     % \writestatus{FAR OUT LIST}{\structurelistexternal::page(\number\structurelistrealpagenumber)}%
       \strc_references_get_simple_reference{\structurelistexternal::page(\number\structurelistrealpagenumber)}%
       \let\p_interaction_backward\empty
     \fi
     \a_strc_lists_reference\currentreferenceattribute
   \else
     \a_strc_lists_reference\attributeunsetvalue
   \fi
   \ifnum\a_strc_lists_reference=\attributeunsetvalue
     \let\strc_lists_get_reference_attribute\gobbleoneargument
     \let\strc_lists_set_reference_attribute\gobbleoneargument
     \let\strc_lists_set_style_color        \strc_lists_set_style_color_normal
   \else
     \let\strc_lists_get_reference_attribute\strc_lists_get_reference_attribute_indeed
     \let\strc_lists_set_reference_attribute\strc_lists_set_reference_attribute_indeed
     \let\strc_lists_set_style_color        \strc_lists_set_style_color_special
   \fi
   \ifx\p_interaction_backward\v!list
     \strc_references_set_simple_reference{*\currentlistentrylocation}%
     \a_strc_lists_destination\currentdestinationattribute
   \else
     \a_strc_lists_destination\attributeunsetvalue
   \fi
   \ifnum\a_strc_lists_destination=\attributeunsetvalue
     \lettonothing\strc_lists_get_destination_attribute
     \lettonothing\strc_lists_set_destination_attribute
   \else
     \let\strc_lists_get_destination_attribute\strc_lists_get_destination_attribute_indeed
     \let\strc_lists_set_destination_attribute\strc_lists_set_destination_attribute_indeed
   \fi}

\def\strc_lists_interaction_check_yes_nop
  {\a_strc_lists_reference  \attributeunsetvalue
   \a_strc_lists_destination\attributeunsetvalue
   \let\strc_lists_get_reference_attribute\gobbleoneargument
   \let\strc_lists_set_reference_attribute\gobbleoneargument
   \lettonothing\strc_lists_get_destination_attribute
   \lettonothing\strc_lists_set_destination_attribute
   \let\strc_lists_set_style_color\strc_lists_set_style_color_normal}

\def\strc_lists_interaction_check_yes
  {\ifempty\currentlistentrylocation
     \strc_lists_interaction_check_yes_nop
   \orelse\ifnum\currentlistentrylocation=\zerocount
     \strc_lists_interaction_check_yes_nop
   \else
     \strc_lists_interaction_check_yes_yes
   \fi}

\def\strc_lists_interaction_check_nop
  {\let\strc_lists_get_reference_attribute  \gobbleoneargument
   \let\strc_lists_set_reference_attribute  \gobbleoneargument
   \lettonothing\strc_lists_get_destination_attribute
   \lettonothing\strc_lists_set_destination_attribute
   \let\strc_lists_set_style_color          \strc_lists_set_style_color_normal}

\strc_lists_interaction_check_nop

\def\strc_lists_get_reference_attribute_indeed#element%
  {\ifx#element\p_interaction_forward
     attr \referenceattribute\a_strc_lists_reference
   \fi}

\def\strc_lists_set_reference_attribute_indeed#element%
  {\ifx#element\p_interaction_forward
     \c_attr_reference\a_strc_lists_reference
   \fi}

\def\strc_lists_get_destination_attribute_indeed
  {attr \destinationattribute\number\a_strc_lists_destination}

\def\strc_lists_set_destination_attribute_indeed
  {\c_attr_destination\a_strc_lists_destination}

\protected\def\strc_lists_set_style_color_normal#style#color#element%
  {\useliststyleandcolor#style#color}

\protected\def\strc_lists_set_style_color_special#style#color#element%
  {\useliststyleandcolor#style#color%
   \ifempty\currentcolorparameter
     \ifx#element\p_interaction_forward
       \setlocationcolor
     \fi
 % \else
 %   \resetinteractioncolor
   \fi}

\let\strc_lists_set_style_color\strc_lists_set_style_color_normal

%D A helper:

\protected\def\strc_lists_limitated_text#text%
  {\edef\p_maxwidth{\listparameter\c!maxwidth}%
   \ifempty\p_maxwidth
     \listparameter\c!textcommand{#text}%
   \else
     \listparameter\c!textcommand{\limitatetext{#text}\p_maxwidth{\splitsymbol{\listparameter\c!limittext}}}%
   \fi}

% public helpers

\permanent\protected\def\startcurrentlistentrywrapper
  {\hbox \strc_lists_get_reference_attribute\v!all \strc_lists_get_destination_attribute\bgroup}

\aliased\let\stopcurrentlistentrywrapper\egroup

\permanent\def\currentlistentryreferenceattribute  {\strc_lists_get_reference_attribute}   % this definition can change
\permanent\def\currentlistentrydestinationattribute{\strc_lists_get_destination_attribute} % this definition can change
\permanent\def\currentlistentrylimitedtext         {\strc_lists_limitated_text}            % this definition can change

% todo:

\permanent\def\utilitylistlength{\listlength} % also in strc-reg (downward compatible name)

\mutable\let\listlength\!!zerocount           % also in strc-reg

\permanent\tolerant\protected\def\determinelistcharacteristics[#list]#spacer[#S#settings]%
  {\begingroup
   \cdef\currentlist{\firststructureelementinlist{#list}}%
   \ifempty\currentlist
     \endgroup
     \let\listlength\!!zerocount
   \else
     \setupcurrentlist[#settings]%
     \strc_lists_analyze{#list}{\listparameter\c!criterium}{\listparameter\c!reference}%
     \expanded{\endgroup\noexpand\edef\noexpand\listlength{\structurelistsize}}%
   \fi
   \strc_lists_set_mode}

\protect \endinput
