%D \module
%D   [       file=setups-basics, % x-set-11,
%D        version=2016.04.05, % 2004.10.31,
%D         remark=setupx.tex: 1998.07.20 and later,
%D          title=\CONTEXT\ Setup Definitions,
%D       subtitle=Macro Definitions,
%D         author={Hans Hagen & Wolfgang Schuster},
%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.

%D We can make this module a bit cleaner using more recent features or we go \LUA\
%D completely but as this style evolved over 15 years it's a waste of time.
%D
%D As we also have a help server we can make a common framework for this \unknown\
%D but even then, this file is also a test for the the \XML\ processor.
%D
%D Traditionally we used the sorter to generate the lists while nowadays we can
%D as well use the \XML\ mechanisms directly. We cannot change too much because
%D manuals depend on it.
%D
%D Currently we load the \XML\ file and when not in the english interface we just
%D remap the relevant words to their translation.

%D Todo: use lua instead of synonyms

\unprotect

\defineregister
  [texmacro]

\definesorting
  [texcommand]

\setupsorting
  [texcommand]
  [\c!command=\showsetupinlist,
   \c!criterium=\setupparameter\c!criterium]

\pushmacro\setuptext

\defineframedtext
  [setuptext]
  [\c!width=\hsize,
   \c!height=\v!fit,
   \c!align=\v!right,
   \c!offset=0.75\emwidth] % \exheight

\popmacro\setuptext

\installcorenamespace{interfacesetup}

\installsetuponlycommandhandler \??interfacesetup {setup} % \??interfacesetup

\setupsetup
  [\c!before=,
   \c!after=,
   \c!command=\setup,
   \c!criterium=\v!used]

%D General:

\unexpanded\def\setupnumfont {}
\unexpanded\def\setuptxtfont {}
\unexpanded\def\setupintfont {\WORD}
\unexpanded\def\setupvarfont {\sl}
\unexpanded\def\setupoptfont {\sl}
\unexpanded\def\setupalwcolor{}
\unexpanded\def\setupoptcolor{darkgray}

% \unexpanded\def\setupvarword#1{{\sl\detokenize{#1}}}
\unexpanded\def\setupvarword#1{\detokenize{#1}}
\unexpanded\def\setupintword#1{\WORD{\detokenize{#1}}}
\unexpanded\def\setuptxtword#1{\detokenize{#1}}

\unexpanded\def\cmd_internal_value#1%
  {\dontleavehmode
   \begingroup
   \setupintfont{#1}%
   \endgroup}

\unexpanded\def\cmd_text_value#1%
  {\dontleavehmode
   \begingroup
   \setupvarfont{#1}%
   \endgroup}

\unexpanded\def\cmd_command_value#1%
  {\begingroup
   \setupvarfont{#1}%
   \endgroup}

%D Loading:

\let\currentSETUPfullname\s!unknown

\startxmlsetups xml:setups:assemblename
    \doifelse {\xmlatt{#1}{type}} {environment} {
        \doifsomethingelse {\xmlatt{#1}{begin}} {
            \edef\currentSETUPprefix{\xmllastatt}%
        } {
            \let\currentSETUPprefix\e!start
        }
    } {
        \let\currentSETUPprefix\empty
    }
    \edef\currentSETUPname{\xmlatt{#1}{name}}
    \let\currentSETUPgenerated\empty
    \doifelsenothing {\xmlatt{#1}{variant}} {
        \let\currentSETUPvariant\empty
    } {
        \def\currentSETUPvariant{:\xmllastatt}
    }
    \edef\currentSETUPfullname {
        \currentSETUPprefix
        \currentSETUPname
        \currentSETUPvariant
        \currentSETUPgenerated
    }
\stopxmlsetups

\startxmlsetups xml:setups:assemblename:instance
    \doifelse {\xmlatt{#1}{type}} {environment} {
        \doifsomethingelse {\xmlatt{#1}{begin}} {
            \edef\currentSETUPprefix{\xmllastatt}%
        } {
            \let\currentSETUPprefix\e!start
        }
    } {
        \let\currentSETUPprefix\empty
    }
%     \edef\currentSETUPname{\xmlatt{#1}{name}}
    \let\currentSETUPgenerated\empty
    \doifelsenothing {\xmlatt{#1}{variant}} {
        \let\currentSETUPvariant\empty
    } {
        \def\currentSETUPvariant{:\xmllastatt}
    }
    \edef\currentSETUPfullname {
        \currentSETUPprefix
        \currentSETUPname
        \currentSETUPvariant
        \currentSETUPgenerated
    }
\stopxmlsetups

% \startxmlsetups xml:setups:register
%     \doifelse {\xmlatt{#1}{variant}} {instance} {
%         \def\docommand##1%
%           {\def\currentSETUPname{##1}%
%            \xmlsetup{#1}{xml:setups:assemblename:instance}
%            \expanded{\texcommand[stp:x:\currentSETUPfullname]{{#1}{##1}}}}%
%         \processcommacommand[\clf_getinstances{#1}]\docommand
%     } {
%         \xmlsetup{#1}{xml:setups:assemblename}
%         % not really needed if we just use setups
%         \expanded{\texcommand[stp:x:\currentSETUPfullname]{{#1}{}}}
%     }
% \stopxmlsetups

\startxmlsetups xml:setups:register
    \doif {\xmlatt{#1}{variant}} {instance} {
        \def\docommand##1%
          {\xmlsetup{#1}{xml:setups:assemblename:instance}
           \expanded{\texcommand[stp:x:\currentSETUPfullname:##1]{{#1}{##1}}}}%
        \processcommacommand[\clf_getinstances{#1}]\docommand
    }
    \xmlsetup{#1}{xml:setups:assemblename}
    % not really needed if we just use setups
    \expanded{\texcommand[stp:x:\currentSETUPfullname]{{#1}{}}}
\stopxmlsetups

\startluacode

    local find, gsub = string.find, string.gsub

    local xmlcollected   = xml.collected
    local xmlcount       = xml.count
    local xmlfirst       = xml.first

    local lxmlgetid      = lxml.getid
    local lxmlflush      = lxml.flush

    local context        = context

    local setupvarword   = context.formatted.setupvarword
    local setupintword   = context.formatted.setupintword
    local setuptxtword   = context.formatted.setuptxtword

    local getsetupstring = interfaces.getsetupstring

    -- normally a lookup is fast enough but here we can have many setups
    -- spread over many files so we do a little speedup here

    local setups       = moduledata.setups or { }
    moduledata.setups  = setups
    local definitions  = { }
    setups.definitions = definitions

    function xml.functions.setups_define(id)
        local x = lxmlgetid(id)
        for c in xmlcollected(x,"cd:interface/cd:define") do
            definitions[c.at.name] = c
        end
        for c in xmlcollected(x,"cd:interface/cd:interface") do
            c.at.file = c.__f__
            c.at["xmlns:cd"] = nil
         -- c.dt[#c.dt+1] = "    "
        end

        local interface = interfaces.currentinterface or "en"

        if interface ~= "en" then

            local constants  = interfaces.complete.constants
            local variables  = interfaces.complete.variables
            local commands   = interfaces.complete.commands
            local elements   = interfaces.complete.elements

            local function replace(pattern,attribute,one,two,three)
                for e in xmlcollected(x,pattern) do
                    local a = e.at
                    local t = a[attribute]
                    if t then
                        local c = one[t] or (two and two[t]) or (three and three[t])
                        if c then
                            local v = c[interface]
                            if v then
                                a[attribute] = v
                            end
                        end
                    end
                end
            end

            replace('cd:command',   'name',    commands, elements, variables)
            replace('cd:string',    'value',   commands, elements)
            replace('cd:variable' , 'value',   variables)

            replace('cd:parameter', 'name',    constants)
            replace('cd:constant',  'type',    variables)
            replace('cd:constant',  'default', variables)
            replace('cd:variable',  'type',    variables)
            replace('cd:inherit',   'name',    commands, elements)

            replace('cd:instances/cd:constant', 'value', variables)
        end

        if tex.modes["setups:save"] and environment.currentrun == 1 then
            --
            -- the reload is a hack .. we could make a handler instead
            --
            local filename = "context-" .. interface .. ".xml"
            local xmlroot  = x
            local xmlblob  = tostring(xmlroot)
            io.savedata(filename,xmlblob)
            xmlroot = xml.load(filename)
            --
            local definitions = { }
            for e in xml.collected(xmlroot,"cd:interface/cd:define") do
                definitions[e.at.name] = e.dt
            end
            local function resolve(root)
                for e in xmlcollected(root,"*") do
                    if e.tg == "resolve" then
                        local name = e.at.name or ""
                        local resolved = definitions[name]
                        if resolved then
                            e.__p__.dt[e.ni] = resolved
                            resolve(resolved)
                         -- logs.report("setups","resolved: %a",name)
                        else
                            logs.report("setups","unable to resolve: %a",name)
                        end
                    end
                end
            end
            resolve(xmlroot)
            for e in xml.collected(xmlroot,"cd:interface/cd:define") do
                e.__p__.dt[e.ni] = ""
            end
            xml.delete(xmlroot,"/cd:interface/cd:interface/cd:interface/..")
            --
            xmlblob = xml.tostring(xmlroot)
            io.savedata(filename,xmlblob)
            xmlroot = xml.load(filename)
            --
            local spacer = utilities.strings.newrepeater(" ")
            local function simplify(dt,n)
                local nt, nn = { }, 0
                for i=1,#dt do
                    local d = dt[i]
                    if d.special then
                        --
                    elseif type(d) ~= "string" then
                        d.dt = simplify(d.dt,n+1)
                        nn = nn + 1 nt[nn] = "\n" .. spacer[n]
                        nn = nn + 1 nt[nn] = d
                        nn = nn + 1 nt[nn] = "\n" .. spacer[n-1]
                    end
                end
                return nn == 0 and "" or nt
            end
            xmlroot.dt = simplify(xmlroot.dt,0)
            --
            xmlblob = "<?xml version='1.0'?>\n<!-- expanded and compacted i-context.xml -->\n" .. xml.tostring(xmlroot)
            xmlblob = gsub(xmlblob,"\n *\n","\n")
            io.savedata(filename,xmlblob)
        end
    end

    function moduledata.setups.resolved(name)
        lxmlflush(definitions[name])
    end

    function xml.finalizers.s_count(collected)
        local n = 0
        for i=1,#collected do
            local c = collected[i]
            local tg = c.tg
            if tg == "resolve" then
                local d = definitions[c.at.name]
                n = n + xmlcount(d,"/*")
            elseif tg == "delimiter" then
                -- skip
            else
                n = n + 1
            end
        end
        context(n)
    end

    local function getinstances(id)
        local t = { }
        local x = lxmlgetid(id)
        local r = xmlfirst(x,"/instances/resolve")
        if r then
            local x = setups.definitions[r.at.name]
            for c in xmlcollected(x,"constant") do
                t[#t+1] = c.at.value
            end
        else
            for c in xmlcollected(x,"/instances/constant") do
                t[#t+1] = c.at.value
            end
        end
        return t
    end

    interfaces.implement {
        name      = "getsetupstring",
        actions   = function(s)
            local g = getsetupstring(s)
            if not find(s,"^cd:") then
                setuptxtword(g)
            elseif find(s,"%-.$") then -- singular | plural
                setupvarword(g)
            else
                setupintword(g) -- cap
            end
        end,
        overload  = true,
        arguments = "string",
    }

    interfaces.implement {
        name      = "rawsetupstring",
        actions   = { getsetupstring, context },
        overload  = true,
        arguments = "string",
    }

    interfaces.implement {
        name      = "getinstances",
        actions   = { getinstances, function(t) context("%,t",t) end },
        overload  = true,
        arguments = { "string" },
    }
\stopluacode

% <?xml version="1.0" encoding="UTF-8"?>
%
% <cd:interface xmlns:cd="http://www.pragma-ade.com/commands">
%
%     <cd:interfacefile filename="i-document.xml"/>
%     <cd:interfacefile filename="i-file.xml"/>
%
% </cd:interface>

\startxmlsetups xml:setups:interfacefile
    \loadsetups[\xmlatt{#1}{filename}]
\stopxmlsetups

\startxmlsetups xml:setups:basics
    \xmlincludeoptions{#1}{interfacefile|include}{filename}{recurse,basename}
    \xmlsetsetup{#1}{*}{xml:setups:*}
    \xmlfunction{#1}{setups_define}
\stopxmlsetups

\xmlregisterdocumentsetup{setups}{xml:setups:basics}

\let\loadedsetups\empty % we load more setups, setups:<name>

\unexpanded\def\loadsetups
  {\dosingleempty\cmd_load_setups}

\def\cmd_load_setups[#1]%
  {\edef\m_cmd_asked_setups{#1}%
   \doifnotmode{no-setup-main}{\def\m_cmd_asked_setups{i-context.xml}}%
   \ifx\m_cmd_asked_setups\empty \else
     \doonlyonce{setups:#1}
       {\doglobal\prependtocommalist{setups:#1}\loadedsetups
        \doiffileexistselse{#1}
           {\xmlloadonly{setups:#1}{#1}{setups}}%
           {\xmlloadonly{setups:#1}{#1.xml}{setups}}%
        % qualified path saves > 50% runtime
        \xmlfilter{setups:#1}{/interface//command/command(xml:setups:register)}}%
   \fi}

\newconstant   \c_cmd_kind
\newconditional\c_cmd_doing_line
\newconditional\c_cmd_measuring
\newconditional\c_cmd_show_setup
\newcount      \c_cmd_current_argument
\newcount      \c_cmd_maximum_argument
\newdimen      \d_cmd_current_width
\let           \m_cmd_current_hash      \empty
\let           \m_cmd_current_file      \empty

% todo: use different names (and a backward compatible extra module then)

\unexpanded\def\basicsetup{\c_cmd_kind\zerocount\cmd_show_setup}
\unexpanded\def\shortsetup{\c_cmd_kind\plusone  \cmd_show_setup}
\unexpanded\def\setup     {\c_cmd_kind\plustwo  \cmd_show_setup}
\unexpanded\def\showsetup {\c_cmd_kind\plustwo  \cmd_show_setup}

\unexpanded\def\showsetupinlist#1#2#3%
  {%(#1)(#2)(#3)\par
   \edef\m_cmd_instance{\secondoftwoarguments#3}%
   \c_cmd_kind\plustwo
   \xmlsetup{\firstoftwoarguments#3}{xml:setups:typeset}
   \let\m_cmd_instance\empty
   \par}

\installtextracker
  {cmd.showsetup}
  {\settrue\c_cmd_show_setup}
  {\setfalse\c_cmd_show_setup}

\unexpanded\def\cmd_show_setup
  {\doifelsenextoptionalcs\cmd_show_setup_yes\cmd_show_setup_nop}

\def\cmd_show_setup_yes[#1]%
  {\iffirstargument
     \cmd_show_setup_nop{#1}%
   \else
     \expandafter\cmd_show_setup_nop
   \fi}

\def\cmd_show_setup_nop#1% this will trigger 'used'
  {\registersort[texcommand][stp:x:#1]%
   \ifconditional\c_cmd_show_setup
     \writestatus{setup}{#1 / \rawsynonymname{texcommand}{stp:x:#1}}%
   \fi
   \startelement[setup][name=#1]%
     \startelement[noexport][comment={setup definition #1}]%
       \edef\cmd_id{\rawsynonymname{texcommand}{stp:x:#1}}%
       \ifx\cmd_id\empty
          missing: stp:x:#1
       \else
         \xmlsetup{\expandafter\firstoftwoarguments\cmd_id}{xml:setups:typeset}
       \fi
     \stopelement
   \stopelement}

\unexpanded\def\placesetup    {\placelistofsorts[texcommand][\c!criterium=\v!used]}
\unexpanded\def\placeallsetups{\placelistofsorts[texcommand][\c!criterium=\v!all ]}

% todo: grouped

\let\placeeverysetup\placeallsetups

%D Typesetting:

\startxmlsetups xml:setups:typeset
    \doifelsenothing {#1} {
        \xmlsetup{#1}{xml:setups:typeset:nop}
    } {
        \xmlsetup{#1}{xml:setups:typeset:yes}
    }
\stopxmlsetups

\startxmlsetups xml:setups:typeset:nop
    \blank
    {\tttf MISSING SETUP}
    \blank
\stopxmlsetups

\startxmlsetups xml:setups:make:string
    \xmlatt{#1}{value}
\stopxmlsetups

\startxmlsetups xml:setups:make:instance
    \ifx\m_cmd_instance\empty
        \setupintfont{\xmlatt{#1}{value}}
    \else
        \m_cmd_instance
    \fi
\stopxmlsetups

\startxmlsetups xml:setups:make:variable
    \setupintfont{\xmlatt{#1}{value}}
\stopxmlsetups

\let\m_cmd_current_hash\empty
\let\m_cmd_current_file\empty
\let\m_cmd_font        \empty
\let\m_cmd_name        \empty
\let\m_cmd_start       \empty
\let\m_cmd_stop        \empty
\let\m_cmd_instance    \empty

\startxmlsetups xml:setups:make:prepare
    \edef\m_cmd_current_hash{\xmlatt{#1}{hash}}
    \xdef\m_cmd_current_file{\xmlatt{#1}{file}}%
    \xmldoifelseempty{#1}{/sequence} {
        \edef\m_cmd_name{\xmlatt{#1}{name}}
    } {
        \edef\m_cmd_name{\xmlfilter{#1}{/sequence/(string|variable|instance)/command(xml:setups:make:*)}}
    }
    \doifelse {\xmlatt{#1}{type}} {environment} {
        \doifsomethingelse {\xmlatt{#1}{begin}} {
            \edef\m_cmd_start{\xmllastatt}
        } {
            \let\m_cmd_start\e!start
        }
        \doifsomethingelse {\xmlatt{#1}{end}} {
            \edef\m_cmd_stop{\xmllastatt}
        } {
            \let\m_cmd_stop\e!stop
        }
    } {
        \let\m_cmd_start\empty
        \let\m_cmd_stop \empty
    }
    \doifelse {\xmlatt{#1}{generated}} {yes} {
        \let\m_cmd_font\ttsl
    } {
        \let\m_cmd_font\relax
    }
\stopxmlsetups

\startsetups xml:setups:make:start
    \bgroup
        \settrue\c_cmd_doing_line
        \m_cmd_font
        \letterbackslash
        \m_cmd_start
        \m_cmd_name
        \ignorespaces
    \egroup
\stopsetups

\startsetups xml:setups:make:stop
    \ifx\m_cmd_stop\empty \else
        \bgroup
            \settrue\c_cmd_doing_line
            \hskip.5em\unknown\hskip.5em
            \m_cmd_font
            \letterbackslash
            \m_cmd_stop
            \m_cmd_name
            \ignorespaces
        \egroup
    \fi
\stopsetups

\startxmlsetups xml:setups:typeset:line
    \ttbf
    \nohyphens
    \xmlsetup{#1}{xml:setups:make:prepare}
    \directsetup{xml:setups:make:start}
    \xmldoif{#1}{/arguments} {
        \bgroup
            \settrue\c_cmd_doing_line
            \global\c_cmd_current_argument\zerocount
            \ignorespaces
            \xmlfilter{#1}{/arguments/text()}
        \egroup
    }
    \directsetup{xml:setups:make:stop}
\stopxmlsetups

\startxmlsetups xml:setups:typeset:raw
    \nohyphens
    \veryraggedright
    \global\c_cmd_current_argument\zerocount
    \global\c_cmd_maximum_argument0\xmlfilter{#1}{/arguments/*/s_count()}\relax
    \xmlsetup{#1}{xml:setups:make:prepare}
    \ttbf
    \directsetup{xml:setups:make:start}
    \xmldoif{#1}{/arguments} {
        \settrue\c_cmd_doing_line
        \bgroup
            \tttf
            \global\c_cmd_current_argument\zerocount
            \ignorespaces
            \xmlfilter{#1}{/arguments/text()}
        \egroup
    }
    \directsetup{xml:setups:make:stop}
\stopxmlsetups

\startxmlsetups xml:setups:typeset:detail
    \xmldoif{#1}{/arguments} {
        \bgroup
            \setfalse\c_cmd_doing_line
            \global\c_cmd_current_argument\zerocount
           %\blank[\v!line] % packed mode (we could do \startunpacked ...)
            \godown[.75\lineheight]
            \switchtobodyfont[\v!small]
            \ignorespaces\xmlfilter{#1}{/arguments/text()}\endgraf
        \egroup
    }
\stopxmlsetups

\startxmlsetups xml:setups:instance
    \doifelse {\xmltag{#1}} {resolve} {
        \ctxlua{lxml.command(moduledata.setups.definitions['\xmlatt{#1}{name}'],"constant","xml:setups:instance")}
    } {
        \xmlatt{#1}{value}\enskip % we need a break
    }
\stopxmlsetups

\startxmlsetups xml:setups:typeset:instances
    \ifx\m_cmd_instance\empty
        \xmldoif{#1}{/instances} {
            \godown[.75\lineheight]
            {\ttbf instances:}
            \enspace
            \xmlfilter{#1}{/instances/(constant|resolve)/command(xml:setups:instance)}
            \removeunwantedspaces
        }
    \fi
\stopxmlsetups

\startxmlsetups xml:setups:typeset:yes
    \glet\m_cmd_current_file\empty
    \ifcase\c_cmd_kind
        \xmlsetup{#1}{xml:setups:typeset:line}
    \or
        \getvalue{\e!start setuptext}
        \xmlsetup{#1}{xml:setups:typeset:raw}
        \getvalue{\e!stop setuptext}
    \or
        \getvalue{\e!start setuptext}
        \xmlsetup{#1}{xml:setups:typeset:raw}
        \endgraf
        \xmlsetup{#1}{xml:setups:typeset:detail}
        \endgraf
        \xmlsetup{#1}{xml:setups:typeset:instances}
        \getvalue{\e!stop setuptext}
    \fi
    \glet\m_cmd_current_file\empty
\stopxmlsetups

\startsetups xml:setups:overlay:file
    \vbox to \overlayheight \bgroup
        \infofont
        \vfill
        \scratchdimen.5\exheight
        \hbox to \overlaywidth \bgroup
            \strut
            \hss
            \m_cmd_current_file
            \hskip\dimexpr\scratchdimen+\strutdp\relax
        \egroup
        \vskip\scratchdimen
    \egroup
\stopsetups

\defineoverlay
  [setupfilename]
  [\directsetup{xml:setups:overlay:file}]

\startxmlsetups xml:setups:resolve
    \ignorespaces
    \ctxlua{moduledata.setups.resolved('\xmlatt{#1}{name}')}
\stopxmlsetups

%D This is the first pass; here we generate the top line.

\startxmlsetups xml:setups:define
    \ignorespaces\xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:setups:sequence
    \ignorespaces\xmlflush{#1}
\stopxmlsetups

\startxmlsetups xml:setups:string
    \xmlatt{#1}{value}\ignorespaces
\stopxmlsetups

\startxmlsetups xml:setups:delimiter
    \ifconditional\c_cmd_doing_line
        \kern.5\emwidth
        \letterbackslash\xmlatt{#1}{name}
    \fi
    \ignorespaces
\stopxmlsetups

\startxmlsetups xml:setups:content     \show_setup_component{#1}{content}    \stopxmlsetups
\startxmlsetups xml:setups:displaymath \show_setup_component{#1}{displaymath}\stopxmlsetups
\startxmlsetups xml:setups:index       \show_setup_component{#1}{index}      \stopxmlsetups
\startxmlsetups xml:setups:math        \show_setup_component{#1}{math}       \stopxmlsetups
\startxmlsetups xml:setups:nothing     \show_setup_component{#1}{nothing}    \stopxmlsetups
\startxmlsetups xml:setups:file        \show_setup_component{#1}{file}       \stopxmlsetups
\startxmlsetups xml:setups:position    \show_setup_component{#1}{position}   \stopxmlsetups
\startxmlsetups xml:setups:reference   \show_setup_component{#1}{reference}  \stopxmlsetups
\startxmlsetups xml:setups:csname      \show_setup_component{#1}{csname}     \stopxmlsetups
\startxmlsetups xml:setups:destination \show_setup_component{#1}{destination}\stopxmlsetups
\startxmlsetups xml:setups:triplet     \show_setup_component{#1}{triplet}    \stopxmlsetups
\startxmlsetups xml:setups:word        \show_setup_component{#1}{word}       \stopxmlsetups
\startxmlsetups xml:setups:template    \show_setup_component{#1}{template}   \stopxmlsetups
\startxmlsetups xml:setups:angles      \show_setup_component{#1}{angles}     \stopxmlsetups
\startxmlsetups xml:setups:apply       \show_setup_component{#1}{apply}      \stopxmlsetups
\startxmlsetups xml:setups:twowords    \show_setup_component{#1}{twowords}   \stopxmlsetups
\startxmlsetups xml:setups:threewords  \show_setup_component{#1}{threewords} \stopxmlsetups
\startxmlsetups xml:setups:text        \show_setup_component{#1}{text}       \stopxmlsetups

% todo: cd:par => \par
% todo: cd:sep => \\

\unexpanded\def\show_setup_component#1#2%
  {\ifconditional\c_cmd_doing_line
     \getvalue{show_setup_#2}{#1}%
   \else
     \simpleSETUPargument{#2}%
   \fi}

%D This is the second pass; here we generate the table.

\unexpanded\def\cmd_column_one_start
  {\bgroup
   \scratchdimen2\emwidth
   \advance\leftskip \scratchdimen
   \noindent\llap{\hbox to \scratchdimen{\show_setup_number\hss}}%
   \strut}

\unexpanded\def\cmd_column_one_stop
  {\endgraf
   \egroup}

\unexpanded\def\cmd_column_two_start#1#2%
  {\bgroup
   \scratchdimen2.5\emwidth
   \advance\hangindent\dimexpr\d_cmd_current_width+\scratchdimen\relax
   \noindent \hbox to \hangindent{#1\hss\hbox to \scratchdimen{\hss#2\hss}}%
   \strut}

\unexpanded\def\cmd_column_two_stop
  {\endgraf
   \egroup}

\startxmlsetups xml:setups:assignments
    \ifconditional\c_cmd_doing_line
        \ifcase\c_cmd_kind
            \expandafter\show_setup_line
        \else
            \expandafter\show_setup_any
        \fi{#1}{assignment\xmlattdef{#1}{delimiters}{brackets}}
    \else
        \global\d_cmd_current_width\zeropoint
        \setbox\scratchbox\vbox\bgroup
            \settrue\c_cmd_measuring
            \xmlall{#1}{/(parameter|resolve)}
        \egroup
        \global\d_cmd_current_width\themaxboxwidth\scratchbox\relax
        \cmd_column_one_start
            \ignorespaces
            \xmldoifelse {#1} {/(parameter|inherit|resolve)} {
               \xmlflush{#1}
            } {
               \unknown
            }
        \cmd_column_one_stop
        \godown[.75\lineheight]
        \ignorespaces
    \fi
\stopxmlsetups

\startxmlsetups xml:setups:keywords
    \ifconditional\c_cmd_doing_line
        \ifcase\c_cmd_kind
            \expandafter\show_setup_line
        \else
            \expandafter\show_setup_any
        \fi{#1}{\xmlattdef{#1}{delimiters}{brackets}}
    \else
        \cmd_column_one_start
            \ignorespaces
            \xmlflush{#1}
        \cmd_column_one_stop
        \godown[.75\lineheight]
        \ignorespaces
    \fi
\stopxmlsetups

\startxmlsetups xml:setups:parameter
    \ifconditional\c_cmd_measuring
      \getsetupstring{\xmlatt{#1}{name}}\par
    \else
      \cmd_column_two_start{\getsetupstring{\xmlatt{#1}{name}}}{=}
            \ignorespaces
            \xmlflush{#1}
            \doifmode{interface:setup:defaults} {
                \ifx\m_cmd_current_hash\empty \else
                    \begingroup
                        % todo, make a one level expansion of parameter
                        \let\emwidth \relax
                        \let\exheight\relax
                        \edef\temp{\csname named\m_cmd_current_hash parameter\endcsname\empty{\xmlatt{#1}{name}}}
                        \ifx\temp\empty \else
                            =\space
                            \detokenize\expandafter{\temp}
                        \fi
                    \endgroup
                \fi
            }
        \cmd_column_two_stop
    \fi
    \ignorespaces
\stopxmlsetups

%xmlmapvalue{setups:method}{class} {:}
\xmlmapvalue{setups:method}{range} {:}
\xmlmapvalue{setups:method}{apply} {->}
\xmlmapvalue{setups:method}{factor}{*}
\xmlmapvalue{setups:method}{none}  {}

\startxmlsetups xml:setups:constant:value
    \getsetupstring{\xmlatt{#1}{type}}
\stopxmlsetups

\definebar % in case we mess with underbar settings
  [cmd_underbar]
  [\v!underbar]
  [\c!foregroundcolor=,
   \c!foregroundstyle=,
   \c!color=]

\startxmlsetups xml:setups:constant
    \doifelsemode {setups-pass-one} {
    } {
        \doifsomethingelse{\xmlatt{#1}{prefix}} {
            \getsetupstring{\xmllastatt}
            \xmlmappedvalue{setups:method}{\xmlatt{#1}{method}}{none}
        } {
            \doif {\xmlatt{#1}{default}} {yes} {
                \cmd_underbar % next needs to be {braced}
            }
        }
        {\getsetupstring{\xmlatt{#1}{type}}}
        \space
        \ignorespaces
    }
\stopxmlsetups

\startxmlsetups xml:setups:variable
    \doifelsemode {setups-pass-one} {
        \expanded{\setupintfont{\xmlatt{#1}{value}}}\ignorespaces
    } {
        \getsetupstring{\xmlatt{#1}{value}}
        \space
        \ignorespaces
    }
\stopxmlsetups

\startxmlsetups xml:setups:inherit
%     \cmd_column_two_start{}{}
        \rawsetupstring{cd:inherits}:
        \enspace
        \letterbackslash
        \xmlatt{#1}{name}
%     \cmd_column_two_stop
    \ignorespaces
\stopxmlsetups

\unexpanded\def\simpleSETUPargument#1%
  {\cmd_column_one_start
      \cmd_internal_value{#1}%
   \cmd_column_one_stop
   \godown[.75\lineheight]
   \ignorespaces}

%D Auxiliary.

\unexpanded\def\show_setup_any#1#2%
  {\bgroup
   \global\advance\c_cmd_current_argument\plusone
   \doifelse{\xmlatt{#1}{optional}}{yes}\donetrue\donefalse
   \setbox0=\hbox
     {\ifdone\sl\fi
      \doifelse{\xmlatt{#1}{list}}{yes}
        {\getsetupstring{cd:#2-l}}%
        {\getsetupstring{cd:#2-s}}}%
   \setbox2=\hbox to \wd0
     {\hss
      \ifcase\c_cmd_kind\else
        \ifcase\c_cmd_maximum_argument \relax
        \or
          \raise1.25\exheight\hbox
            {\txx *}%
        \else
          \raise1.25\exheight\hbox
            {\txx\the\c_cmd_current_argument}%
         \fi
      \fi
      \hss}%
   \setbox4=\hbox to \wd0
     {\hss
      \ifdone
        \lower2\exheight\hbox
          \bgroup
            \txx
            \getsetupstring{cd:optional}%
          \egroup
        \hss
      \fi}%
   \ht2\ht\strutbox
   \dp4\dp\strutbox
   \hskip.5\emwidth
   \wd0\zeropoint
   \box0
   \wd2\zeropoint
   \box2
   \box4%
   \egroup
   \ignorespaces}

\unexpanded\def\show_setup_line#1#2%
  {\kern.5\emwidth
   \getsetupstring{cd:#2-s}%
   \ignorespaces}

\unexpanded\def\show_setup_number
  {\global\advance\c_cmd_current_argument\plusone
   \hbox to 2\emwidth
     {\ifcase\c_cmd_maximum_argument \relax
        \or*\else\the\c_cmd_current_argument
      \fi
      \hss}}

% todo: replace = by lower

\unexpanded\def\setupEQsymbol % we raise the number already
  {.\lower.25\exheight\hpack{=}.}

\unexpanded\def\setupAPPLYsymbol % we raise the number already
  {..\lower.25\exheight\hpack{=>}..}

% arguments

\unexpanded\def\show_setup_displaymath#1{\show_setup_any {#1}{displaymath}}
\unexpanded\def\show_setup_index      #1{\show_setup_any {#1}{index}}
\unexpanded\def\show_setup_math       #1{\show_setup_any {#1}{math}}
\unexpanded\def\show_setup_nothing    #1{\show_setup_any {#1}{nothing}}
\unexpanded\def\show_setup_file       #1{\show_setup_any {#1}{file}}
\unexpanded\def\show_setup_position   #1{\show_setup_any {#1}{position}}
\unexpanded\def\show_setup_template   #1{\show_setup_any {#1}{template}}
\unexpanded\def\show_setup_angles     #1{\show_setup_any {#1}{angle}}
\unexpanded\def\show_setup_reference  #1{\show_setup_any {#1}{reference}}
\unexpanded\def\show_setup_apply      #1{\show_setup_any {#1}{apply}}
\unexpanded\def\show_setup_twowords   #1{\show_setup_any {#1}{twowords}}
\unexpanded\def\show_setup_threewords #1{\show_setup_any {#1}{threewords}}
\unexpanded\def\show_setup_csname     #1{\show_setup_any {#1}{noargument}}
\unexpanded\def\show_setup_destination#1{\show_setup_any {#1}{destination}}
\unexpanded\def\show_setup_triplet    #1{\show_setup_any {#1}{triplet}}
\unexpanded\def\show_setup_word       #1{\show_setup_any {#1}{word}}
\unexpanded\def\show_setup_content    #1{\show_setup_any {#1}{content}}
\unexpanded\def\show_setup_text       #1{\show_setup_any {#1}{textual}}
\unexpanded\def\show_setup_to         #1{\show_setup_line{#1}{to}}
\unexpanded\def\show_setup_macro      #1{\show_setup_any {#1}{macro}}

% A prelude to a rewrite and some more:

% \definetype[parametercommand][\v!type]
% \definetype[parameterkey]    [\v!type]
% \definetype[parametervalue]  [\v!type][\c!space=\v!on]

% todo: no list but hash ..

\definetype[parametercommand]
\definetype[parameterkey]
\definetype[parametervalue]  [\c!space=\v!on]

\setuptype [parametercommand] [\c!color=darkmagenta]
\setuptype [parametervalue]   [\c!color=darkyellow]

\startxmlsetups xml:setups:parameters:value
    \edef\currentsetupparameterkey  {\xmlatt{#1}{name}}
    \edef\currentsetupparametervalue{\begincsname named\currentsetupparametercategory parameter\endcsname\currentsetupparameterinstance\currentsetupparameterkey}
    \ifx\currentsetupparameterinstance\empty
        \expanded {
            \NC \parameterkey  {\currentsetupparameterkey}
            \NC \parametervalue{\detokenize\expandafter{\currentsetupparametervalue}}
            \NC \NR
        }
    \else\ifx\currentsetupparametervalue\empty
    \else
        \edef\currentsetupparameterdefault{\begincsname named\currentsetupparametercategory parameter\endcsname\empty\currentsetupparameterkey}
        \ifx\currentsetupparametervalue\currentsetupparameterdefault
            % skip
        \else
            \expanded {
                \NC \parameterkey  {\currentsetupparameterkey}
                \NC \parametervalue{\detokenize\expandafter{\currentsetupparametervalue}}
                \NC \NR
            }
        \fi
    \fi\fi
\stopxmlsetups

\startxmlsetups xml:setups:parameters:values
    \blank[\v!big]
    \expanded {
        \parametercommand {
            \currentsetupparametercommand
            \space:\space
            \ifx\currentsetupparameterinstance\empty
                defaults
            \else
                \currentsetupparameterinstance
            \fi
        }
    }
    \blank[\v!big,\v!samepage]
    \starttabulate[|l|p|]
        % no /interface here
        \xmlall
            {#1}
            {interface/command[@name=='\currentsetupparametercommand' or @handler=='\currentsetupparametercommand']/arguments/assignments/parameter/command(xml:setups:parameters:value)}
        \ifnum\noftabulaterows = \zerocount
            \NC \parameterkey{no specific settings} \NC \NC \NR
        \fi
    \stoptabulate
\stopxmlsetups

\starttexdefinition showrootvalues [#1]
    \edef\currentsetupparametercategory{#1}
    \edef\currentsetupparametercommand{setup#1}
    \let\currentsetupparameterinstance\empty
    \xmlsetup{\loadedsetups}{xml:setups:parameters:values}
\stoptexdefinition

\starttexdefinition showinstancevalues [#1]#2[#3]
    \edef\currentsetupparametercategory{#1}
    \edef\currentsetupparametercommand{setup#1}
    \edef\currentsetupparameterinstance{#3}
    \xmlsetup{\loadedsetups}{xml:setups:parameters:values}
\stoptexdefinition

% official interface

\unexpanded\def\cmdinternal#1%
  {{\tttf\getsetupstring{#1}}} % todo color .. highlight

\let\cmdbasicsetup\basicsetup
\let\cmdshortsetup\shortsetup
\let\cmdfullsetup \showsetup

\unexpanded\def\cmd_with_instance#1#2#3%
  {\edef\m_cmd_instance{#3}%
   #1{#2}%
   \let\m_cmd_instance\empty}

\unexpanded\def\cmdbasicsetupinstance{\cmd_with_instance\cmdbasicsetup}
\unexpanded\def\cmdshortsetupinstance{\cmd_with_instance\cmdshortsetup}
\unexpanded\def\cmdfullsetupinstance {\cmd_with_instance\cmdfullsetup }

% bonus

\definefloat
  [definition]

\setupcaption
  [definition]
  [align=flushright]

\unexpanded\def\showdefinition
  {\doifelsenextoptional\cmd_show_definition_yes\cmd_show_definition_nop}

\unexpanded\def\cmd_show_definition_nop#1%
  {\cmd_show_definition_yes[#1]}

\unexpanded\def\cmd_show_definition_yes[#1]%
  {\placedefinition[here][definition:#1]{\tex{#1}}{\showsetup{#1}}}

\unexpanded\def\definition[#1]%
  {\begingroup
   \getcommalistsize[#1]%
   \scratchcounter\zerocount
   \def\dodefinition##1%
     {\advance\scratchcounter\plusone
      \ifnum\scratchcounter=\commalistsize
        \in{and}[definition:##1]%
      \else\ifnum\scratchcounter=\plusone
        \in{definition}[definition:##1]\space
      \else
        \in{, }[definition:##1]\space
      \fi\fi}%
   \processcommalist[#1]\dodefinition
   \endgroup}

\protect \endinput
