summaryrefslogtreecommitdiff
path: root/tex/context/base/lxml-sor.lua
blob: f2bb756f205ef55e7d97e82c5c82d24c9d8f8b48 (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
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 texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes

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 = splitter:match(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
        context.starttabulate { "|Tr|Tr|Tl|" }
        NC() bold("n") NC() bold("id") NC() bold("entry") 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) NC() context(concat(entry[2]," ")) NR()
        end
        context.stoptabulate()
    end
end

function lxml.sorters.compare(a,b)
    return sorters.comparers.basic(a.split,b.split)
end

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
        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 = sorters.firstofsplit(v.split)
            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
    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
                local dr = data[d]
                texsprint(ctxcatcodes,"\\xmlw{",setup,"}{",dr.entry,"}")
            end
        end
    else
        local entries = list and list.entries
        if entries then
            for i=1,#entries do
                texsprint(ctxcatcodes,"\\xmlw{",setup,"}{",entries[i][1],"}")
            end
        end
    end
end