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