1if not modules then modules = { } end modules ['page-ini'] = {
2 version = 1.001,
3 comment = "companion to page-ini.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
11local tonumber, rawget, rawset, type, next = tonumber, rawget, rawset, type, next
12local match = string.match
13local sort, tohash, insert, remove, sortedkeys = table.sort, table.tohash, table.insert, table.remove, table.sortedkeys
14local settings_to_array, settings_to_hash = utilities.parsers.settings_to_array, utilities.parsers.settings_to_hash
15
16local texgetcount = tex.getcount
17
18local tonut = nodes.tonut
19local nextlist = nodes.nuts.traversers.list
20local texlists = tex.lists
21
22local context = context
23local ctx_doif = commands.doif
24local ctx_doifelse = commands.doifelse
25
26local implement = interfaces.implement
27
28local data = table.setmetatableindex("table")
29local last = 0
30local pages = structures.pages
31local autolist = { }
32local report = logs.reporter("pages","mark")
33local active = false
34
35local trace = false trackers.register("pages.mark",function(v) trace = v end)
36
37function pages.mark(name,list,settings)
38 active = true
39
40 local realpage = texgetcount("realpageno")
41 if type(settings) == "string" then
42 settings = settings_to_hash(settings)
43 end
44 if not list or list == "" then
45 if trace then
46 report("marking current page %i as %a",realpage,name)
47 end
48 data[realpage][name] = settings or true
49 return
50 end
51 if type(list) == "string" then
52 list = settings_to_array(list)
53 end
54 if type(list) == "table" then
55 for i=1,#list do
56 local page = list[i]
57 local sign = false
58 if type(page) == "string" then
59 local f, t = match(page,"(%d+)[:%-](%d+)")
60 if f and t then
61 f, t = tonumber(f), tonumber(t)
62 if f and t and f <= t then
63 if trace then
64 report("marking page %i upto %i as %a",f,t,name)
65 end
66 for page=f,t do
67 data[page][name] = settings or true
68 end
69 end
70 page = false
71 else
72 local s, p = match(page,"([%+%-])(%d+)")
73 if s then
74 sign, page = s, p
75 end
76 end
77 end
78 if page then
79 page = tonumber(page)
80 if page then
81 if sign == "+" then
82 page = realpage + page
83 end
84 if sign == "-" then
85 report("negative page numbers are not supported")
86 else
87 if trace then
88 report("marking page %i as %a",page,name)
89 end
90 data[page][name] = settings or true
91 end
92 end
93 end
94 end
95 else
96 if trace then
97 report("marking current page %i as %a",realpage,name)
98 end
99 data[realpage][name] = settings or true
100 end
101end
102
103local tobemarked = { }
104
105function pages.markedlist(realpage)
106 if active and realpage then
107 local m = rawget(tobemarked,realpage) or rawget(data,realpage)
108 return m and next(m) and sortedkeys(m)
109 end
110end
111
112local function marked(name)
113 if active then
114 local realpage = texgetcount("realpageno")
115 if last ~= 0 then
116 for i=last,realpage-1 do
117
118 local di = data[i]
119 if di then
120 tobemarked[i] = di
121 rawset(data,i,nil)
122 end
123 end
124 last = 0
125 end
126 local pagedata = rawget(data,realpage)
127 return pagedata and pagedata[name] and true or false
128 else
129 return false
130 end
131end
132
133local function markedparameter(name,key)
134 if active then
135 local pagedata = rawget(data,texgetcount("realpageno"))
136 if pagedata then
137 pagedata = pagedata[name]
138 if pagedata then
139 pagedata = pagedata[key]
140 end
141 end
142 return pagedata
143 end
144end
145
146local function toranges(marked)
147 local list = { }
148 local size = #marked
149 if size > 0 then
150 local first = marked[1]
151 local last = first
152 for i=2,size do
153 local page = marked[i]
154 if page > last + 1 then
155 list[#list+1] = { first, last }
156 first = page
157 end
158 last = page
159 end
160 list[#list+1] = { first, last }
161
162 active = true
163 end
164 return list
165end
166
167local function allmarked(list)
168 if active and list then
169 local collected = pages.collected
170 if collected then
171 if type(list) == "string" then
172 list = settings_to_hash(list)
173 elseif type(list) == "table" and #list > 0 then
174 list = tohash(list)
175 end
176 if type(list) == "table" then
177 local found = { }
178 for name in next, list do
179 for page, list in next, data do
180 if list[name] and collected[page] then
181 found[#found+1] = page
182 end
183 end
184 end
185 if #found > 0 then
186 sort(found)
187 if trace then
188 local ranges = toranges(found)
189 for i=1,#ranges do
190 local range = ranges[i]
191 local first = range[1]
192 local last = range[2]
193 if first == last then
194 report("marked page : %i",first)
195 else
196 report("marked range: %i upto %i",first,last)
197 end
198 end
199 end
200 return found
201 end
202 end
203 end
204 end
205end
206
207pages.marked = marked
208pages.toranges = toranges
209pages.allmarked = allmarked
210
211
212
213
214
215
216
217
218
219
220
221
222local function autopageaction()
223 if active then
224 local nofauto = #autolist
225 if nofauto > 0 then
226 local realpage = texgetcount("realpageno")
227 for i=1,nofauto do
228 local entry = autolist[i]
229 local names = entry[1]
230 local settings = entry[2]
231 for j=1,#names do
232 local name = names[j]
233 local list = data[realpage]
234 if not list[name] then
235 if trace then
236 report("automatically marking page %i as %a",realpage,name)
237 end
238 list[name] = settings or true
239 end
240 end
241 end
242 end
243 end
244end
245
246local function startmarked(name,settings)
247 active = true
248
249 insert(autolist, { settings_to_array(name), settings_to_hash(settings) })
250 autopageaction(true)
251end
252
253local function stopmarked()
254 local nofauto = #autolist
255 if nofauto > 0 then
256 if not texlists.pagehead then
257 local realpage = texgetcount("realpageno")
258 for i=1,nofauto do
259 local entry = autolist[i]
260 local names = entry[1]
261 for j=1,#names do
262 local name = names[j]
263 local list = data[realpage]
264 if list[name] then
265 if trace then
266 report("automatically unmarking page %i as %a",realpage,name)
267 end
268 list[name] = nil
269 end
270 end
271 end
272 end
273 remove(autolist)
274 end
275end
276
277implement {
278 name = "checkmarkedpages",
279 actions = autopageaction,
280}
281
282implement {
283 name = "markpage",
284 arguments = "3 strings",
285 actions = pages.mark
286}
287
288implement {
289 name = "doifelsemarkedpage",
290 arguments = "string",
291 actions = { marked, ctx_doifelse }
292}
293
294implement {
295 name = "doifmarkedpage",
296 arguments = "string",
297 actions = { marked, ctx_doif }
298}
299
300implement {
301 name = "markedpageparameter",
302 arguments = "strings",
303 actions = function(name,key)
304 local value = markedparameter(name,key)
305 if value then
306 context(value)
307 end
308 end
309}
310
311implement {
312 name = "markedpages",
313 arguments = "string",
314 actions = function(name)
315 local t = allmarked(name)
316 if t then
317 context("%,t",t)
318 end
319 end
320}
321
322implement {
323 name = "startmarkpages",
324 arguments = "2 strings",
325 actions = startmarked,
326}
327
328implement {
329 name = "stopmarkpages",
330 actions = stopmarked,
331}
332
333local tonut = nodes.tonut
334local nextlist = nodes.nuts.traversers.list
335local texlists = tex.lists
336
337implement {
338 name = "doifelsependingpagecontent",
339 actions = function()
340 local h = texlists.contrib_head
341
342 local p = false
343 if h then
344 for n in nextlist, tonut(h) do
345 p = true
346 break
347 end
348 end
349 ctx_doifelse(p)
350 end,
351}
352 |