1if not modules then modules = { } end modules ['strc-doc'] = {
2 version = 1.001,
3 comment = "companion to strc-doc.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
14
15
16
17
18local next, type, tonumber, select = next, type, tonumber, select
19local find, match = string.find, string.match
20local concat, fastcopy, insert, remove = table.concat, table.fastcopy, table.insert, table.remove
21local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys
22local max, min = math.max, math.min
23local allocate, mark, accesstable = utilities.storage.allocate, utilities.storage.mark, utilities.tables.accesstable
24local setmetatableindex = table.setmetatableindex
25local lpegmatch, P, C = lpeg.match, lpeg.P, lpeg.C
26
27local catcodenumbers = catcodes.numbers
28local ctxcatcodes = catcodenumbers.ctxcatcodes
29local variables = interfaces.variables
30
31local implement = interfaces.implement
32
33local v_last = variables.last
34local v_first = variables.first
35local v_previous = variables.previous
36local v_next = variables.next
37local v_auto = variables.auto
38local v_strict = variables.strict
39local v_all = variables.all
40local v_positive = variables.positive
41local v_current = variables.current
42
43local texgetcount = tex.getcount
44
45local trace_sectioning = false trackers.register("structures.sectioning", function(v) trace_sectioning = v end)
46local trace_details = false trackers.register("structures.details", function(v) trace_details = v end)
47
48local report_structure = logs.reporter("structure","sectioning")
49local report_used = logs.reporter("structure")
50
51local context = context
52local commands = commands
53local ctx_doifelse = commands.doifelse
54
55local structures = structures
56local helpers = structures.helpers
57local documents = structures.documents
58local sections = structures.sections
59local lists = structures.lists
60local counters = structures.counters
61local sets = structures.sets
62local tags = structures.tags
63
64local processors = typesetters.processors
65local applyprocessor = processors.apply
66local startapplyprocessor = processors.startapply
67local stopapplyprocessor = processors.stopapply
68local strippedprocessor = processors.stripped
69
70local convertnumber = converters.convert
71
72local ctx_convertnumber = context.convertnumber
73local ctx_sprint = context.sprint
74local ctx_finalizeauto = context.finalizeautostructurelevel
75
76
77
78local data
79
80function documents.initialize()
81 data = allocate {
82 numbers = { },
83 forced = { },
84 ownnumbers = { },
85 status = { },
86 checkers = { },
87 depth = 0,
88 blocks = { },
89 block = "",
90 }
91 documents.data = data
92end
93
94function documents.reset()
95 data.numbers = { }
96 data.forced = { }
97 data.ownnumbers = { }
98 data.status = { }
99
100 data.depth = 0
101end
102
103documents.initialize()
104
105
106
107function documents.preset(numbers)
108 local nofnumbers = #numbers
109 local ownnumbers = { }
110 data.numbers = numbers
111 data.ownnumbers = ownnumbers
112 data.depth = nofnumbers
113 for i=1,nofnumbers do
114 ownnumbers[i] = ""
115 end
116 sections.setnumber(nofnumbers,"-1")
117end
118
119
120
121
122
123
124
125local collected = allocate()
126local tobesaved = allocate()
127
128sections.collected = collected
129sections.tobesaved = tobesaved
130
131
132
133
134
135local function initializer()
136 collected = sections.collected
137 tobesaved = sections.tobesaved
138end
139
140job.register('structures.sections.collected', tobesaved, initializer)
141
142local registered = sections.registered or allocate()
143sections.registered = registered
144
145storage.register("structures/sections/registered", registered, "structures.sections.registered")
146
147local function update(name,level,section)
148 for k, v in next, registered do
149 if k ~= name and v.coupling == name then
150 report_structure("updating section level %a to level of %a",k,name)
151 context.doredefinehead(k,name)
152 update(k,level,section)
153 end
154 end
155end
156
157function sections.register(name,specification)
158 registered[name] = specification
159 local level = specification.level
160 local section = specification.section
161 update(name,level,section)
162end
163
164function sections.currentid()
165 return #tobesaved
166end
167
168local lastsaved = 0
169
170function sections.save(sectiondata)
171local sectiondata = helpers.simplify(sectiondata)
172 local numberdata = sectiondata.numberdata
173 local ntobesaved = #tobesaved
174 if not numberdata or sectiondata.metadata.nolist then
175
176 else
177 ntobesaved = ntobesaved + 1
178 tobesaved[ntobesaved] = numberdata
179 if not collected[ntobesaved] then
180 collected[ntobesaved] = numberdata
181 end
182 end
183 lastsaved = ntobesaved
184 return ntobesaved
185end
186
187function sections.currentsectionindex()
188 return lastsaved
189end
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214sections.verbose = true
215
216local sectionblockdata = sections.sectionblockdata or { }
217sections.sectionblockdata = sectionblockdata
218
219local levelmap = sections.levelmap or { }
220sections.levelmap = levelmap
221levelmap.block = -1
222
223storage.register("structures/sections/levelmap", sections.levelmap, "structures.sections.levelmap")
224
225function sections.setlevel(name,level)
226 local l = tonumber(level)
227 if not l then
228 l = levelmap[level]
229 end
230 if l and l > 0 then
231 levelmap[name] = l
232 else
233
234 end
235end
236
237function sections.getlevel(name)
238 return levelmap[name] or 0
239end
240
241table.setmetatableindex(sectionblockdata,"table")
242
243function sections.setblock(name,settings)
244 local block = name or data.block or "unknown"
245 data.block = block
246 sectionblockdata[block] = settings
247 return block
248end
249
250local jobvariables = job.variables
251local pushed_order = { }
252local pushed_done = { }
253
254jobvariables.tobesaved.sectionblockorder = pushed_order
255
256
257
258
259
260function sections.setinitialblock(default)
261 local order = jobvariables.collected.sectionblockorder or pushed_order
262 local name = #order > 0 and order[1] or default or "bodypart"
263 context.setsectionblock { name }
264
265
266end
267
268function sections.pushblock(name,settings)
269 counters.check(0)
270 local block = name or data.block
271 insert(data.blocks,block)
272 data.block = block
273 sectionblockdata[block] = settings
274 documents.reset()
275 if not pushed_done[name] then
276 pushed_done[name] = true
277 local nofpushed = #pushed_order + 1
278 pushed_order[nofpushed] = name
279 end
280 return block
281end
282
283function sections.popblock()
284 local block = remove(data.blocks) or data.block
285 data.block = block
286 documents.reset()
287 return block
288end
289
290local function getcurrentblock()
291 return data.block or data.blocks[#data.blocks] or "unknown"
292end
293
294sections.currentblock = getcurrentblock
295
296function sections.currentlevel()
297 return data.depth
298end
299
300function sections.getcurrentlevel()
301 context(data.depth)
302end
303
304local saveset = { }
305
306function sections.setentry(given)
307
308 local numbers = data.numbers
309
310 local metadata = given.metadata
311 local numberdata = given.numberdata
312 local references = given.references
313 local directives = given.directives
314 local userdata = given.userdata
315
316 if not metadata then
317 metadata = { }
318 given.metadata = metadata
319 end
320 if not numberdata then
321 numberdata = { }
322 given.numberdata = numberdata
323 end
324 if not references then
325 references = { }
326 given.references = references
327 end
328
329 local ownnumbers = data.ownnumbers
330 local forced = data.forced
331 local status = data.status
332 local olddepth = data.depth
333 local givenname = metadata.name
334 local mappedlevel = levelmap[givenname]
335 local newdepth = tonumber(mappedlevel or (olddepth > 0 and olddepth) or 1)
336 local resetset = directives and directives.resetset or ""
337
338
339
340
341 if trace_details then
342 report_structure("name %a, mapped level %a, old depth %a, new depth %a, reset set %a",
343 givenname,mappedlevel,olddepth,newdepth,resetset)
344 end
345 if userdata then
346
347 if userdata.reference and userdata.reference ~= "" then given.metadata.reference = userdata.reference ; userdata.reference = nil end
348 if userdata.ownnumber and userdata.ownnumber ~= "" then given.numberdata.ownnumber = userdata.ownnumber ; userdata.ownnumber = nil end
349 if userdata.title and userdata.title ~= "" then given.titledata.title = userdata.title ; userdata.title = nil end
350 if userdata.bookmark and userdata.bookmark ~= "" then given.titledata.bookmark = userdata.bookmark ; userdata.bookmark = nil end
351 if userdata.label and userdata.label ~= "" then given.titledata.label = userdata.label ; userdata.label = nil end
352 end
353
354 if saveset then
355 saveset[newdepth] = (resetset ~= "" and resetset) or saveset[newdepth] or ""
356 end
357 if newdepth > olddepth then
358 for i=olddepth+1,newdepth do
359 local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
360 if trace_details then
361 report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
362 end
363 if not s or s == 0 then
364 numbers[i] = numbers[i] or 0
365 ownnumbers[i] = ownnumbers[i] or ""
366 else
367 numbers[i] = s - 1
368 ownnumbers[i] = ""
369 end
370 status[i] = { }
371 end
372 elseif newdepth < olddepth then
373 for i=olddepth,newdepth+1,-1 do
374 local s = tonumber(sets.get("structure:resets",data.block,saveset and saveset[i] or resetset,i))
375 if trace_details then
376 report_structure("new depth %s, old depth %s, reset set %a, reset value %a, current %a",olddepth,newdepth,resetset,s,numbers[i])
377 end
378 if not s or s == 0 then
379 numbers[i] = numbers[i] or 0
380 ownnumbers[i] = ownnumbers[i] or ""
381 else
382 numbers[i] = s - 1
383 ownnumbers[i] = ""
384 end
385 status[i] = nil
386 end
387 end
388 counters.check(newdepth)
389 ownnumbers[newdepth] = numberdata.ownnumber or ""
390 numberdata.ownnumber = nil
391 data.depth = newdepth
392
393 olddepth = newdepth
394 if metadata.increment then
395 local oldn = numbers[newdepth] or 0
396 local newn = 0
397 local fd = forced[newdepth]
398 if fd then
399 if fd[1] == "add" then
400 newn = oldn + fd[2] + 1
401 else
402 newn = fd[2] + 1
403 end
404 if newn < 0 then
405 newn = 1
406 end
407 forced[newdepth] = nil
408 if trace_details then
409 report_structure("old depth %a, new depth %a, old n %a, new n %a, forced %t",olddepth,newdepth,oldn,newn,fd)
410 end
411 else
412 newn = oldn + 1
413 if trace_details then
414 report_structure("old depth %a, new depth %a, old n %a, new n %a, increment",olddepth,newdepth,oldn,newn)
415 end
416 end
417 numbers[newdepth] = newn
418 end
419 status[newdepth] = given or { }
420 for k, v in next, data.checkers do
421 if v[1] == newdepth and v[2] then
422 v[2](k)
423 end
424 end
425 numberdata.numbers = { unpack(numbers,1,newdepth) }
426 if not numberdata.block then
427 numberdata.block = getcurrentblock()
428 end
429 if #ownnumbers > 0 then
430 numberdata.ownnumbers = fastcopy(ownnumbers)
431 end
432 if trace_details then
433 report_structure("name %a, numbers % a, own numbers % a",givenname,numberdata.numbers,numberdata.ownnumbers)
434 end
435 if not references.block then
436 references.block = getcurrentblock()
437 end
438 local tag = references.tag or tags.getid(metadata.kind,metadata.name)
439 if tag and tag ~= "" and tag ~= "?" then
440 references.tag = tag
441 end
442 local setcomponent = structures.references.setcomponent
443 if setcomponent then
444 setcomponent(given)
445 end
446 references.section = sections.save(given)
447
448end
449
450function sections.reportstructure()
451 if sections.verbose then
452 local numbers = data.numbers
453 local ownnumbers = data.ownnumbers
454 local status = data.status
455 local depth = data.depth
456 local d = status[depth]
457 local o = concat(ownnumbers,".",1,depth)
458 local n = (numbers and concat(numbers,".",1,min(depth,#numbers))) or 0
459 local t = d.titledata.title
460 local l = t or ""
461 local t = (l ~= "" and l) or t or "[no title]"
462 local m = d.metadata.name
463 if o and not find(o,"^%.*$") then
464 report_structure("%s @ level %i : (%s) %s -> %s",m,depth,n,o,t)
465 elseif d.directives and d.directives.hidenumber then
466 report_structure("%s @ level %i : (%s) -> %s",m,depth,n,t)
467 else
468 report_structure("%s @ level %i : %s -> %s",m,depth,n,t)
469 end
470 end
471end
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486function sections.setnumber(depth,n)
487 data.forced[depth or data.depth] = {
488 type(n) == "string" and find(n,"^[%+%-]") and "add" or "set",
489 tonumber(n) or 0
490 }
491end
492
493function sections.numberatdepth(depth)
494 return data.numbers[tonumber(depth) or sections.getlevel(depth) or 0] or 0
495end
496
497function sections.numbers()
498 return data.numbers
499end
500
501function sections.matchingtilldepth(depth,numbers,parentnumbers)
502 local dn = parentnumbers or data.numbers
503 local ok = false
504 for i=1,depth do
505 if dn[i] == numbers[i] then
506 ok = true
507 else
508 return false
509 end
510 end
511 return ok
512end
513
514function sections.getnumber(depth)
515 context(data.numbers[depth] or 0)
516end
517
518function sections.set(key,value)
519 data.status[data.depth][key] = value
520end
521
522function sections.cct()
523 local metadata = data.status[data.depth].metadata
524 context(metadata and metadata.catcodes or ctxcatcodes)
525end
526
527
528
529function sections.structuredata(depth,key,default,honorcatcodetable)
530 if depth then
531 depth = levelmap[depth] or tonumber(depth)
532 end
533 if not depth or depth == 0 then
534 depth = data.depth
535 end
536 local data = data.status[depth]
537 local d
538 if data then
539 if find(key,".",1,true) then
540 d = accesstable(key,data)
541 else
542 d = data.titledata
543 d = d and d[key]
544 end
545 end
546 if d and type(d) ~= "table" then
547 if honorcatcodetable == true or honorcatcodetable == v_auto then
548 local metadata = data.metadata
549 local catcodes = metadata and metadata.catcodes
550 if catcodes then
551 ctx_sprint(catcodes,d)
552 else
553 context(d)
554 end
555 elseif not honorcatcodetable or honorcatcodetable == "" then
556 context(d)
557 else
558 local catcodes = catcodenumbers[honorcatcodetable]
559 if catcodes then
560 ctx_sprint(catcodes,d)
561 else
562 context(d)
563 end
564 end
565 elseif default then
566 context(default)
567 end
568end
569
570function sections.userdata(depth,key,default)
571 if depth then
572 depth = levelmap[depth] or tonumber(depth)
573 end
574 if not depth or depth == 0 then
575 depth = data.depth
576 end
577 if depth > 0 then
578 local userdata = data.status[depth]
579 userdata = userdata and userdata.userdata
580 userdata = (userdata and userdata[key]) or default
581 if userdata then
582 context(userdata)
583 end
584 end
585end
586
587function sections.setchecker(name,level,command)
588 data.checkers[name] = (name and command and level >= 0 and { level, command }) or nil
589end
590
591function sections.current()
592 return data.status[data.depth]
593end
594
595local function depthnumber(n)
596 local depth = data.depth
597 if not n or n == 0 then
598 n = depth
599 elseif n < 0 then
600 n = depth + n
601 end
602 return data.numbers[n] or 0
603end
604
605sections.depthnumber = depthnumber
606
607function sections.autodepth(numbers)
608 for i=#numbers,1,-1 do
609 if numbers[i] ~= 0 then
610 return i
611 end
612 end
613 return 0
614end
615
616
617
618function structures.currentsectionnumber()
619 local sc = sections.current()
620 return sc and sc.numberdata
621end
622
623
624
625
626
627
628
629
630
631
632
633
634local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
635
636 local number = numbers and (numbers[index] or 0)
637 local ownnumber = ownnumbers and ownnumbers[index] or ""
638 if number > criterium or (ownnumber ~= "") then
639 local block = (entry.block ~= "" and entry.block) or sections.currentblock()
640 if preceding then
641 local separator = sets.get("structure:separators",block,separatorset,preceding,".")
642 if separator then
643 if result then
644 result[#result+1] = strippedprocessor(separator)
645 else
646 applyprocessor(separator)
647 end
648 end
649 preceding = false
650 end
651 if result then
652 if ownnumber ~= "" then
653 result[#result+1] = ownnumber
654 elseif conversion and conversion ~= "" then
655 result[#result+1] = convertnumber(conversion,number,language)
656 else
657 local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
658 result[#result+1] = convertnumber(theconversion,number,language)
659 end
660 else
661 if ownnumber ~= "" then
662 applyprocessor(ownnumber)
663 elseif conversion and conversion ~= "" then
664 ctx_convertnumber(conversion,number)
665 else
666 local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
667 local data = startapplyprocessor(theconversion)
668 ctx_convertnumber(data or "numbers",number)
669 stopapplyprocessor()
670 end
671 end
672 return index, true
673 else
674 return preceding or false, done
675 end
676end
677
678
679
680function sections.typesetnumber(entry,kind,...)
681
682
683
684
685
686 if entry then
687 local separatorset = ""
688 local conversionset = ""
689 local conversion = ""
690 local groupsuffix = ""
691 local stopper = ""
692 local starter = ""
693 local connector = ""
694 local set = ""
695 local segments = ""
696 local criterium = ""
697 local language = ""
698 for d=1,select("#",...) do
699 local data = select(d,...)
700 if data then
701 if separatorset == "" then separatorset = data.separatorset or "" end
702 if conversionset == "" then conversionset = data.conversionset or "" end
703 if conversion == "" then conversion = data.conversion or "" end
704 if groupsuffix == "" then groupsuffix = data.groupsuffix or "" end
705 if stopper == "" then stopper = data.stopper or "" end
706 if starter == "" then starter = data.starter or "" end
707 if connector == "" then connector = data.connector or "" end
708 if set == "" then set = data.set or "" end
709 if segments == "" then segments = data.segments or "" end
710 if criterium == "" then criterium = data.criterium or "" end
711 if language == "" then language = data.language or "" end
712 end
713 end
714 if separatorset == "" then separatorset = "default" end
715 if conversionset == "" then conversionset = "default" end
716 if conversion == "" then conversion = nil end
717 if groupsuffix == "" then groupsuffix = nil end
718 if stopper == "" then stopper = nil end
719 if starter == "" then starter = nil end
720 if connector == "" then connector = nil end
721 if set == "" then set = "default" end
722 if segments == "" then segments = nil end
723 if language == "" then language = nil end
724
725 if criterium == v_strict then
726 criterium = 0
727 elseif criterium == v_positive then
728 criterium = -1
729 elseif criterium == v_all then
730 criterium = -1000000
731 else
732 criterium = 0
733 end
734
735 local firstprefix = 0
736 local lastprefix = 16
737 if segments == v_current then
738 firstprefix = data.depth
739 lastprefix = firstprefix
740 elseif segments then
741 local f, l = match(tostring(segments),"^(.-):(.+)$")
742 if l == "*" or l == v_all then
743 l = 100
744 end
745 if f and l then
746
747 firstprefix = tonumber(f) or sections.getlevel(f) or 0
748 lastprefix = tonumber(l) or sections.getlevel(l) or 100
749 else
750
751 local fl = tonumber(segments) or sections.getlevel(segments)
752 if fl then
753 firstprefix = fl
754 lastprefix = fl
755 end
756 end
757 end
758
759 local numbers = entry.numbers
760 local ownnumbers = entry.ownnumbers
761 if numbers then
762 local done = false
763 local preceding = false
764
765 local result = kind == "direct" and { }
766 if result then
767 connector = false
768 end
769
770 local prefixlist = set and sets.getall("structure:prefixes","",set)
771 if starter then
772 if result then
773 result[#result+1] = strippedprocessor(starter)
774 else
775 applyprocessor(starter)
776 end
777 end
778
779 if prefixlist and (kind == "section" or kind == "prefix" or kind == "direct") then
780
781
782 local b = 1
783 local e = #prefixlist
784 local bb = 0
785 local ee = 0
786
787
788
789 for k=e,b,-1 do
790 local prefix = prefixlist[k]
791 local index = sections.getlevel(prefix) or k
792 if index >= firstprefix and index <= lastprefix then
793 local number = numbers and numbers[index]
794 if number then
795 local ownnumber = ownnumbers and ownnumbers[index] or ""
796 if number > 0 or (ownnumber ~= "") then
797 break
798 else
799 e = k -1
800 end
801 end
802 end
803 end
804
805 for k=b,e do
806 local prefix = prefixlist[k]
807 local index = sections.getlevel(prefix) or k
808 if index >= firstprefix and index <= lastprefix then
809 local number = numbers and numbers[index]
810 if number then
811 local ownnumber = ownnumbers and ownnumbers[index] or ""
812 if number > 0 or (ownnumber ~= "") then
813 if bb == 0 then
814 bb = k
815 end
816 ee = k
817 elseif criterium >= 0 then
818 bb = 0
819 ee = 0
820 end
821 else
822 break
823 end
824 end
825 end
826
827 for k=bb,ee do
828 local prefix = prefixlist[k]
829 local index = sections.getlevel(prefix) or k
830 if index >= firstprefix and index <= lastprefix then
831 preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
832 end
833 end
834 else
835
836 for index=firstprefix,lastprefix do
837 preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
838 end
839 end
840
841 if done then
842 if connector and kind == 'prefix' then
843 if result then
844
845 else
846 applyprocessor(connector)
847 end
848 else
849 if groupsuffix and kind ~= "prefix" then
850 if result then
851 result[#result+1] = strippedprocessor(groupsuffix)
852 else
853 applyprocessor(groupsuffix)
854 end
855 end
856 if stopper then
857 if result then
858 result[#result+1] = strippedprocessor(stopper)
859 else
860 applyprocessor(stopper)
861 end
862 end
863 end
864 end
865 return result
866 else
867
868 end
869 end
870end
871
872function sections.title()
873 local sc = sections.current()
874 if sc then
875 helpers.title(sc.titledata.title,sc.metadata)
876 end
877end
878
879function sections.findnumber(depth,what)
880 local data = data.status[depth or data.depth]
881 if not data then
882 return
883 end
884 local references = data.references
885 if not references then
886 return
887 end
888 local index = references.section
889 local collected = sections.collected
890 local sectiondata = collected[index]
891 if sectiondata and sectiondata.hidenumber ~= true then
892 local quit = what == v_previous or what == v_next
893 if what == v_first or what == v_previous then
894 for i=index-1,1,-1 do
895 local s = collected[i]
896 if s then
897 local n = s.numbers
898 if #n == depth and n[depth] and n[depth] ~= 0 then
899 sectiondata = s
900 if quit then
901 break
902 end
903 elseif #n < depth then
904 break
905 end
906 end
907 end
908 elseif what == v_last or what == v_next then
909 for i=index+1,#collected do
910 local s = collected[i]
911 if s then
912 local n = s.numbers
913 if #n == depth and n[depth] and n[depth] ~= 0 then
914 sectiondata = s
915 if quit then
916 break
917 end
918 elseif #n < depth then
919 break
920 end
921 end
922 end
923 end
924 return sectiondata
925 end
926end
927
928function sections.finddata(depth,what)
929 local data = data.status[depth or data.depth]
930 if not data then
931 return
932 end
933 local references = data.references
934 if not references then
935 return
936 end
937 local index = references.listindex
938 if not index then
939 return
940 end
941 local collected = structures.lists.collected
942 local quit = what == v_previous or what == v_next
943 if what == v_first or what == v_previous then
944 for i=index-1,1,-1 do
945 local s = collected[i]
946 if not s then
947 break
948 elseif s.metadata.kind == "section" then
949 local n = s.numberdata.numbers
950 if #n == depth and n[depth] and n[depth] ~= 0 then
951 data = s
952 if quit then
953 break
954 end
955 elseif #n < depth then
956 break
957 end
958 end
959 end
960 elseif what == v_last or what == v_next then
961 for i=index+1,#collected do
962 local s = collected[i]
963 if not s then
964 break
965 elseif s.metadata.kind == "section" then
966 local n = s.numberdata.numbers
967 if #n == depth and n[depth] and n[depth] ~= 0 then
968 data = s
969 if quit then
970 break
971 end
972 elseif #n < depth then
973 break
974 end
975 end
976 end
977 end
978 return data
979end
980
981function sections.internalreference(sectionname,what)
982 local r = type(sectionname) == "number" and sectionname or registered[sectionname]
983 if r then
984 local data = sections.finddata(r.level,what)
985 return data and data.references and data.references.internal
986 end
987end
988
989function sections.fullnumber(depth,what)
990 local sectiondata = sections.findnumber(depth,what)
991 if sectiondata then
992 sections.typesetnumber(sectiondata,'section',sectiondata)
993 end
994end
995
996function sections.getnumber(depth,what)
997 local sectiondata = sections.findnumber(depth,what)
998 local askednumber = 0
999 if sectiondata then
1000 local numbers = sectiondata.numbers
1001 if numbers then
1002 askednumber = numbers[depth] or 0
1003 end
1004 end
1005 context(askednumber)
1006end
1007
1008
1009
1010function sections.showstructure()
1011
1012 local tobesaved = structures.lists.tobesaved
1013
1014 if not tobesaved then
1015 return
1016 end
1017
1018 local levels = setmetatableindex("table")
1019 local names = setmetatableindex("table")
1020
1021 report_used()
1022 report_used("sections")
1023 for i=1,#tobesaved do
1024 local si = tobesaved[i]
1025 local md = si.metadata
1026 if md and md.kind == "section" then
1027 local level = md.level
1028 local name = md.name
1029 local numbers = si.numberdata.numbers
1030 local title = si.titledata.title
1031 report_used(" %i : %-10s %-20s %s",level,concat(numbers,"."),name,title)
1032 levels[level][name] = true
1033 names[name][level] = true
1034 end
1035 end
1036 report_used()
1037 report_used("levels")
1038 for level, list in sortedhash(levels) do
1039 report_used(" %s : % t",level,sortedkeys(list))
1040 end
1041 report_used()
1042 report_used("names")
1043 for name, list in sortedhash(names) do
1044 report_used(" %-10s : % t",name,sortedkeys(list))
1045 end
1046 report_used()
1047end
1048
1049
1050
1051local levels = { }
1052
1053local function autonextstructurelevel(level)
1054 if level > #levels then
1055 for i=#levels+1,level do
1056 levels[i] = false
1057 end
1058 else
1059 for i=level,#levels do
1060 if levels[i] then
1061 ctx_finalizeauto()
1062 levels[i] = false
1063 end
1064 end
1065 end
1066 levels[level] = true
1067end
1068
1069local function autofinishstructurelevels()
1070 for i=1,#levels do
1071 if levels[i] then
1072 ctx_finalizeauto()
1073 end
1074 end
1075 levels = { }
1076end
1077
1078implement {
1079 name = "autonextstructurelevel",
1080 actions = autonextstructurelevel,
1081 arguments = "integer",
1082}
1083
1084implement {
1085 name = "autofinishstructurelevels",
1086 actions = autofinishstructurelevels,
1087}
1088
1089
1090
1091implement {
1092 name = "depthnumber",
1093 actions = { depthnumber, context },
1094 arguments = "integer",
1095}
1096
1097implement { name = "structurenumber", actions = sections.fullnumber }
1098implement { name = "structuretitle", actions = sections.title }
1099
1100implement { name = "structurevariable", actions = sections.structuredata, arguments = { false, "string" } }
1101implement { name = "structureuservariable", actions = sections.userdata, arguments = { false, "string" } }
1102implement { name = "structurecatcodedget", actions = sections.structuredata, arguments = { false, "string", false, true } }
1103implement { name = "structuregivencatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "integer" } }
1104implement { name = "structureautocatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "string" } }
1105
1106implement { name = "namedstructurevariable", actions = sections.structuredata, arguments = "2 strings" }
1107implement { name = "namedstructureuservariable", actions = sections.userdata, arguments = "2 strings" }
1108
1109implement { name = "setstructurelevel", actions = sections.setlevel, arguments = "2 strings" }
1110implement { name = "getstructurelevel", actions = sections.getcurrentlevel, arguments = "string" }
1111implement { name = "setstructurenumber", actions = sections.setnumber, arguments = { "integer", "string" } }
1112implement { name = "getstructurenumber", actions = sections.getnumber, arguments = "integer" }
1113implement { name = "getsomestructurenumber", actions = sections.getnumber, arguments = { "integer", "string" } }
1114implement { name = "getfullstructurenumber", actions = sections.fullnumber, arguments = "integer" }
1115implement { name = "getsomefullstructurenumber", actions = sections.fullnumber, arguments = { "integer", "string" } }
1116implement { name = "getspecificstructuretitle", actions = sections.structuredata, arguments = { "string", "'titledata.title'",false,"string" } }
1117
1118implement { name = "reportstructure", actions = sections.reportstructure }
1119implement { name = "showstructure", actions = sections.showstructure }
1120
1121implement {
1122 name = "registersection",
1123 actions = sections.register,
1124 arguments = {
1125 "string",
1126 {
1127 { "coupling" },
1128 { "section" },
1129 { "level", "integer" },
1130 { "parent" },
1131 }
1132 }
1133}
1134
1135implement {
1136 name = "setsectionentry",
1137 actions = sections.setentry,
1138 arguments = {
1139 {
1140 { "references", {
1141 { "internal", "integer" },
1142 { "block" },
1143 { "backreference" },
1144 { "prefix" },
1145 { "reference" },
1146 }
1147 },
1148 { "directives", {
1149 { "resetset" }
1150 }
1151 },
1152 { "metadata", {
1153 { "kind" },
1154 { "name" },
1155 { "catcodes", "integer" },
1156 { "coding" },
1157 { "xmlroot" },
1158 { "xmlsetup" },
1159 { "nolist", "boolean" },
1160 { "increment" },
1161 }
1162 },
1163 { "titledata", {
1164 { "label" },
1165 { "title" },
1166 { "bookmark" },
1167 { "marking" },
1168 { "list" },
1169 { "reference" },
1170 }
1171 },
1172 { "numberdata", {
1173 { "block" },
1174 { "hidenumber", "boolean" },
1175 { "separatorset" },
1176 { "conversionset" },
1177 { "conversion" },
1178 { "starter" },
1179 { "stopper" },
1180 { "set" },
1181 { "segments" },
1182 { "ownnumber" },
1183 { "language" },
1184 { "criterium" },
1185 },
1186 },
1187 { "userdata" },
1188 }
1189 }
1190}
1191
1192
1193
1194implement {
1195 name = "setsectionblock",
1196 actions = sections.setblock,
1197 arguments = { "string", { { "bookmark" } } }
1198}
1199
1200implement {
1201 name = "setinitialsectionblock",
1202 actions = sections.setinitialblock,
1203 arguments = "string",
1204
1205}
1206
1207implement {
1208 name = "pushsectionblock",
1209 actions = sections.pushblock,
1210 arguments = { "string", { { "bookmark" } } }
1211}
1212
1213implement {
1214 name = "popsectionblock",
1215 actions = sections.popblock,
1216}
1217
1218interfaces.implement {
1219 name = "doifelsefirstsectionpage",
1220 arguments = "1 argument",
1221 public = true,
1222 protected = true,
1223 actions = function(name)
1224 local found = false
1225
1226 local list = lists.collected
1227 if list then
1228 local realpage = texgetcount("realpageno")
1229 for i=1,#list do
1230 local listdata = list[i]
1231 local metadata = listdata.metadata
1232 if metadata and metadata.kind == "section" and metadata.name == name then
1233
1234 local current = data.status[metadata.level]
1235 if current and current.references.internal == listdata.references.internal then
1236 found = listdata.references.realpage == realpage
1237 break
1238 end
1239 end
1240 end
1241 end
1242 ctx_doifelse(found)
1243 end,
1244}
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294 |