1if not modules then modules = { } end modules [ ' page-lin ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to page-lin.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
11
12
13
14local next , tonumber = next , tonumber
15
16local trace_numbers = false trackers . register ( " lines.numbers " , function ( v ) trace_numbers = v end )
17
18local report_lines = logs . reporter ( " lines " )
19
20local attributes = attributes
21local nodes = nodes
22local context = context
23
24local implement = interfaces . implement
25
26nodes . lines = nodes . lines or { }
27local lines = nodes . lines
28
29lines . data = lines . data or { }
30local data = lines . data
31local last = # data
32
33lines . scratchbox = lines . scratchbox or 0
34
35storage . register ( " lines/data " , data , " nodes.lines.data " )
36
37local variables = interfaces . variables
38
39local v_next = variables . next
40local v_page = variables . page
41local v_no = variables . no
42
43local properties = nodes . properties . data
44
45local nodecodes = nodes . nodecodes
46local listcodes = nodes . listcodes
47
48local hlist_code = nodecodes . hlist
49local vlist_code = nodecodes . vlist
50local whatsit_code = nodecodes . whatsit
51local glyph_code = nodecodes . glyph
52
53local linelist_code = listcodes . line
54
55local a_displaymath = attributes . private ( ' displaymath ' )
56local a_linenumber = attributes . private ( ' linenumber ' )
57local a_linereference = attributes . private ( ' linereference ' )
58
59
60local current_list = { }
61local cross_references = { }
62local chunksize = 250
63
64local nuts = nodes . nuts
65
66local getid = nuts . getid
67local getsubtype = nuts . getsubtype
68local getnext = nuts . getnext
69local getattr = nuts . getattr
70local setattr = nuts . setattr
71local getlist = nuts . getlist
72local getbox = nuts . getbox
73
74
75local getheight = nuts . getheight
76local getdepth = nuts . getdepth
77
78local setprop = nuts . setprop
79local getprop = nuts . getprop
80
81local nexthlist = nuts . traversers . hlist
82local nextvlist = nuts . traversers . vlist
83
84local copy_node = nuts . copy
85
86local is_display_math = nuts . is_display_math
87local leftmarginwidth = nuts . leftmarginwidth
88
89
90
91
92local ctx_convertnumber = context . convertnumber
93local ctx_makelinenumber = context . makelinenumber
94
95local paragraphs = typesetters . paragraphs
96local addtoline = paragraphs . addtoline
97local checkline = paragraphs . checkline
98local moveinline = paragraphs . moveinline
99
100
101
102function lines . number ( n )
103 n = tonumber ( n )
104 local cr = cross_references [ n ] or 0
105 cross_references [ n ] = nil
106 return cr
107end
108
109local function resolve ( n , m )
110 while n do
111 local id = getid ( n )
112 if id = = whatsit_code then
113 local a = getattr ( n , a_linereference )
114 if a then
115 cross_references [ a ] = m
116 end
117 elseif id = = hlist_code or id = = vlist_code then
118 resolve ( getlist ( n ) , m )
119 end
120 n = getnext ( n )
121 end
122end
123
124function lines . finalize ( t )
125 local getnumber = lines . number
126 for _ , p in next , t do
127 for _ , r in next , p do
128 local m = r . metadata
129 if m and m . kind = = " line " then
130 local e = r . entries
131 local u = r . userdata
132 e . linenumber = getnumber ( e . text or 0 )
133 e . conversion = u and u . conversion
134 r . userdata = nil
135 end
136 end
137 end
138end
139
140local filters = structures . references . filters
141local helpers = structures . helpers
142
143structures . references . registerfinalizer ( lines . finalize )
144
145filters . line = filters . line or { }
146
147function filters . line . default ( data )
148
149 ctx_convertnumber ( data . entries . conversion or " numbers " , data . entries . linenumber or " 0 " )
150end
151
152function filters . line . page ( data , prefixspec , pagespec )
153 helpers . prefixpage ( data , prefixspec , pagespec )
154end
155
156function filters . line . linenumber ( data )
157 context ( data . entries . linenumber or " 0 " )
158end
159
160
161
162lines . boxed = { }
163local boxed = lines . boxed
164
165
166
167
168function boxed . register ( configuration )
169 last = last + 1
170 data [ last ] = configuration
171 if trace_numbers then
172 report_lines ( " registering setup %a " , last )
173 end
174 return last
175end
176
177implement {
178 name = " registerlinenumbering " ,
179 actions = { boxed . register , context } ,
180 arguments = {
181 {
182 { " continue " } ,
183 { " start " , " integer " } ,
184 { " step " , " integer " } ,
185 { " method " } ,
186 { " tag " } ,
187 }
188 }
189}
190
191function boxed . setup ( n , configuration )
192 local d = data [ n ]
193 if d then
194 if trace_numbers then
195 report_lines ( " updating setup %a " , n )
196 end
197 for k , v in next , configuration do
198 d [ k ] = v
199 end
200 else
201 if trace_numbers then
202 report_lines ( " registering setup %a (br) " , n )
203 end
204 data [ n ] = configuration
205 end
206 return n
207end
208
209implement {
210 name = " setuplinenumbering " ,
211 actions = boxed . setup ,
212 arguments = {
213 " integer " ,
214 {
215 { " continue " } ,
216 { " start " , " integer " } ,
217 { " step " , " integer " } ,
218 { " method " } ,
219 { " tag " } ,
220 }
221 }
222}
223
224local function check_number ( n , a , skip , sameline )
225 local d = data [ a ]
226 if d then
227 local tag = d . tag or " "
228 local skipflag = 0
229 local s = d . start or 1
230 current_list [ # current_list + 1 ] = { n , s }
231 if sameline then
232 skipflag = 0
233 if trace_numbers then
234 report_lines ( " skipping broken line number %s for setup %a: %s (%s) " , # current_list , a , s , d . continue or v_no )
235 end
236 elseif not skip and s % d . step = = 0 then
237 skipflag , d . start = 1 , s + 1
238 if trace_numbers then
239 report_lines ( " making number %s for setup %a: %s (%s) " , # current_list , a , s , d . continue or v_no )
240 end
241 else
242 skipflag , d . start = 0 , s + 1
243 if trace_numbers then
244 report_lines ( " skipping line number %s for setup %a: %s (%s) " , # current_list , a , s , d . continue or v_no )
245 end
246 end
247 local p = checkline ( n )
248 if p then
249 ctx_makelinenumber ( tag , skipflag , s , p . hsize , p . reverse and 1 or 0 )
250 else
251 report_lines ( " needs checking " )
252 end
253 end
254end
255
256
257
258
259
260
261
262
263
264local function lineisnumbered ( n )
265 local n = getlist ( n )
266 while n do
267 local id = getid ( n )
268 if id = = hlist_code or id = = vlist_code then
269
270 local a = getattr ( n , a_linenumber )
271 if a and a > 0 then
272 return a
273 end
274 elseif id = = glyph_code then
275 local a = getattr ( n , a_linenumber )
276 if a and a > 0 then
277 return a
278 else
279 return false
280 end
281 end
282 n = getnext ( n )
283 end
284end
285
286local function listisnumbered ( list )
287 if list then
288 for n , subtype in nexthlist , list do
289 if subtype = = linelist_code then
290 local a = getattr ( n , a_linenumber )
291 if a then
292
293 return a > 0 and list or false
294 else
295
296 if lineisnumbered ( n ) then
297 return list
298 end
299 end
300 end
301 end
302 end
303end
304
305local function findnumberedlist ( list )
306
307 local n = list
308 while n do
309 local id = getid ( n )
310 if id = = hlist_code then
311 if getsubtype ( n ) = = linelist_code then
312 local a = getattr ( n , a_linenumber )
313 if a then
314 return a > 0 and list
315 end
316 return
317 else
318 local list = getlist ( n )
319 if lineisnumbered ( list ) then
320 return n
321 end
322 local okay = findnumberedlist ( list )
323 if okay then
324 return okay
325 end
326 end
327 elseif id = = vlist_code then
328 local list = getlist ( n )
329 if listisnumbered ( list ) then
330 return list
331 end
332 local okay = findnumberedlist ( list )
333 if okay then
334 return okay
335 end
336 elseif id = = glyph_code then
337 return
338 end
339 n = getnext ( n )
340 end
341end
342
343
344
345
346
347local function findcolumngap ( list )
348
349 local n = list
350 while n do
351 local id = getid ( n )
352 if id = = hlist_code or id = = vlist_code then
353 local p = properties [ n ]
354 if p and p . columngap then
355 if trace_numbers then
356 report_lines ( " first column gap %a " , p . columngap )
357 end
358 return n
359 else
360 local list = getlist ( n )
361 if list then
362 local okay = findcolumngap ( list )
363 if okay then
364 return okay
365 end
366 end
367 end
368 end
369 n = getnext ( n )
370 end
371end
372
373function boxed . stage_one ( n , nested )
374 current_list = { }
375 local box = getbox ( n )
376 if not box then
377 return
378 end
379 local list = getlist ( box )
380 if not list then
381 return
382 end
383 local last_a = nil
384 local last_v = -1
385 local skip = false
386
387 local function check ( )
388 for n , subtype in nexthlist , list do
389 if subtype ~ = linelist_code then
390
391 elseif getheight ( n ) = = 0 and getdepth ( n ) = = 0 then
392
393 else
394 local a = lineisnumbered ( n )
395 if a then
396 if last_a ~ = a then
397 local da = data [ a ]
398 local ma = da . method
399 if ma = = v_next then
400 skip = true
401 elseif ma = = v_page then
402 da . start = 1
403 end
404 last_a = a
405 if trace_numbers then
406 report_lines ( " starting line number range %s: start %s, continue %s " , a , da . start , da . continue or v_no )
407 end
408 end
409 if getattr ( n , a_displaymath ) then
410
411 if is_display_math ( n ) then
412 check_number ( n , a , skip )
413 end
414 else
415
416
417
418
419 check_number ( n , a , skip )
420
421
422
423 end
424 skip = false
425 end
426 end
427 end
428 end
429
430 if nested = = 0 then
431 if list then
432 check ( )
433 end
434 elseif nested = = 1 then
435 local id = getid ( box )
436 if id = = vlist_code then
437 if listisnumbered ( list ) then
438
439 else
440 list = findnumberedlist ( list )
441 end
442 else
443 list = findnumberedlist ( list )
444 end
445 if list then
446 check ( )
447 end
448 elseif nested = = 2 then
449 list = findcolumngap ( list )
450
451 if not list then
452 return
453 end
454 for n in nextvlist , list do
455 local p = properties [ n ]
456 if p and p . columngap then
457 if trace_numbers then
458 report_lines ( " found column gap %a " , p . columngap )
459 end
460 list = getlist ( n )
461 if list then
462 check ( )
463 end
464 end
465 end
466 else
467
468 end
469end
470
471
472
473function boxed . stage_two ( n , m )
474 if # current_list > 0 then
475 m = m or lines . scratchbox
476 local t = { }
477 local tn = 0
478 for l in nexthlist , getlist ( getbox ( m ) ) do
479 tn = tn + 1
480 t [ tn ] = copy_node ( l )
481 end
482 for i = 1 , # current_list do
483 local li = current_list [ i ]
484 local n = li [ 1 ]
485 local m = li [ 2 ]
486 local ti = t [ i ]
487 if ti then
488 addtoline ( n , ti )
489 resolve ( n , m )
490 else
491 report_lines ( " error in linenumbering (1) " )
492 return
493 end
494 end
495 end
496end
497
498
499
500
501
502implement {
503 name = " linenumbersstageone " ,
504 actions = boxed . stage_one ,
505 arguments = { " integer " , " integer " }
506}
507
508implement {
509 name = " linenumbersstagetwo " ,
510 actions = boxed . stage_two ,
511 arguments = { " integer " , " integer " }
512}
513 |