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)
171 local 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
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570function sections.structuredata(depth,key,default,honorcatcodetable)
571 local detail = false
572 if type(depth) == "string" then
573 depth, detail = string.splitup(depth,":")
574 end
575 if depth then
576 depth = levelmap[depth] or tonumber(depth)
577 end
578 if not depth or depth == 0 then
579 depth = data.depth
580 end
581 local useddata
582 if detail == "+" then
583 useddata = structures.lists.collected[#structures.lists.tobesaved+1]
584 else
585 useddata = data.status[depth]
586 end
587 local d
588 if useddata then
589 if find(key,".",1,true) then
590 d = accesstable(key,useddata)
591 else
592 d = useddata.titledata
593 d = d and d[key]
594 end
595 end
596 if d and type(d) ~= "table" then
597 if honorcatcodetable == true or honorcatcodetable == v_auto then
598 local metadata = useddata.metadata
599 local catcodes = metadata and metadata.catcodes
600 if catcodes then
601 ctx_sprint(catcodes,d)
602 else
603 context(d)
604 end
605 elseif not honorcatcodetable or honorcatcodetable == "" then
606 context(d)
607 else
608 local catcodes = catcodenumbers[honorcatcodetable]
609 if catcodes then
610 ctx_sprint(catcodes,d)
611 else
612 context(d)
613 end
614 end
615 elseif default then
616 context(default)
617 end
618end
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637function sections.userdata(depth,key,default)
638 local detail = false
639 if type(depth) == "string" then
640 depth, detail = string.splitup(depth,":")
641 end
642 if depth then
643 depth = levelmap[depth]
644 end
645 if not depth then
646 depth = tonumber(depth)
647 end
648 if not depth or depth == 0 then
649 depth = data.depth
650 end
651 local userdata
652 if detail == "+" then
653 userdata = structures.lists.collected[#structures.lists.tobesaved+1]
654 if userdata then
655 userdata = userdata.userdata
656 end
657 elseif depth > 0 then
658 userdata = data.status[depth]
659 userdata = userdata and userdata.userdata
660 end
661 userdata = (userdata and userdata[key]) or default
662 if userdata then
663 context(userdata)
664 end
665end
666
667function sections.setchecker(name,level,command)
668 data.checkers[name] = (name and command and level >= 0 and { level, command }) or nil
669end
670
671function sections.current()
672 return data.status[data.depth]
673end
674
675local function depthnumber(n)
676 local depth = data.depth
677 if not n or n == 0 then
678 n = depth
679 elseif n < 0 then
680 n = depth + n
681 end
682 return data.numbers[n] or 0
683end
684
685sections.depthnumber = depthnumber
686
687function sections.autodepth(numbers)
688 for i=#numbers,1,-1 do
689 if numbers[i] ~= 0 then
690 return i
691 end
692 end
693 return 0
694end
695
696
697
698function structures.currentsectionnumber()
699 local sc = sections.current()
700 return sc and sc.numberdata
701end
702
703
704
705
706
707
708
709
710
711
712
713
714local function process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
715
716 local number = numbers and (numbers[index] or 0)
717 local ownnumber = ownnumbers and ownnumbers[index] or ""
718 if number > criterium or (ownnumber ~= "") then
719 local block = (entry.block ~= "" and entry.block) or sections.currentblock()
720 if preceding then
721 local separator = sets.get("structure:separators",block,separatorset,preceding,".")
722 if separator then
723 if result then
724 result[#result+1] = strippedprocessor(separator)
725 else
726 applyprocessor(separator)
727 end
728 end
729 preceding = false
730 end
731 if result then
732 if ownnumber ~= "" then
733 result[#result+1] = ownnumber
734 elseif conversion and conversion ~= "" then
735 result[#result+1] = convertnumber(conversion,number,language)
736 else
737 local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
738 result[#result+1] = convertnumber(theconversion,number,language)
739 end
740 else
741 if ownnumber ~= "" then
742 applyprocessor(ownnumber)
743 elseif conversion and conversion ~= "" then
744 ctx_convertnumber(conversion,number)
745 else
746 local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
747 local data = startapplyprocessor(theconversion)
748 ctx_convertnumber(data or "numbers",number)
749 stopapplyprocessor()
750 end
751 end
752 return index, true
753 else
754 return preceding or false, done
755 end
756end
757
758
759
760function sections.typesetnumber(entry,kind,...)
761
762
763
764
765
766 if entry then
767 local separatorset = ""
768 local conversionset = ""
769 local conversion = ""
770 local groupsuffix = ""
771 local stopper = ""
772 local starter = ""
773 local connector = ""
774 local set = ""
775 local segments = ""
776 local criterium = ""
777 local language = ""
778 for d=1,select("#",...) do
779 local data = select(d,...)
780 if data then
781 if separatorset == "" then separatorset = data.separatorset or "" end
782 if conversionset == "" then conversionset = data.conversionset or "" end
783 if conversion == "" then conversion = data.conversion or "" end
784 if groupsuffix == "" then groupsuffix = data.groupsuffix or "" end
785 if stopper == "" then stopper = data.stopper or "" end
786 if starter == "" then starter = data.starter or "" end
787 if connector == "" then connector = data.connector or "" end
788 if set == "" then set = data.set or "" end
789 if segments == "" then segments = data.segments or "" end
790 if criterium == "" then criterium = data.criterium or "" end
791 if language == "" then language = data.language or "" end
792 end
793 end
794 if separatorset == "" then separatorset = "default" end
795 if conversionset == "" then conversionset = "default" end
796 if conversion == "" then conversion = nil end
797 if groupsuffix == "" then groupsuffix = nil end
798 if stopper == "" then stopper = nil end
799 if starter == "" then starter = nil end
800 if connector == "" then connector = nil end
801 if set == "" then set = "default" end
802 if segments == "" then segments = nil end
803 if language == "" then language = nil end
804
805 if criterium == v_strict then
806 criterium = 0
807 elseif criterium == v_positive then
808 criterium = -1
809 elseif criterium == v_all then
810 criterium = -1000000
811 else
812 criterium = 0
813 end
814
815 local firstprefix = 0
816 local lastprefix = 16
817 if segments == v_current then
818 firstprefix = data.depth
819 lastprefix = firstprefix
820 elseif segments then
821 local f, l = match(tostring(segments),"^(.-):(.+)$")
822 if l == "*" or l == v_all then
823 l = 100
824 end
825 if f and l then
826
827 firstprefix = tonumber(f) or sections.getlevel(f) or 0
828 lastprefix = tonumber(l) or sections.getlevel(l) or 100
829 else
830
831 local fl = tonumber(segments) or sections.getlevel(segments)
832 if fl then
833 firstprefix = fl
834 lastprefix = fl
835 end
836 end
837 end
838
839 local numbers = entry.numbers
840 local ownnumbers = entry.ownnumbers
841 if numbers then
842 local done = false
843 local preceding = false
844
845 local result = kind == "direct" and { }
846 if result then
847 connector = false
848 end
849
850 local prefixlist = set and sets.getall("structure:prefixes","",set)
851 if starter then
852 if result then
853 result[#result+1] = strippedprocessor(starter)
854 else
855 applyprocessor(starter)
856 end
857 end
858
859 if prefixlist and (kind == "section" or kind == "prefix" or kind == "direct") then
860
861
862 local b = 1
863 local e = #prefixlist
864 local bb = 0
865 local ee = 0
866
867
868
869 for k=e,b,-1 do
870 local prefix = prefixlist[k]
871 local index = sections.getlevel(prefix) or k
872 if index >= firstprefix and index <= lastprefix then
873 local number = numbers and numbers[index]
874 if number then
875 local ownnumber = ownnumbers and ownnumbers[index] or ""
876 if number > 0 or (ownnumber ~= "") then
877 break
878 else
879 e = k -1
880 end
881 end
882 end
883 end
884
885 for k=b,e do
886 local prefix = prefixlist[k]
887 local index = sections.getlevel(prefix) or k
888 if index >= firstprefix and index <= lastprefix then
889 local number = numbers and numbers[index]
890 if number then
891 local ownnumber = ownnumbers and ownnumbers[index] or ""
892 if number > 0 or (ownnumber ~= "") then
893 if bb == 0 then
894 bb = k
895 end
896 ee = k
897 elseif criterium >= 0 then
898 bb = 0
899 ee = 0
900 end
901 else
902 break
903 end
904 end
905 end
906
907 for k=bb,ee do
908 local prefix = prefixlist[k]
909 local index = sections.getlevel(prefix) or k
910 if index >= firstprefix and index <= lastprefix then
911 preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
912 end
913 end
914 else
915
916 for index=firstprefix,lastprefix do
917 preceding, done = process(index,numbers,ownnumbers,criterium,separatorset,conversion,conversionset,entry,result,preceding,done,language)
918 end
919 end
920
921 if done then
922 if connector and kind == 'prefix' then
923 if result then
924
925 else
926 applyprocessor(connector)
927 end
928 else
929 if groupsuffix and kind ~= "prefix" then
930 if result then
931 result[#result+1] = strippedprocessor(groupsuffix)
932 else
933 applyprocessor(groupsuffix)
934 end
935 end
936 if stopper then
937 if result then
938 result[#result+1] = strippedprocessor(stopper)
939 else
940 applyprocessor(stopper)
941 end
942 end
943 end
944 end
945 return result
946 else
947
948 end
949 end
950end
951
952function sections.title()
953 local sc = sections.current()
954 if sc then
955 helpers.title(sc.titledata.title,sc.metadata)
956 end
957end
958
959function sections.findnumber(depth,what)
960 local data = data.status[depth or data.depth]
961 if not data then
962 return
963 end
964 local references = data.references
965 if not references then
966 return
967 end
968 local index = references.section
969 local collected = sections.collected
970 local sectiondata = collected[index]
971 if sectiondata and sectiondata.hidenumber ~= true then
972 local quit = what == v_previous or what == v_next
973 if what == v_first or what == v_previous then
974 for i=index-1,1,-1 do
975 local s = collected[i]
976 if s then
977 local n = s.numbers
978 if #n == depth and n[depth] and n[depth] ~= 0 then
979 sectiondata = s
980 if quit then
981 break
982 end
983 elseif #n < depth then
984 break
985 end
986 end
987 end
988 elseif what == v_last or what == v_next then
989 for i=index+1,#collected do
990 local s = collected[i]
991 if s then
992 local n = s.numbers
993 if #n == depth and n[depth] and n[depth] ~= 0 then
994 sectiondata = s
995 if quit then
996 break
997 end
998 elseif #n < depth then
999 break
1000 end
1001 end
1002 end
1003 end
1004 return sectiondata
1005 end
1006end
1007
1008function sections.finddata(depth,what)
1009 local data = data.status[depth or data.depth]
1010 if not data then
1011 return
1012 end
1013 local references = data.references
1014 if not references then
1015 return
1016 end
1017 local index = references.listindex
1018 if not index then
1019 return
1020 end
1021 local collected = structures.lists.collected
1022 local quit = what == v_previous or what == v_next
1023 if what == v_first or what == v_previous then
1024 for i=index-1,1,-1 do
1025 local s = collected[i]
1026 if not s then
1027 break
1028 elseif s.metadata.kind == "section" then
1029 local n = s.numberdata.numbers
1030 if #n == depth and n[depth] and n[depth] ~= 0 then
1031 data = s
1032 if quit then
1033 break
1034 end
1035 elseif #n < depth then
1036 break
1037 end
1038 end
1039 end
1040 elseif what == v_last or what == v_next then
1041 for i=index+1,#collected do
1042 local s = collected[i]
1043 if not s then
1044 break
1045 elseif s.metadata.kind == "section" then
1046 local n = s.numberdata.numbers
1047 if #n == depth and n[depth] and n[depth] ~= 0 then
1048 data = s
1049 if quit then
1050 break
1051 end
1052 elseif #n < depth then
1053 break
1054 end
1055 end
1056 end
1057 end
1058 return data
1059end
1060
1061function sections.internalreference(sectionname,what)
1062 local r = type(sectionname) == "number" and sectionname or registered[sectionname]
1063 if r then
1064 local data = sections.finddata(r.level,what)
1065 return data and data.references and data.references.internal
1066 end
1067end
1068
1069function sections.fullnumber(depth,what)
1070 local sectiondata = sections.findnumber(depth,what)
1071 if sectiondata then
1072 sections.typesetnumber(sectiondata,'section',sectiondata)
1073 end
1074end
1075
1076function sections.getnumber(depth,what)
1077 local sectiondata = sections.findnumber(depth,what)
1078 local askednumber = 0
1079 if sectiondata then
1080 local numbers = sectiondata.numbers
1081 if numbers then
1082 askednumber = numbers[depth] or 0
1083 end
1084 end
1085 context(askednumber)
1086end
1087
1088
1089
1090function sections.showstructure()
1091
1092 local tobesaved = structures.lists.tobesaved
1093
1094 if not tobesaved then
1095 return
1096 end
1097
1098 local levels = setmetatableindex("table")
1099 local names = setmetatableindex("table")
1100
1101 report_used()
1102 report_used("sections")
1103 for i=1,#tobesaved do
1104 local si = tobesaved[i]
1105 local md = si.metadata
1106 if md and md.kind == "section" then
1107 local level = md.level
1108 local name = md.name
1109 local numbers = si.numberdata.numbers
1110 local title = si.titledata.title
1111 report_used(" %i : %-10s %-20s %s",level,concat(numbers,"."),name,title)
1112 levels[level][name] = true
1113 names[name][level] = true
1114 end
1115 end
1116 report_used()
1117 report_used("levels")
1118 for level, list in sortedhash(levels) do
1119 report_used(" %s : % t",level,sortedkeys(list))
1120 end
1121 report_used()
1122 report_used("names")
1123 for name, list in sortedhash(names) do
1124 report_used(" %-10s : % t",name,sortedkeys(list))
1125 end
1126 report_used()
1127end
1128
1129
1130
1131local levels = { }
1132
1133local function autonextstructurelevel(level)
1134 if level > #levels then
1135 for i=#levels+1,level do
1136 levels[i] = false
1137 end
1138 else
1139 for i=level,#levels do
1140 if levels[i] then
1141 ctx_finalizeauto()
1142 levels[i] = false
1143 end
1144 end
1145 end
1146 levels[level] = true
1147end
1148
1149local function autofinishstructurelevels()
1150 for i=1,#levels do
1151 if levels[i] then
1152 ctx_finalizeauto()
1153 end
1154 end
1155 levels = { }
1156end
1157
1158implement {
1159 name = "autonextstructurelevel",
1160 actions = autonextstructurelevel,
1161 arguments = "integer",
1162}
1163
1164implement {
1165 name = "autofinishstructurelevels",
1166 actions = autofinishstructurelevels,
1167}
1168
1169
1170
1171implement {
1172 name = "depthnumber",
1173 actions = { depthnumber, context },
1174 arguments = "integer",
1175}
1176
1177implement { name = "structurenumber", actions = sections.fullnumber }
1178implement { name = "structuretitle", actions = sections.title }
1179
1180implement { name = "structurevariable", actions = sections.structuredata, arguments = { false, "string" } }
1181implement { name = "structureuservariable", actions = sections.userdata, arguments = { false, "string" } }
1182implement { name = "structurecatcodedget", actions = sections.structuredata, arguments = { false, "string", false, true } }
1183implement { name = "structuregivencatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "integer" } }
1184implement { name = "structureautocatcodedget", actions = sections.structuredata, arguments = { false, "string", false, "string" } }
1185
1186implement { name = "namedstructurevariable", actions = sections.structuredata, arguments = "2 strings" }
1187implement { name = "namedstructureuservariable", actions = sections.userdata, arguments = "2 strings" }
1188
1189implement { name = "setstructurelevel", actions = sections.setlevel, arguments = "2 strings" }
1190implement { name = "getstructurelevel", actions = sections.getcurrentlevel, arguments = "string" }
1191implement { name = "setstructurenumber", actions = sections.setnumber, arguments = { "integer", "string" } }
1192implement { name = "getstructurenumber", actions = sections.getnumber, arguments = "integer" }
1193implement { name = "getsomestructurenumber", actions = sections.getnumber, arguments = { "integer", "string" } }
1194implement { name = "getfullstructurenumber", actions = sections.fullnumber, arguments = "integer" }
1195implement { name = "getsomefullstructurenumber", actions = sections.fullnumber, arguments = { "integer", "string" } }
1196implement { name = "getspecificstructuretitle", actions = sections.structuredata, arguments = { "string", "'titledata.title'",false,"string" } }
1197
1198implement { name = "reportstructure", actions = sections.reportstructure }
1199implement { name = "showstructure", actions = sections.showstructure }
1200
1201implement {
1202 name = "registersection",
1203 actions = sections.register,
1204 arguments = {
1205 "string",
1206 {
1207 { "coupling" },
1208 { "section" },
1209 { "level", "integer" },
1210 { "parent" },
1211 }
1212 }
1213}
1214
1215implement {
1216 name = "setsectionentry",
1217 actions = sections.setentry,
1218 arguments = {
1219 {
1220 { "references", {
1221 { "internal", "integer" },
1222 { "block" },
1223 { "backreference" },
1224 { "prefix" },
1225 { "reference" },
1226 }
1227 },
1228 { "directives", {
1229 { "resetset" }
1230 }
1231 },
1232 { "metadata", {
1233 { "kind" },
1234 { "name" },
1235 { "catcodes", "integer" },
1236 { "coding" },
1237 { "xmlroot" },
1238 { "xmlsetup" },
1239 { "nolist", "boolean" },
1240 { "increment" },
1241 }
1242 },
1243 { "titledata", {
1244 { "label" },
1245 { "title" },
1246 { "bookmark" },
1247 { "marking" },
1248 { "list" },
1249 { "reference" },
1250 }
1251 },
1252 { "numberdata", {
1253 { "block" },
1254 { "hidenumber", "boolean" },
1255 { "separatorset" },
1256 { "conversionset" },
1257 { "conversion" },
1258 { "starter" },
1259 { "stopper" },
1260 { "set" },
1261 { "segments" },
1262 { "ownnumber" },
1263 { "language" },
1264 { "criterium" },
1265 },
1266 },
1267 { "userdata" },
1268 }
1269 }
1270}
1271
1272
1273
1274implement {
1275 name = "setsectionblock",
1276 actions = sections.setblock,
1277 arguments = { "string", { { "bookmark" } } }
1278}
1279
1280implement {
1281 name = "setinitialsectionblock",
1282 actions = sections.setinitialblock,
1283 arguments = "string",
1284
1285}
1286
1287implement {
1288 name = "pushsectionblock",
1289 actions = sections.pushblock,
1290 arguments = { "string", { { "bookmark" } } }
1291}
1292
1293implement {
1294 name = "popsectionblock",
1295 actions = sections.popblock,
1296}
1297
1298interfaces.implement {
1299 name = "doifelsefirstsectionpage",
1300 arguments = "1 argument",
1301 public = true,
1302 protected = true,
1303 actions = function(name)
1304 local found = false
1305
1306 local list = lists.collected
1307 if list then
1308 local realpage = texgetcount("realpageno")
1309 for i=1,#list do
1310 local listdata = list[i]
1311 local metadata = listdata.metadata
1312 if metadata and metadata.kind == "section" and metadata.name == name then
1313
1314 local current = data.status[metadata.level]
1315 if current and current.references.internal == listdata.references.internal then
1316 found = listdata.references.realpage == realpage
1317 break
1318 end
1319 end
1320 end
1321 end
1322 ctx_doifelse(found)
1323 end,
1324}
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 |