1if not modules then modules = { } end modules ['strc-lst'] = {
2 version = 1.001,
3 comment = "companion to strc-lst.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 tonumber, type, next = tonumber, type, next
19local concat, insert, remove, sort = table.concat, table.insert, table.remove, table.sort
20local lpegmatch = lpeg.match
21
22local setmetatableindex = table.setmetatableindex
23local sortedkeys = table.sortedkeys
24
25local settings_to_set = utilities.parsers.settings_to_set
26local allocate = utilities.storage.allocate
27local checked = utilities.storage.checked
28
29local trace_lists = false trackers.register("structures.lists", function(v) trace_lists = v end)
30
31local report_lists = logs.reporter("structure","lists")
32
33local context = context
34local commands = commands
35local implement = interfaces.implement
36local conditionals = tex.conditionals
37
38local ctx_latelua = context.latelua
39
40
41local cheat = false
42
43local structures = structures
44local lists = structures.lists
45local sections = structures.sections
46local helpers = structures.helpers
47local documents = structures.documents
48local tags = structures.tags
49local counters = structures.counters
50local references = structures.references
51
52local collected = allocate()
53local tobesaved = allocate()
54local cached = allocate()
55local pushed = allocate()
56local kinds = allocate()
57local names = allocate()
58
59lists.collected = collected
60lists.tobesaved = tobesaved
61
62lists.enhancers = lists.enhancers or { }
63
64lists.ordered = allocate(lists.ordered or { })
65lists.cached = cached
66lists.pushed = pushed
67lists.kinds = kinds
68lists.names = names
69
70local sorters = sorters
71local sortstripper = sorters.strip
72local sortsplitter = sorters.splitters.utf
73local sortcomparer = sorters.comparers.basic
74
75local sectionblocks = allocate()
76lists.sectionblocks = sectionblocks
77
78references.specials = references.specials or { }
79
80local matchingtilldepth = sections.matchingtilldepth
81local numberatdepth = sections.numberatdepth
82local getsectionlevel = sections.getlevel
83local typesetnumber = sections.typesetnumber
84local autosectiondepth = sections.autodepth
85
86local variables = interfaces.variables
87
88local v_all <const> = variables.all
89local v_reference <const> = variables.reference
90local v_title <const> = variables.title
91local v_command <const> = variables.command
92local v_text <const> = variables.text
93local v_current <const> = variables.current
94local v_previous <const> = variables.previous
95local v_intro <const> = variables.intro
96local v_here <const> = variables.here
97local v_component <const> = variables.component
98local v_product <const> = variables.product
99local v_file <const> = variables.file
100local v_local <const> = variables["local"]
101local v_default <const> = variables.default
102
103local cheats = {
104 [variables.fit] = true,
105 [variables.tight] = true,
106}
107
108local function zerostrippedconcat(t,separator)
109 local f = 1
110 local l = #t
111 for i=f,l do
112 if t[i] == 0 then
113 f = f + 1
114 end
115 end
116 for i=l,f,-1 do
117 if t[i] == 0 then
118 l = l - 1
119 end
120 end
121 return concat(t,separator,f,l)
122end
123
124
125
126local reordered = { } do
127
128 local function addlevel(t,k)
129 local v = { }
130 setmetatableindex(v,function(t,k)
131 local v = { }
132 t[k] = v
133 return v
134 end)
135 t[k] = v
136 return v
137 end
138
139 local function reorder(kind,names)
140
141 local sublists = setmetatableindex({ },addlevel)
142 local collected = lists.collected or { }
143
144 for i=1,#collected do
145 local entry = collected[i]
146 local metadata = entry.metadata
147 if metadata then
148 local name = metadata.name
149
150
151 if name and metadata.kind == kind and names[name] then
152 local numberdata = entry.numberdata
153 if numberdata then
154 local references = entry.references
155 if references then
156 local internal = references.internal
157 if internal then
158 local sublist = sublists[kind][name]
159numberdata = table.fastcopy(numberdata)
160
161 sublist[#sublist + 1] = { internal, numberdata, entry }
162 end
163 end
164 end
165 end
166 end
167 end
168
169
170
171 for _, sublist in next, sublists do
172 for _, v in next, sublist do
173 local tmp = { }
174 for i=1,#v do
175 tmp[i] = v[i]
176 end
177 sort(tmp,function(a,b) return a[1] < b[1] end)
178 for i=1,#tmp do
179 local vi = v[i]
180 local numberdata = tmp[i][2]
181 vi[3].numberdata = numberdata
182 reordered[vi[1]] = numberdata
183 end
184 end
185 end
186
187 end
188
189 local done = { }
190
191 function lists.reorder(kind,names)
192 if names then
193
194
195
196 local todo = { }
197 for i=1,#names do
198 local name = names[i]
199 if not done[name] then
200 todo[name] = true
201 done[name] = true
202 end
203 end
204 if next(todo) then
205 reorder(kind,todo)
206 end
207 end
208 end
209
210 function lists.reordered(data)
211
212
213 return data.numberdata
214 end
215
216 implement {
217 name = "reorderfloats",
218 public = true,
219 protected = true,
220 actions = function(names)
221 lists.reorder("float",names)
222 end,
223 arguments = "array",
224 }
225
226end
227
228local function initializer()
229
230
231 local collected = lists.collected
232 local internals = checked(references.internals)
233 local ordered = lists.ordered
234 local usedinternals = references.usedinternals
235 local blockdone = { }
236 local lastblock = nil
237 for i=1,#collected do
238 local c = collected[i]
239 local m = c.metadata
240 local r = c.references
241 if m then
242
243 if r then
244 local internal = r.internal
245 if internal then
246 internals[internal] = c
247 usedinternals[internal] = r.used
248 end
249 local block = r.block
250 if not block then
251
252 elseif lastblock == block then
253
254 elseif lastblock then
255 if blockdone[block] then
256 if trace_lists then
257 report_lists("out of order sectionsblocks, maybe use \\setsectionblock")
258 end
259 else
260 blockdone[block] = true
261 sectionblocks[#sectionblocks+1] = block
262 end
263 lastblock = block
264 elseif not blockdone[block] then
265 blockdone[block] = true
266 sectionblocks[#sectionblocks+1] = block
267 lastblock = block
268 end
269 end
270
271 local kind = m.kind
272 local name = m.name
273 if kind and name then
274 local ok = ordered[kind]
275 if ok then
276 local on = ok[name]
277 if on then
278 on[#on+1] = c
279 else
280 ok[name] = { c }
281 end
282 else
283 ordered[kind] = { [name] = { c } }
284 end
285 kinds[kind] = true
286 names[name] = true
287 elseif kind then
288 kinds[kind] = true
289 elseif name then
290 names[name] = true
291 end
292 end
293 if r then
294 r.listindex = i
295 end
296 end
297end
298
299local function finalizer()
300 local flaginternals = references.flaginternals
301 local usedviews = references.usedviews
302 for i=1,#tobesaved do
303 local r = tobesaved[i].references
304 if r then
305 local i = r.internal
306 local f = flaginternals[i]
307 local v = usedviews[i]
308 if cheat and v and cheats[v] then
309
310 r.view = v
311 end
312 if f then
313 r.used = v or true
314 end
315 end
316 end
317end
318
319job.register('structures.lists.collected', tobesaved, initializer, finalizer)
320
321local groupindices = setmetatableindex("table")
322
323function lists.groupindex(name,group)
324 local groupindex = groupindices[name]
325 return groupindex and groupindex[group] or 0
326end
327
328
329
330function lists.addto(t)
331 local metadata = t.metadata
332 local userdata = t.userdata
333 local numberdata = t.numberdata
334 if userdata and type(userdata) == "string" then
335 t.userdata = helpers.touserdata(userdata)
336 end
337 if not metadata.level then
338 metadata.level = structures.sections.currentlevel()
339 end
340
341
342
343
344
345
346
347
348 if numberdata then
349 local numbers = numberdata.numbers
350 if type(numbers) == "string" then
351 counters.compact(numberdata,numbers,numberdata.level)
352 end
353 end
354 local group = numberdata and numberdata.group
355 local name = metadata.name
356 local kind = metadata.kind
357 if not group then
358
359 elseif group == "" then
360 group, numberdata.group = nil, nil
361 else
362 local groupindex = groupindices[name][group]
363 if groupindex then
364 numberdata.numbers = cached[groupindex].numberdata.numbers
365 end
366 end
367
368
369
370
371
372
373 local r = t.references
374 local i = r and r.internal or 0
375 if r then
376 if not r.section then
377 r.section = structures.sections.currentid()
378 end
379 if not r.structure then
380 r.structure = resolvers.jobs.currentstructure()
381 end
382 local b = r and t.block
383 if not b then
384 local s = r.section
385 if s then
386 s = structures.sections.tobesaved[s]
387 r.block = s and s.block or nil
388 end
389 end
390 if kind and name then
391 local tag = tags.getid(kind,name)
392 if tag and tag ~= "?" then
393 r.tag = tag
394 end
395 end
396 end
397 local p = pushed[i]
398 if not p then
399 p = #cached + 1
400 cached[p] = helpers.simplify(t)
401 pushed[i] = p
402 if r then
403 r.listindex = p
404 end
405 end
406 if group then
407 groupindices[name][group] = p
408 end
409 if trace_lists then
410 report_lists("added %a, internal %a",name,p)
411 end
412 return p
413end
414
415function lists.discard(n)
416 n = tonumber(n)
417 if not n then
418
419 elseif n == #cached then
420 cached[n] = nil
421 n = n - 1
422 while n > 0 and cached[n] == false do
423 cached[n] = nil
424 n = n - 1
425 end
426 else
427 cached[n] = false
428 end
429end
430
431function lists.iscached(n)
432 return cached[tonumber(n)]
433end
434
435
436
437local enhanced = { }
438
439local synchronizepage = function(r)
440 synchronizepage = references.synchronizepage
441 return synchronizepage(r)
442end
443
444local function enhancelist(specification)
445 local n = specification.n
446 local l = cached[n]
447 if not l then
448 report_lists("enhancing %a, unknown internal",n)
449 elseif enhanced[n] then
450 if trace_lists then
451 report_lists("enhancing %a, name %a, duplicate ignored",n,name)
452 end
453 else
454 local metadata = l.metadata
455 local references = l.references
456
457 l.directives = nil
458
459 lists.tobesaved[#lists.tobesaved+1] = l
460
461 synchronizepage(references)
462
463 local kind = metadata.kind
464 local name = metadata.name
465 if trace_lists then
466 report_lists("enhancing %a, name %a, page %a",n,name,references.realpage or 0)
467 end
468
469
470
471
472
473
474
475
476 local enhancer = kind and lists.enhancers[kind]
477 if enhancer then
478 enhancer(l)
479 end
480
481 enhanced[n] = true
482 return l
483 end
484end
485
486lists.enhance = enhancelist
487
488
489
490local nesting = { }
491
492function lists.pushnesting(i)
493 local result = lists.result
494 local parent = result[i]
495 local name = parent.metadata.name
496 local numberdata = parent.numberdata
497 local numbers = numberdata and numberdata.numbers
498 local number = numbers and numbers[getsectionlevel(name)] or 0
499 insert(nesting, {
500 number = number,
501 name = name,
502 result = result,
503 parent = parent
504 })
505end
506
507function lists.popnesting()
508 local old = remove(nesting)
509 if old then
510 lists.result = old.result
511 else
512 report_lists("nesting error")
513 end
514end
515
516
517
518
519local splitter = lpeg.splitat(":")
520
521local listsorters = {
522 [v_command] = function(a,b)
523 if a.metadata.kind == "command" or b.metadata.kind == "command" then
524 return a.references.internal < b.references.internal
525 else
526 return a.references.order < b.references.order
527 end
528 end,
529 [v_all] = function(a,b)
530 return a.references.internal < b.references.internal
531 end,
532 [v_title] = function(a,b)
533 local da = a.titledata
534 local db = b.titledata
535 if da and db then
536 local ta = da.title
537 local tb = db.title
538 if ta and tb then
539 local sa = da.split
540 if not sa then
541 sa = sortsplitter(sortstripper(ta))
542 da.split = sa
543 end
544 local sb = db.split
545 if not sb then
546 sb = sortsplitter(sortstripper(tb))
547 db.split = sb
548 end
549 return sortcomparer(da,db) == -1
550 end
551 end
552 return a.references.internal < b.references.internal
553 end
554}
555
556
557
558local filters = setmetatableindex(function(t,k) return t[v_default] end)
559
560local used = { }
561
562function lists.use(tag,filename,class)
563 used[tag] = {
564 names = names,
565 filename = filename,
566 data = job.loadother(filename),
567 }
568end
569
570implement {
571 name = "uselist",
572 arguments = "3 strings",
573 actions = lists.use,
574}
575
576filters.external = function(specification)
577 local collected = specification.collected or { }
578 local result = { }
579 local nofresult = 0
580 local all = specification.all
581 local names = specification.names
582 setmetatableindex(result,{ external = specification.reference })
583 for i=1,#collected do
584 local v = collected[i]
585 local m = v.metadata
586 if m and names[m.name] or all then
587 nofresult = nofresult + 1
588 result[nofresult] = v
589 end
590 end
591 return result
592end
593
594
595local function filtercollected(specification)
596
597 local names = specification.names or { }
598 local criterium = specification.criterium or v_default
599 local number = 0
600 local reference = specification.reference or ""
601 local collected = specification.collected or lists.collected
602 local forced = specification.forced or { }
603 local nested = specification.nested or false
604 local sortorder = specification.sortorder or specification.order
605 local numbers = documents.data.numbers
606 local depth = documents.data.depth
607 local block = false
608
609 local wantedblock, wantedcriterium = lpegmatch(splitter,criterium)
610 if wantedblock == "" or wantedblock == v_all or wantedblock == v_text then
611 criterium = wantedcriterium ~= "" and wantedcriterium or criterium
612 elseif not wantedcriterium then
613 block = documents.data.block
614 else
615 block = wantedblock
616 criterium = wantedcriterium
617 end
618 if block == "" then
619 block = false
620 end
621 if type(names) == "string" then
622 names = settings_to_set(names)
623 end
624 local all = not next(names) or names[v_all] or false
625
626 specification.names = names
627 specification.criterium = criterium
628 specification.number = 0
629 specification.reference = reference
630 specification.collected = collected
631 specification.forced = forced
632 specification.nested = nested
633 specification.sortorder = sortorder
634 specification.numbers = numbers
635 specification.depth = depth
636 specification.block = block
637 specification.all = all
638
639 if specification.atmost then
640 criterium = v_text
641 end
642
643 if trace_lists then
644 report_lists("filtering names %,t, criterium %a, block %a",sortedkeys(names), criterium, block or "*")
645 end
646 local result = filters[criterium](specification)
647 if trace_lists then
648 report_lists("criterium %a, block %a, found %a",specification.criterium, specification.block or "*", #result)
649 end
650
651 local levels = tonumber(specification.levels)
652 if levels then
653 local minlevel = 1000
654 local found = result
655 local nofresult = #result
656 for i=1,nofresult do
657 local v = found[i]
658 local l = v.metadata.level or 1
659 if l < minlevel then
660 minlevel = l
661 end
662 end
663 local maxlevel = minlevel + levels - 1
664 result = { }
665 nofresult = 0
666 for i=1,#found do
667 local v = found[i]
668 local l = v.metadata.level or 1
669 if l >= minlevel and l <= maxlevel then
670 nofresult = nofresult + 1
671 result[nofresult] = v
672 end
673 end
674 end
675
676 if sortorder then
677 local sorter = listsorters[sortorder]
678 if sorter then
679 if trace_lists then
680 report_lists("sorting list using method %a",sortorder)
681 end
682 for i=1,#result do
683 result[i].references.order = i
684 end
685 sort(result,sorter)
686 end
687 end
688
689 return result
690end
691
692filters[v_intro] = function(specification)
693 local collected = specification.collected
694 local result = { }
695 local nofresult = 0
696 local all = specification.all
697 local names = specification.names
698 for i=1,#collected do
699 local v = collected[i]
700 local metadata = v.metadata
701 if metadata and (all or names[metadata.name or false]) then
702 local r = v.references
703 if r and r.section == 0 then
704 nofresult = nofresult + 1
705 result[nofresult] = v
706 end
707 end
708 end
709 return result
710end
711
712filters[v_reference] = function(specification)
713 local collected = specification.collected
714 local result = { }
715 local nofresult = 0
716 local names = specification.names
717 local sections = sections.collected
718 local reference = specification.reference
719 if reference ~= "" then
720 local prefix, rest = lpegmatch(references.prefixsplitter,reference)
721 local r = prefix and rest and references.derived[prefix][rest] or references.derived[""][reference]
722 local s = r and r.numberdata
723 if s then
724 local depth = getsectionlevel(r.metadata.name)
725 local numbers = s.numbers
726 for i=1,#collected do
727 local v = collected[i]
728 local r = v.references
729 if r and (not block or not r.block or block == r.block) then
730 local metadata = v.metadata
731 if metadata and names[metadata.name or false] then
732 local sectionnumber = (r.section == 0) or sections[r.section]
733 if sectionnumber then
734 if matchingtilldepth(depth,numbers,sectionnumber.numbers) then
735 nofresult = nofresult + 1
736 result[nofresult] = v
737 end
738 end
739 end
740 end
741 end
742 else
743 report_lists("unknown reference %a specified",reference)
744 end
745 else
746 report_lists("no reference specified")
747 end
748 return result
749end
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799filters[v_all] = function(specification)
800 local collected = specification.collected
801 local result = { }
802 local nofresult = 0
803 local block = specification.block
804 local all = specification.all
805 local forced = specification.forced
806 local names = specification.names
807 local sections = sections.collected
808 for i=1,#collected do
809 local v = collected[i]
810 local r = v.references
811 if r and (not block or not r.block or block == r.block) then
812 local metadata = v.metadata
813 if metadata then
814 local name = metadata.name or false
815 local sectionnumber = (r.section == 0) or sections[r.section]
816 if forced[name] or (sectionnumber and not metadata.nolist and (all or names[name])) then
817 nofresult = nofresult + 1
818 result[nofresult] = v
819 end
820 end
821 end
822 end
823 return result
824end
825
826filters[v_text] = filters[v_all]
827
828filters[v_current] = function(specification)
829 if specification.depth == 0 then
830 specification.nested = false
831 specification.criterium = v_intro
832 return filters[v_intro](specification)
833 end
834 local collected = specification.collected
835 local result = { }
836 local nofresult = 0
837 local depth = specification.depth
838 local block = specification.block
839 local all = specification.all
840 local names = specification.names
841 local numbers = specification.numbers
842 local sections = sections.collected
843 for i=1,#collected do
844 local v = collected[i]
845 local r = v.references
846 if r and (not block or not r.block or block == r.block) then
847 local sectionnumber = sections[r.section]
848 if sectionnumber then
849 local cnumbers = sectionnumber.numbers
850 local metadata = v.metadata
851 if cnumbers then
852 if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers > depth then
853 local ok = true
854 for d=1,depth do
855 local cnd = cnumbers[d]
856 if not (cnd == 0 or cnd == numbers[d]) then
857 ok = false
858 break
859 end
860 end
861 if ok then
862 nofresult = nofresult + 1
863 result[nofresult] = v
864 end
865 end
866 end
867 end
868 end
869 end
870 return result
871end
872
873filters[v_here] = function(specification)
874
875 if specification.depth == 0 then
876 specification.nested = false
877 specification.criterium = v_intro
878 return filters[v_intro](specification)
879 end
880 local collected = specification.collected
881 local result = { }
882 local nofresult = 0
883 local depth = specification.depth
884 local block = specification.block
885 local all = specification.all
886 local names = specification.names
887 local numbers = specification.numbers
888 local sections = sections.collected
889 for i=1,#collected do
890 local v = collected[i]
891 local r = v.references
892 if r then
893 local sectionnumber = sections[r.section]
894 if sectionnumber then
895 local cnumbers = sectionnumber.numbers
896 local metadata = v.metadata
897 if cnumbers then
898 if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
899 local ok = true
900 for d=1,depth do
901 local cnd = cnumbers[d]
902 if not (cnd == 0 or cnd == numbers[d]) then
903 ok = false
904 break
905 end
906 end
907 if ok then
908 nofresult = nofresult + 1
909 result[nofresult] = v
910 end
911 end
912 end
913 end
914 end
915 end
916 return result
917end
918
919filters[v_previous] = function(specification)
920 if specification.depth == 0 then
921 specification.nested = false
922 specification.criterium = v_intro
923 return filters[v_intro](specification)
924 end
925 local collected = specification.collected
926 local result = { }
927 local nofresult = 0
928 local block = specification.block
929 local all = specification.all
930 local names = specification.names
931 local numbers = specification.numbers
932 local sections = sections.collected
933 local depth = specification.depth
934 for i=1,#collected do
935 local v = collected[i]
936 local r = v.references
937 if r and (not block or not r.block or block == r.block) then
938 local sectionnumber = sections[r.section]
939 if sectionnumber then
940 local cnumbers = sectionnumber.numbers
941 local metadata = v.metadata
942 if cnumbers then
943 if metadata and not metadata.nolist and (all or names[metadata.name or false]) and #cnumbers >= depth then
944 local ok = true
945 for d=1,depth-1 do
946 local cnd = cnumbers[d]
947 if not (cnd == 0 or cnd == numbers[d]) then
948 ok = false
949 break
950 end
951 end
952 if ok then
953 nofresult = nofresult + 1
954 result[nofresult] = v
955 end
956 end
957 end
958 end
959 end
960 end
961 return result
962end
963
964filters[v_local] = function(specification)
965 local numbers = specification.numbers
966 local nested = nesting[#nesting]
967 if nested then
968 return filtercollected {
969 names = specification.names,
970 criterium = nested.name,
971 collected = specification.collected,
972 forced = specification.forced,
973 nested = nested,
974 sortorder = specification.sortorder,
975 }
976 else
977 specification.criterium = autosectiondepth(numbers) == 0 and v_all or v_current
978 specification.nested = false
979 return filtercollected(specification)
980 end
981end
982
983filters[v_component] = function(specification)
984
985 local collected = specification.collected
986 local result = { }
987 local nofresult = 0
988 local all = specification.all
989 local names = specification.names
990 local component = resolvers.jobs.currentcomponent() or ""
991 if component ~= "" then
992 for i=1,#collected do
993 local v = collected[i]
994 local r = v.references
995 local m = v.metadata
996 if r and r.component == component and (m and names[m.name] or all) then
997 nofresult = nofresult + 1
998 result[nofresult] = v
999 end
1000 end
1001 end
1002 return result
1003end
1004
1005filters[v_product] = function(specification)
1006 local reference = specification.reference
1007 if reference and reference ~= "" then
1008 local utilitydata = job.loadother(reference)
1009 if utilitydata then
1010 local collected = utilitydata.structures.lists.collected or { }
1011 local result = { }
1012 local nofresult = 0
1013 local all = specification.all
1014 local names = specification.names
1015setmetatableindex(result,{ external = reference })
1016 for i=1,#collected do
1017 local v = collected[i]
1018 local m = v.metadata
1019
1020 if m and not m.nolist and (names[m.name] or all) then
1021 nofresult = nofresult + 1
1022 result[nofresult] = v
1023 end
1024 end
1025 return result
1026 end
1027 end
1028 return { }
1029end
1030
1031
1032
1033
1034
1035
1036filters[v_default] = function(specification)
1037 local collected = specification.collected
1038 local result = { }
1039 local nofresult = 0
1040
1041 local block = specification.block
1042 local criterium = specification.criterium
1043 local all = specification.all
1044 local names = specification.names
1045 local numbers = specification.numbers
1046 local sections = sections.collected
1047 local reference = specification.reference
1048 local nested = specification.nested
1049
1050 if reference then
1051 reference = tonumber(reference)
1052 end
1053
1054 local depth = getsectionlevel(criterium)
1055 local pnumbers = nil
1056 local pblock = block
1057 local parent = nested and nested.parent
1058
1059 if parent then
1060 pnumbers = parent.numberdata.numbers or pnumbers
1061 pblock = parent.references.block or pblock
1062 if trace_lists then
1063 report_lists("filtering by block %a and section %a",pblock,criterium)
1064 end
1065 end
1066
1067 for i=1,#collected do
1068 local v = collected[i]
1069 local r = v.references
1070 if r and (not block or not r.block or pblock == r.block) then
1071 local sectionnumber = sections[r.section]
1072 if sectionnumber then
1073 local metadata = v.metadata
1074 local cnumbers = sectionnumber.numbers
1075 if cnumbers then
1076 if all or names[metadata.name or false] then
1077 if reference then
1078
1079 if reference == cnumbers[depth] then
1080 nofresult = nofresult + 1
1081 result[nofresult] = v
1082 end
1083 else
1084 if #cnumbers >= depth and matchingtilldepth(depth,cnumbers,pnumbers) then
1085 nofresult = nofresult + 1
1086 result[nofresult] = v
1087 end
1088 end
1089 end
1090 end
1091 end
1092 end
1093 end
1094 return result
1095end
1096
1097
1098
1099lists.filter = filtercollected
1100
1101lists.result = { }
1102
1103function lists.getresult(r)
1104 return lists.result[r]
1105end
1106
1107function lists.process(specification)
1108 local names = specification.names
1109 local external = used[names or ""]
1110 if external then
1111 specification.reference = names
1112 specification.names = external.names
1113 specification.collected = external.data.structures.lists.collected
1114 specification.criterium = "external"
1115 end
1116 local result = filtercollected(specification)
1117 local total = #result
1118 lists.result = result
1119 if total > 0 then
1120 local usedinternals = references.usedinternals
1121 local usedviews = references.usedviews
1122 local specials = settings_to_set(specification.extras or "")
1123 specials = next(specials) and specials or nil
1124 for i=1,total do
1125 local listentry = result[i]
1126 local metadata = listentry.metadata
1127 local numberdata = listentry.numberdata
1128 local references = listentry.references
1129 local special = specials and numberdata and specials[zerostrippedconcat(numberdata.numbers,".")] or ""
1130 local view = usedviews[i]
1131
1132 if cheat and references and view and cheats[view] then
1133
1134 local internal = references.internal
1135 usedinternals[internal] = true
1136 usedviews [internal] = references.view
1137 end
1138 context.strclistsentryprocess(metadata.name,metadata.kind,i,special)
1139 end
1140 end
1141end
1142
1143function lists.analyze(specification)
1144 lists.result = filtercollected(specification)
1145end
1146
1147function lists.userdata(name,r,tag)
1148 local result = lists.result[r]
1149 if result then
1150 local userdata = result.userdata
1151 local str = userdata and userdata[tag]
1152 if str then
1153 return str, result.metadata
1154 end
1155 end
1156end
1157
1158function lists.uservalue(name,r,tag,default)
1159 local str = lists.result[r]
1160 if str then
1161 str = str.userdata
1162 end
1163 if str then
1164 str = str[tag]
1165 end
1166 return str or default
1167end
1168
1169function lists.size()
1170 return #lists.result
1171end
1172
1173function lists.external(n)
1174 return lists.result.external or ""
1175end
1176
1177function lists.location(n)
1178 local l = lists.result[n]
1179 return l and l.references.internal or n
1180end
1181
1182function lists.label(n,default)
1183 local l = lists.result[n]
1184 local t = l.titledata
1185 return t and t.label or default or ""
1186end
1187
1188function lists.sectionnumber(name,n,spec)
1189 local data = lists.result[n]
1190 local sectiondata = sections.collected[data.references.section]
1191
1192 typesetnumber(sectiondata,"prefix",spec,sectiondata)
1193end
1194
1195
1196
1197function lists.title(name,n,tag)
1198 local data = lists.result[n]
1199 if data then
1200 local titledata = data.titledata
1201 if titledata then
1202 helpers.title(titledata[tag] or titledata.list or titledata.title or "",data.metadata)
1203 end
1204 end
1205end
1206
1207function lists.hastitledata(name,n,tag)
1208 local data = cached[tonumber(n)]
1209 if data then
1210 local titledata = data.titledata
1211 if titledata then
1212 return (titledata[tag] or titledata.title or "") ~= ""
1213 end
1214 end
1215 return false
1216end
1217
1218function lists.haspagedata(name,n)
1219 local data = lists.result[n]
1220 if data then
1221 local references = data.references
1222 if references and references.realpage then
1223 return true
1224 end
1225 end
1226 return false
1227end
1228
1229function lists.hasnumberdata(name,n)
1230 local data = lists.result[n]
1231 if data then
1232 local numberdata = data.numberdata
1233 if numberdata and not numberdata.hidenumber then
1234 return true
1235 end
1236 end
1237 return false
1238end
1239
1240function lists.rawnumber(n,name)
1241 local data = lists.result[n]
1242 if data then
1243 local numberdata = data.numberdata
1244 if numberdata then
1245 numberdata = numberdata.numbers
1246 return numberdata and numberdata[getsectionlevel(name)] or numberdata[name] or 0
1247 end
1248 end
1249 return 0
1250end
1251
1252function lists.prefix(name,n,spec)
1253 helpers.prefix(lists.result[n],spec)
1254end
1255
1256function lists.page(name,n,pagespec)
1257 helpers.page(lists.result[n],pagespec)
1258end
1259
1260function lists.prefixedpage(name,n,prefixspec,pagespec)
1261 helpers.prefixpage(lists.result[n],prefixspec,pagespec)
1262end
1263
1264function lists.realpage(name,n)
1265 local data = lists.result[n]
1266 if data then
1267 local references = data.references
1268 return references and references.realpage or 0
1269 else
1270 return 0
1271 end
1272end
1273
1274
1275
1276function lists.number(name,n,spec)
1277 local data = lists.result[n]
1278 if data then
1279 local numberdata = data.numberdata
1280 if numberdata then
1281 typesetnumber(numberdata,"number",spec or false,numberdata or false)
1282 end
1283 end
1284end
1285
1286function lists.prefixednumber(name,n,prefixspec,numberspec,forceddata)
1287 local data = lists.result[n]
1288 if data then
1289 helpers.prefix(data,prefixspec)
1290 local numberdata = data.numberdata or forceddata
1291 if numberdata then
1292 typesetnumber(numberdata,"number",numberspec or false,numberdata or false)
1293 end
1294 end
1295end
1296
1297
1298
1299
1300
1301local splitter = lpeg.splitat(":")
1302
1303function references.specials.order(var,actions)
1304 local operation = var.operation
1305 if operation then
1306 local kind, name, n = lpegmatch(splitter,operation)
1307 local order = lists.ordered[kind]
1308 order = order and order[name]
1309 local v = order[tonumber(n)]
1310 local r = v and v.references.realpage
1311 if r then
1312 actions.realpage = r
1313 var.operation = r
1314 return references.specials.page(var,actions)
1315 end
1316 end
1317end
1318
1319
1320
1321implement { name = "pushlist", actions = lists.pushnesting, arguments = "integer" }
1322implement { name = "poplist", actions = lists.popnesting }
1323
1324implement {
1325 name = "addtolist",
1326 actions = { lists.addto, context },
1327 arguments = {
1328 {
1329 { "references", {
1330 { "internal", "integer" },
1331 { "block" },
1332 { "section", "integer" },
1333 { "location" },
1334 { "prefix" },
1335 { "reference" },
1336 { "view" },
1337 { "order", "integer" },
1338 }
1339 },
1340 { "metadata", {
1341 { "kind" },
1342 { "name" },
1343 { "level", "integer" },
1344 { "catcodes", "integer" },
1345 { "coding" },
1346 { "xmlroot" },
1347 { "setup" },
1348 }
1349 },
1350 { "userdata" },
1351 { "titledata", {
1352 { "label" },
1353 { "title" },
1354 { "bookmark" },
1355 { "marking" },
1356 { "list" },
1357 { "reference" },
1358 }
1359 },
1360 { "prefixdata", {
1361 { "prefix" },
1362 { "separatorset" },
1363 { "conversionset" },
1364 { "conversion" },
1365 { "set" },
1366 { "segments" },
1367 { "connector" },
1368 }
1369 },
1370 { "numberdata", {
1371 { "level", "integer" },
1372 { "numbers" },
1373 { "groupsuffix" },
1374 { "group" },
1375 { "counter" },
1376 { "separatorset" },
1377 { "conversionset" },
1378 { "conversion" },
1379 { "starter" },
1380 { "stopper" },
1381 { "segments" },
1382 }
1383 }
1384 }
1385 }
1386}
1387
1388implement {
1389 name = "enhancelist",
1390 arguments = "integer",
1391 actions = function(n)
1392 enhancelist { n = n }
1393 end
1394}
1395
1396implement {
1397 name = "deferredenhancelist",
1398 arguments = "integer",
1399 protected = true,
1400 actions = function(n)
1401 ctx_latelua { action = enhancelist, n = n }
1402 end,
1403}
1404
1405implement {
1406 name = "processlist",
1407 actions = lists.process,
1408 arguments = {
1409 {
1410 { "names" },
1411 { "criterium" },
1412 { "reference" },
1413 { "extras" },
1414 { "order" },
1415 { "levels" },
1416 }
1417 }
1418}
1419
1420implement {
1421 name = "analyzelist",
1422 actions = lists.analyze,
1423 arguments = {
1424 {
1425 { "names" },
1426 { "criterium" },
1427 { "reference" },
1428 }
1429 }
1430}
1431
1432implement {
1433 name = "listtitle",
1434 actions = lists.title,
1435 arguments = { "string", "integer" }
1436}
1437
1438implement {
1439 name = "listprefixednumber",
1440 actions = lists.prefixednumber,
1441 arguments = {
1442 "string",
1443 "integer",
1444 {
1445 { "prefix" },
1446 { "separatorset" },
1447 { "conversionset" },
1448 { "starter" },
1449 { "stopper" },
1450 { "set" },
1451 { "segments" },
1452 { "connector" },
1453 },
1454 {
1455 { "separatorset" },
1456 { "conversionset" },
1457 { "starter" },
1458 { "stopper" },
1459 { "segments" },
1460 }
1461 }
1462}
1463
1464implement {
1465 name = "listprefixedpage",
1466 actions = lists.prefixedpage,
1467 arguments = {
1468 "string",
1469 "integer",
1470 {
1471 { "separatorset" },
1472 { "conversionset" },
1473 { "set" },
1474 { "segments" },
1475 { "connector" },
1476 },
1477 {
1478 { "prefix" },
1479 { "conversionset" },
1480 { "starter" },
1481 { "stopper" },
1482 }
1483 }
1484}
1485
1486implement { name = "listsize", actions = { lists.size, context } }
1487implement { name = "listexternal", actions = { lists.external, context }, arguments = "integer" }
1488implement { name = "listlocation", actions = { lists.location, context }, arguments = "integer" }
1489implement { name = "listlabel", actions = { lists.label, context }, arguments = { "integer", "string" } }
1490implement { name = "listrealpage", actions = { lists.realpage, context }, arguments = { "string", "integer" } }
1491implement { name = "listgroupindex", actions = { lists.groupindex, context }, arguments = "2 strings", }
1492
1493implement {
1494 name = "currentsectiontolist",
1495 actions = { sections.current, lists.addto, context }
1496}
1497
1498local function userdata(name,r,tag)
1499 local str, metadata = lists.userdata(name,r,tag)
1500 if str then
1501
1502
1503
1504
1505
1506
1507 helpers.title(str,metadata)
1508 end
1509end
1510
1511implement {
1512 name = "listuserdata",
1513 actions = userdata,
1514 arguments = { "string", "integer", "string" }
1515}
1516
1517
1518
1519
1520implement { name = "doifelselisthastitle", actions = { lists.hastitledata, commands.doifelse }, arguments = { "string", "integer" } }
1521implement { name = "doifelselisthaspage", actions = { lists.haspagedata, commands.doifelse }, arguments = { "string", "integer" } }
1522implement { name = "doifelselisthasnumber", actions = { lists.hasnumberdata, commands.doifelse }, arguments = { "string", "integer" } }
1523implement { name = "doifelselisthasentry", actions = { lists.iscached, commands.doifelse }, arguments = "integer" }
1524
1525
1526
1527local function savedlisttitle(name,n,tag)
1528 local data = cached[n]
1529 if data then
1530 local titledata = data.titledata
1531 if titledata then
1532 helpers.title(titledata[tag] or titledata.title or "",data.metadata)
1533 end
1534 end
1535end
1536
1537local function savedlistnumber(name,n)
1538 local data = cached[n]
1539 if data then
1540 local numberdata = data.numberdata
1541 if numberdata then
1542 typesetnumber(numberdata,"number",numberdata or false)
1543 end
1544 end
1545end
1546
1547local function savedlistprefixednumber(name,n)
1548 local data = cached[n]
1549 if data then
1550
1551
1552 local numberdata = reordered[n] or data.numberdata
1553 if numberdata then
1554 helpers.prefix(data,data.prefixdata)
1555 typesetnumber(numberdata,"number",numberdata or false)
1556 end
1557 end
1558end
1559
1560lists.savedlisttitle = savedlisttitle
1561lists.savedlistnumber = savedlistnumber
1562lists.savedlistprefixednumber = savedlistprefixednumber
1563
1564implement {
1565 name = "savedlistnumber",
1566 actions = savedlistnumber,
1567 arguments = { "string", "integer" }
1568}
1569
1570implement {
1571 name = "savedlisttitle",
1572 actions = savedlisttitle,
1573 arguments = { "string", "integer" }
1574}
1575
1576implement {
1577 name = "savedlistprefixednumber",
1578 actions = savedlistprefixednumber,
1579 arguments = { "string", "integer" }
1580}
1581
1582implement {
1583 name = "discardfromlist",
1584 actions = lists.discard,
1585 arguments = "integer"
1586}
1587
1588implement {
1589 name = "rawlistnumber",
1590 actions = { lists.rawnumber, context },
1591 arguments = { "integer", "string" },
1592}
1593
1594
1595
1596function lists.integrate(utilitydata)
1597 local filename = utilitydata.comment.file
1598 if filename and filename ~= environment.jobname then
1599 local structures = utilitydata.structures
1600 if structures then
1601 local lists = structures.lists.collected or { }
1602 if lists then
1603 local sections = structures.sections.collected or { }
1604 local pages = structures.pages.collected or { }
1605 for i=1,#lists do
1606 local entry = lists[i]
1607 local references = entry.references
1608 if references then
1609 local section = references.section
1610 local realpage = references.realpage
1611
1612 references.sectiondata = section and sections[section]
1613 references.pagedata = realpage and pages[realpage]
1614
1615
1616
1617
1618 if references.view then
1619 references.view = nil
1620 end
1621 if references.used then
1622 references.used = nil
1623 end
1624 if references.x then
1625 references.x = nil
1626 end
1627 if references.y then
1628 references.y = nil
1629 end
1630 references.external = filename
1631 end
1632 end
1633 end
1634 end
1635 end
1636end
1637 |