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