summaryrefslogtreecommitdiff
path: root/tex/context/base/lxml-sor.lua
blob: a159fd4e00feb184eb805b8e5aab70885d97c34e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
if not modules then modules = { } end modules ['lxml-sor'] = {
    version   = 1.001,
    comment   = "companion to lxml-sor.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local format, concat = string.format, table.concat
local lpegmatch = lpeg.match
local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes

local xml, lxml = xml, lxml

lxml.sorters = lxml.sorters or { }

if not lxml.splitid then
    local splitter = lpeg.C((1-lpeg.P(":"))^1) * lpeg.P("::") * lpeg.C(lpeg.P(1)^1)
    function lxml.splitid(id)
        local d, i = lpegmatch(splitter,id)
        if d then
            return d, i
        else
            return "", id
        end
    end
end

local lists = { }

function lxml.sorters.reset(name)
    lists[name] = {
        sorted  = false,
        entries = { },
        reverse = { },
        results = { },
    }
end

function lxml.sorters.add(name,n,key)
    local list = lists[name]
    if list.sorted then
        -- reverse is messed up, we could regenerate it and go on
    else
        local entries = list and list.entries
        if entries then
            local reverse = list.reverse
            local e = reverse[n]
            if e then
                local keys = entries[e][2]
                keys[#keys+1] = key
            else
                entries[#entries+1] = { n, { key } }
                reverse[n] = #entries
            end
        end
    end
end

function lxml.sorters.show(name)
    local list = lists[name]
    local entries = list and list.entries
    local NC, NR, bold = context.NC, context.NR, context.bold -- somehow bold is not working
    if entries then
        local maxn = 1
        for i=1,#entries do
            if #entries[i][2] > maxn then maxn = #entries[i][2] end
        end
        context.starttabulate { "|Tr|Tr|" .. string.rep("Tlp|",maxn) }
        NC() bold("n")
        NC() bold("id")
        if maxn > 1 then
            for i=1,maxn do
                NC() bold("entry " .. i)
            end
        else
            NC() bold("entry")
        end
        NC() NR()
        context.HL()
        for i=1,#entries do
            local entry = entries[i]
            local document, node = lxml.splitid(entry[1])
            NC() context(i)
            NC() context(node)
            local e = entry[2]
            for i=1,#e do
                NC() context.detokenize(e[i])
            end
            NC() NR()
        end
        context.stoptabulate()
    end
end

lxml.sorters.compare = sorters.comparers.basic -- (a,b)

function lxml.sorters.sort(name)
    local list = lists[name]
    local entries = list and list.entries
    if entries then
        -- filtering
        local results = { }
        list.results = results
        for i=1,#entries do
            local entry = entries[i]
            results[i] = {
                entry = entry[1],
                key = concat(entry[2], " "),
            }
        end
        -- preparation
        local strip = sorters.strip
        local splitter = sorters.splitters.utf
        local firstofsplit = sorters.firstofsplit
        for i=1, #results do
            local r = results[i]
            r.split = splitter(strip(r.key))
        end
        -- sorting
        sorters.sort(results,lxml.sorters.compare)
        -- finalizing
        list.nofsorted = #results
        local split = { }
        for k=1,#results do -- rather generic so maybe we need a function
            local v = results[k]
            local entry, tag = firstofsplit(v)
            local s = split[entry] -- keeps track of change
            if not s then
                s = { tag = tag, data = { } }
                split[entry] = s
            end
            s.data[#s.data+1] = v
        end
        list.results = split
        -- done
        list.sorted = true
    end
end

function lxml.sorters.flush(name,setup)
    local list = lists[name]
    local results = list and list.results
    local xmlw = context.xmlw
    if results and next(results) then
        for key, result in next, results do
            local tag, data = result.tag, result.data
            for d=1,#data do
                xmlw(setup,data[d].entry)
            end
        end
    else
        local entries = list and list.entries
        if entries then
            for i=1,#entries do
                xmlw(setup,entries[i][1])
            end
        end
    end
end