anch-snc.lua /size: 8880 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['anch-snc'] = {
2    version   = 1.001,
3    comment   = "companion to anch-snc.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9
10-- use factors as in mlib-int.lua
11
12local tonumber, next, setmetatable = tonumber, next, setmetatable
13local concat, sort, remove, copy = table.concat, table.sort, table.remove, table.copy
14local match, find = string.match, string.find
15local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
16
17local P, Cc = lpeg.P, lpeg.Cc
18
19local setmetatableindex = table.setmetatableindex
20
21local factor            = number.dimenfactors.bp
22local mpprint           = mp.print
23local mpnumeric         = mp.numeric
24local mppoints          = mp.points
25local texgetdimen       = tex.getdimen
26
27local p_number = lpegpatterns.cardinal/tonumber
28local p_space  = lpegpatterns.whitespace^0
29local p_tag    = P("syncpos:") * p_number * P(":") * p_number
30local p_option = p_number * ((P(",") * p_space * P("reset") * Cc(true)) + Cc(false)) -- for now
31
32local list     = { }
33local colors   = setmetatableindex("table")
34
35local kinds    = {
36    above    = 1,
37    continue = 2,
38    nothing  = 3,
39    normal   = 4,
40    below    = 5,
41}
42
43local allentries = setmetatableindex(function(t,category)
44    setmetatable(t,nil)
45    for tag, pos in next, job.positions.collected do
46        local c, n = lpegmatch(p_tag,tag)
47        if c then
48            local tc = t[c]
49            if tc then
50                tc[n] = pos
51            else
52                t[c] = { [n] = pos }
53            end
54        end
55    end
56    for k, list in next, t do
57        sort(list,function(a,b)
58            local ap = a.p
59            local bp = b.p
60            if ap == bp then
61                return b.y < a.y
62            else
63                return ap < bp
64            end
65        end)
66        list.start = 1
67    end
68    setmetatableindex(t,"table")
69    return t[category]
70end)
71
72local lastdone = { }
73
74function mp.sync_collect(category,realpage,useregion)
75    local all = allentries[category]
76    local m   = 0
77    local n   = #all
78    list = { }
79    if useregion then
80        -- successive can be optimized when we sort by region
81        local start = 1
82        local done  = false
83        local last, rtop, rbot
84        for i=start,n do
85            local pos = all[i]
86            local p = pos.p
87            local r = pos.r
88            if r == useregion then
89                if not done then
90                    local region = job.positions.collected[r]
91                    list.region  = region
92                    list.page    = region
93                    rtop = (region.y or 0) + (region.h or 0)
94                    rbot = (region.y or 0) - (region.d or 0)
95                    last = { kind = "nothing", top = rtop, bottom = 0, task = 0 }
96                    m = m + 1 ; list[m] = last
97                    done = true
98                end
99                local top = pos.y + pos.h
100                last.bottom = top
101                local task, reset = lpegmatch(p_option,pos.e)
102                last = { kind = "normal", top = top, bottom = 0, task = task }
103                m = m + 1 ; list[m] = last
104            end
105        end
106        if done then
107            last.bottom = rbot
108        end
109    else
110        local start = all.start or 1
111        local done  = false
112        local last, rtop, rbot, ptop, pbot
113        for i=start,n do
114            local pos = all[i]
115            local p = pos.p
116            if p == realpage then
117                if not done then
118                    local region = job.positions.collected[pos.r]
119                    local page   = job.positions.collected["page:"..realpage] or region
120                    list.region  = region
121                    list.page    = page
122                    rtop = (region.y or 0) + (region.h or 0)
123                    rbot = (region.y or 0) - (region.d or 0)
124                    ptop = (page  .y or 0) + (page  .h or 0)
125                    pbot = (page  .y or 0) - (page  .d or 0)
126                    last = { kind = "above", top = ptop, bottom = rtop, task = 0 }
127                    m = m + 1 ; list[m] = last
128                    if i > 1 then
129                        local task, reset = lpegmatch(p_option,all[i-1].e)
130                        last = { kind = "continue", top = rtop, bottom = 0, task = task }
131                        m = m + 1 ; list[m] = last
132                    else
133                        last = { kind = "nothing", top = rtop, bottom = 0, task = 0 }
134                        m = m + 1 ; list[m] = last
135                    end
136                    done = true
137                end
138                local top = pos.y + pos.h
139                last.bottom = top
140                local task, reset = lpegmatch(p_option,pos.e)
141                if reset then
142                    local l = list[2]
143                    l.kind = "nothing"
144                    l.task = 0
145                end
146                last = { kind = "normal", top = top, bottom = 0, task = task }
147                m = m + 1 ; list[m] = last
148            elseif p > realpage then
149                all.start = i -- tricky, only for page
150                break
151            end
152        end
153        if done then
154            last.bottom = rbot
155            last = { kind = "below", top = rbot, bottom = pbot, task = 0 }
156            m = m + 1 ; list[m] = last
157            lastdone[category] = {
158                { kind = "above", top = ptop, bottom = rtop, task = 0 },
159                { kind = "continue", top = rtop, bottom = rbot, task = list[#list-1].task }, -- lasttask
160                { kind = "below", top = rbot, bottom = pbot, task = 0 },
161                region = list.region,
162                page   = list.page,
163            }
164        else
165            local l = lastdone[category]
166            if l then
167                list = copy(l) -- inefficient, mayb emetatable for region/page
168                m    = 3
169            end
170        end
171    end
172    mpnumeric(m)
173end
174
175function mp.sync_extend()
176     local n = #list
177     if n > 0 then
178        for i=1,n do
179            local l = list[i]
180            local k = l.kind
181            if k == "nothing" then
182                local ll = list[i+1]
183                if ll and ll.kind == "normal" then
184                    ll.top = l.top
185                    remove(list,i)
186                    n = #list
187                    break
188                end
189            end
190        end
191    end
192    mpnumeric(n)
193end
194
195function mp.sync_prune()
196     local n = #list
197     if n > 0 then
198        if list[1].kind == "above" then
199            remove(list,1)
200        end
201        if list[1].kind == "nothing" then
202            remove(list,1)
203        end
204        if list[#list].kind == "below" then
205            remove(list,#list)
206        end
207        n = #list
208    end
209    mpnumeric(n)
210end
211
212function mp.sync_collapse()
213    local n = #list
214    if n > 0 then
215        local m = 0
216        local p = nil
217        for i=1,n do
218            local l = list[i]
219            local t = l.task
220            if p == t then
221                list[m].bottom = l.bottom
222            else
223                m = m + 1
224                list[m] = l
225            end
226            p = t
227        end
228        for i=n,m+1,-1 do
229            list[i] = nil
230        end
231        n = m
232    end
233    mpnumeric(n)
234end
235
236function mp.sync_set_color(category,n,v)
237    colors[category][n] = v
238end
239
240function mp.sync_get_color(category,n)
241    mpprint(colors[category][n])
242end
243
244-- function mp.sync_get_size  ()  mpnumeric(#list) end
245-- function mp.sync_get_top   (n) mppoints (list[n].top) end
246-- function mp.sync_get_bottom(n) mppoints (list[n].bottom) end
247-- function mp.sync_get_kind  (n) mpnumeric(kinds[list[n].kind]) end
248-- function mp.sync_get_task  (n) mpnumeric(list[n].task) end
249
250-- function mp.sync_get_x() mppoints(list.page.x or 0) end
251-- function mp.sync_get_y() mppoints(list.page.y or 0) end
252-- function mp.sync_get_w() mppoints(list.page.w or 0) end
253-- function mp.sync_get_h() mppoints(list.page.h or 0) end
254-- function mp.sync_get_d() mppoints(list.page.d or 0) end
255
256function mp.sync_get_size  ()  mpnumeric(#list) end
257function mp.sync_get_top   (n) mpnumeric(list[n].top * factor) end
258function mp.sync_get_bottom(n) mpnumeric(list[n].bottom * factor) end
259function mp.sync_get_kind  (n) mpnumeric(kinds[list[n].kind]) end
260function mp.sync_get_task  (n) mpnumeric(list[n].task) end
261
262function mp.sync_get_x() mpnumeric((list.page.x or 0)*factor) end
263function mp.sync_get_y() mpnumeric((list.page.y or 0)*factor) end
264function mp.sync_get_w() mpnumeric((list.page.w or 0)*factor) end
265function mp.sync_get_h() mpnumeric((list.page.h or 0)*factor) end
266function mp.sync_get_d() mpnumeric((list.page.d or 0)*factor) end
267
268-- function mp.xxOverlayRegion()
269--     local r = tokens.getters.macro("m_overlay_region")
270--     mp.quoted('"'.. r .. '"')
271-- end
272
273