%D \module
%D   [       file=setups-macros,
%D        version=2018.01.15,
%D          title=\CONTEXT\ Setup Definitions,
%D       subtitle=Macro Properties,
%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.

\startluacode

    local find       = string.find
    local gsub       = string.gsub
    local topattern  = string.topattern
    local concat     = table.concat
    local sort       = table.sort
    local sortedkeys = table.sortedkeys
    local sortedhash = table.sortedhash
    local getmacro   = tokens.getters.macro
    local gethash    = tex.hashtokens

    local lpegmatch, P, R, C, S = lpeg.match, lpeg.P, lpeg.R, lpeg.C, lpeg.S

    local macros      = interfaces.macros or { }
    interfaces.macros = macros

    local hashtable   = nil

 -- table.save("temp.lua",gethash())

    local prefix   = P("??")
    local initial  = R("09")^1 * P(">")
    local name     = C(R("az","AZ") * (R("az","AZ","09")+S(" "))^0)
    local parent   = P(":parent")
    local eos      = P(-1)

    local pattern1 = initial^0
                   * name
                   * parent^0
                   * eos
    local pattern2 = prefix
                   * name
                   * eos
    local pattern3 = C(initial^1)
                   * name
                   * parent^1 -- so no e.g. measure here
                   * eos


    local function reload()
         hashtable = gethash()
         sort(hashtable)
    end

    interfaces.macros.reload = reload

    function interfaces.macros.instances(str)
        local namespace = getmacro("??"..str)
        if namespace then
            local found   = { }
            local pattern = P(namespace) * pattern1
            if not hashtable then
                reload()
            end
            for i=1,#hashtable do
                local hi = hashtable[i]
                local pi = lpegmatch(pattern,hi)
                if pi then
                    found[pi] = true
                end
            end
            return sortedkeys(found)
        end
    end

    function interfaces.macros.namespaces()
        local found = { }
        if not hashtable then
            reload()
        end
        for i=1,#hashtable do
            local hi = hashtable[i]
            local pi = lpegmatch(pattern2,hi)
            if pi then
                found[pi] = true
            end
        end
        return sortedkeys(found)
    end

    function interfaces.macros.allinstances()
        local found   = { }
        local reverse = { }
        local all     = { }
        if not hashtable then
            reload()
        end
        for i=1,#hashtable do
            local hi = hashtable[i]
            local pi = lpegmatch(pattern2,hi)
            if pi then
                found[pi] = true
                reverse[getmacro("??"..pi)] = pi
            end
        end
        for i=1,#hashtable do
            local hi = hashtable[i]
            local ni, pi = lpegmatch(pattern3,hi)
            if ni and pi then
                local ri = reverse[ni]
                if ri and found[ri] then
                    local a = all[ri]
                    if a then
                        a[pi] = true
                    else
                        all[ri] = { [pi] = true  }
                    end
                end
            end
        end
        return all
    end

    function interfaces.macros.collect(str)
        local asked   = gsub(str,"^\\","")
        local found   = { }
        local pattern = "^" .. topattern(asked) .. "$"
        if not hashtable then
            reload()
        end
        for i=1,#hashtable do
            local hi = hashtable[i]
            if find(hi,pattern) then
                found[hi] = true
            end
        end
        return sortedkeys(found)
    end

    function commands.getinstances(str,separator)
        local i = interfaces.macros.instances(str)
        if i then
            context(concat(i,separator or ", "))
        end
    end
    function commands.getnamespaces(separator)
        local i = interfaces.macros.namespaces()
        if i then
            context(concat(i,separator or ", "))
        end
    end

    function commands.showallinstances()
        local i = interfaces.macros.allinstances()
        if i then
            local ctxcmd = context.showoneinstance
            for k, v in sortedhash(i) do
                ctxcmd(k,concat(sortedkeys(v),", "))
            end
        end
    end

\stopluacode

\unprotect

\def\getinstances #1{\ctxlua{commands.getinstances("#1")}} % expandable
\def\getnamespaces  {\ctxlua{commands.getnamespaces()}}    % expandable

\unexpanded\def\showoneinstance#1#2%
  {\begingroup
   \hangindent\emwidth
   \hangafter\plusone
   \veryraggedright
   \dontleavehmode
   \ttbf#1:\space
   \tttf#2\par
   \endgroup}

\unexpanded\def\showallinstances
  {\ctxlua{commands.showallinstances()}}

\protect

\continueifinputfile{s-setups-macros.mkiv}

\usemodule[art-01]

\starttext

% \getinstances{measure} \page
% \getinstances{framed}  \page
% \getinstances{layout}  \page
%
% \getnamespaces         \page

\showallinstances

\stoptext
