back-exp-imp-tag.lmt /size: 23 Kb    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['back-exp-imp-tag'] = {
2    version   = 1.001,
3    comment   = "companion to back-exp.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-- Because we run into the 200 locals limit we now split the file into smaller
10-- parts.
11
12local tonumber = tonumber
13local todimen = number.todimen
14local sortedkeys, sortedhash, setmetatableindex, concat, insert = table.sortedkeys, table.sortedhash, table.setmetatableindex, table.concat, table.insert
15local settings_to_hash = utilities.parsers.settings_to_hash
16local lpegmatch = lpeg.match
17local formatters = string.formatters
18
19local references        = structures.references
20local structurestags    = structures.tags
21local taglist           = structurestags.taglist
22local specifications    = structurestags.specifications
23local properties        = structurestags.properties
24local locatedtag        = structurestags.locatedtag
25
26local backend           = structurestags.backend
27
28local setattribute      = backend.setattribute
29local extras            = backend.extras
30local checks            = backend.checks
31local fixes             = backend.fixes
32local listdata          = backend.listdata
33local finalizers        = backend.finalizers
34local usedstyles        = backend.usedstyles -- for now
35local usedimages        = backend.usedimages -- for now
36local referencehash     = backend.referencehash
37local destinationhash   = backend.destinationhash
38
39local implement         = interfaces.implement
40
41do
42
43    local itemgroups = { }
44
45    local function setitemgroup(packed,continue,level,symbol)
46        itemgroups[locatedtag("itemgroup")] = {
47            packed   = packed,
48            continue = continue,
49            symbol   = symbol,
50            level    = level,
51        }
52    end
53
54    local function getitemgroup(fulltag)
55        return itemgroups[fulltag]
56    end
57
58    local function setitem(kind)
59        itemgroups[locatedtag("item")] = {
60            kind = kind,
61        }
62    end
63
64    function extras.itemgroup(di,element,n,fulltag)
65        local hash = itemgroups[fulltag]
66        if hash then
67            setattribute(di,"packed",hash.packed and "yes" or nil)
68            setattribute(di,"continue",hash.continue and "yes" or nil)
69            setattribute(di,"symbol",hash.symbol)
70            setattribute(di,"level",hash.level)
71        end
72    end
73
74    function extras.item(di,element,n,fulltag)
75        local hash = itemgroups[fulltag]
76        if hash then
77            local kind = hash.kind
78            if kind and kind ~= "" then
79                setattribute(di,"kind",kind)
80            end
81        end
82    end
83
84    implement {
85        name      = "settagitemgroup",
86        actions   = setitemgroup,
87        arguments = { "boolean", "boolean", "integer", "string" }
88    }
89
90    implement {
91        name      = "settagitem",
92        actions   = setitem,
93        arguments = "string"
94    }
95
96    structurestags.setitemgroup = setitemgroup
97    structurestags.getitemgroup = getitemgroup
98    structurestags.setitem      = setitem
99
100end
101
102do
103
104    local registered = structures.sections.registered
105
106    local function resolve(di,element,n,fulltag)
107        local data = listdata[fulltag]
108        if data then
109            extras.addreference(di,data.references)
110            return true
111        else
112            local data = di.data
113            if data then
114                for i=1,#data do
115                    local di = data[i]
116                    if di then
117                        local ft = di.fulltag
118                        if ft and resolve(di,element,n,ft) then
119                            return true
120                        end
121                    end
122                end
123            end
124        end
125    end
126
127    function extras.section(di,element,n,fulltag)
128        local r = registered[specifications[fulltag].detail]
129        if r then
130            setattribute(di,"level",r.level)
131        end
132        resolve(di,element,n,fulltag)
133    end
134
135    local floats = { }
136
137    local function setfloat(options,method)
138        floats[locatedtag("float")] = {
139            options = options,
140            method  = method,
141        }
142    end
143
144    function extras.float(di,element,n,fulltag)
145        local hash = floats[fulltag]
146        if hash then
147            local method  = hash.method
148            if not method or method == "" then
149                method = "here"
150            end
151            setattribute(di,"method",method)
152            local options = hash.options
153            if options and options ~= "" then
154                options = settings_to_hash(options)
155                options[method] = nil
156                options = concat(sortedkeys(options),",")
157                if #options > 0 then
158                    setattribute(di,"options",options)
159                end
160            end
161        end
162        resolve(di,element,n,fulltag)
163    end
164
165    implement {
166        name      = "settagfloat",
167        actions   = setfloat,
168        arguments = "2 strings",
169    }
170
171    structurestags.setfloat = setfloat
172
173end
174
175do
176
177    local registered = { }
178
179    local function setformulacontent(n,image)
180        registered[locatedtag("formulacontent")] = {
181            n     = n,
182            image = image,
183        }
184    end
185
186    function extras.formulacontent(di,element,n,fulltag)
187        local r = registered[fulltag]
188        if r then
189            setattribute(di,"n",r.n)
190            if tonumber(r.image) ~= 0 then
191             -- setattribute(di,"data-lmtx-image","image-"..r.image)
192--                 setattribute(di,"image","image-"..r.image)
193                setattribute(di,"image",tex.jobname .. "-" .. "image-"..r.image)
194            end
195        end
196    end
197
198    implement {
199        name      = "settagformulacontent",
200        actions   = setformulacontent,
201        arguments = "2 strings",
202    }
203
204    structurestags.setformulacontent = setformulacontent
205
206end
207
208do
209
210    local symbols = { }
211
212    local function settagdelimitedsymbol(symbol)
213        symbols[locatedtag("delimitedsymbol")] = {
214            symbol = symbol,
215        }
216    end
217
218    function extras.delimitedsymbol(di,element,n,fulltag)
219        local hash = symbols[fulltag]
220        if hash then
221            setattribute(di,"symbol",hash.symbol or nil)
222        end
223    end
224
225    implement {
226        name      = "settagdelimitedsymbol",
227        actions   = settagdelimitedsymbol,
228        arguments = "string"
229    }
230
231    structurestags.settagdelimitedsymbol = settagdelimitedsymbol
232
233end
234
235
236do
237
238    local symbols = { }
239
240    local function settagsubsentencesymbol(symbol)
241        symbols[locatedtag("subsentencesymbol")] = {
242            symbol = symbol,
243        }
244    end
245
246    function extras.subsentencesymbol(di,element,n,fulltag)
247        local hash = symbols[fulltag]
248        if hash then
249            setattribute(di,"symbol",hash.symbol or nil)
250        end
251    end
252
253    implement {
254        name      = "settagsubsentencesymbol",
255        actions   = settagsubsentencesymbol,
256        arguments = "string"
257    }
258
259    structurestags.settagsubsentencesymbol = settagsubsentencesymbol
260
261end
262
263do
264
265    local synonyms = { }
266    local sortings = { }
267
268    local function setsynonym(tag)
269        synonyms[locatedtag("synonym")] = tag
270    end
271
272    function extras.synonym(di,element,n,fulltag)
273        local tag = synonyms[fulltag]
274        if tag then
275            setattribute(di,"tag",tag)
276        end
277    end
278
279    local function setsorting(tag)
280        sortings[locatedtag("sorting")] = tag
281    end
282
283    function extras.sorting(di,element,n,fulltag)
284        local tag = sortings[fulltag]
285        if tag then
286            setattribute(di,"tag",tag)
287        end
288    end
289
290    implement {
291        name      = "settagsynonym",
292        actions   = setsynonym,
293        arguments = "string"
294    }
295
296    implement {
297        name      = "settagsorting",
298        actions   = setsorting,
299        arguments = "string"
300    }
301
302    structurestags.setsynonym = setsynonym
303    structurestags.setsorting = setsorting
304
305end
306
307do
308
309    local descriptions = { }
310    local symbols      = { }
311    local linked       = { }
312
313    -- we could move the notation itself to the first reference (can be an option)
314
315    local function setnotation(tag,n) -- needs checking (is tag needed)
316        -- we can also use the internals hash or list
317        local nd = structures.notes.get(tag,n)
318        if nd then
319            local references = nd.references
320            descriptions[references and references.internal] = locatedtag("description")
321        end
322    end
323
324    local function setnotationsymbol(tag,n) -- needs checking (is tag needed)
325        local nd = structures.notes.get(tag,n) -- todo: use listdata instead
326        if nd then
327            local references = nd.references
328            symbols[references and references.internal] = locatedtag("descriptionsymbol")
329        end
330    end
331
332    function finalizers.descriptions(tree)
333        local n = 0
334        for id, tag in sortedhash(descriptions) do
335            local sym = symbols[id]
336            if sym then
337                n = n + 1
338                linked[tag] = n
339                linked[sym] = n
340            end
341        end
342    end
343
344    function extras.description(di,element,n,fulltag)
345        local id = linked[fulltag]
346        if id then
347            setattribute(di,"insert",id)
348        end
349    end
350
351    function extras.descriptionsymbol(di,element,n,fulltag)
352        local id = linked[fulltag]
353        if id then
354            setattribute(di,"insert",id)
355        end
356    end
357
358    implement {
359        name      = "settagnotation",
360        actions   = setnotation,
361        arguments = { "string", "integer" }
362    }
363
364    implement {
365        name      = "settagnotationsymbol",
366        actions   = setnotationsymbol,
367        arguments = { "string", "integer" }
368    }
369
370    structurestags.setnotation       = setnotation
371    structurestags.setnotationsymbol = setnotationsymbol
372
373end
374
375
376do
377
378    local strippedtag    = structurestags.strip -- we assume global styles
379
380    local highlight      = { }
381    local construct      = { }
382
383    usedstyles.highlight = highlight
384    usedstyles.construct = construct
385
386    local function sethighlight(name,style,color,mode)
387        if not highlight[name] then
388            highlight[name] = {
389                style = style,
390                color = color,
391                mode  = mode == 1 and "display" or nil,
392            }
393        end
394    end
395
396    local function setconstruct(name,style,color,mode)
397        if not construct[name] then
398            construct[name] = {
399                style = style,
400                color = color,
401                mode  = mode == 1 and "display" or nil,
402            }
403        end
404    end
405
406    implement {
407        name      = "settagconstruct",
408        actions   = setconstruct,
409        arguments = { "string", "string", "integer", "integer" }
410    }
411
412    implement {
413        name      = "settaghighlight",
414        actions   = sethighlight,
415        arguments = { "string", "string", "integer", "integer" }
416    }
417
418    structurestags.sethighlight = sethighlight
419    structurestags.setconstruct = setconstruct
420
421end
422
423do
424
425    local f_id       = formatters["%s-%s"]
426    local image      = { }
427    usedimages.image = image
428
429    structurestags.usewithcare.images = image
430
431    local function setfigure(name,used,page,width,height,depth,label,category)
432        local fulltag = locatedtag("image")
433        local spec    = specifications[fulltag]
434        if spec then
435            local page = tonumber(page)
436            local id = f_id(spec.tagname,spec.tagindex)
437            image[fulltag] = {
438                id       = id,
439  -- ["data-lmtx-image"] = id,
440                image    = id,
441                name     = name,
442                used     = used,
443                page     = page and page > 1 and page or nil,
444                width    = todimen(width,"pt","%0.3F%s"),
445                height   = todimen(height+depth,"pt","%0.3F%s"),
446                drop     = depth ~= 0 and todimen(depth,"pt","%0.3F%s") or nil,
447                label    = label,
448                category = category,
449            }
450        else
451            -- we ignore images in layers in the background / pagebody
452        end
453    end
454
455    function extras.image(di,element,n,fulltag)
456        local data = image[fulltag]
457        if data then
458--             local id = data.id
459            local id = tex.jobname .. "-" .. data.id
460            -- can be less
461            setattribute(di,"name",data.name)
462            setattribute(di,"page",data.page)
463            setattribute(di,"id",id)
464         -- setattribute(di,"data-lmtx-image",id)
465            setattribute(di,"image",id)
466            setattribute(di,"width",data.width)
467            setattribute(di,"height",data.height)
468            setattribute(di,"drop",data.drop)
469            setattribute(di,"label",data.label)
470            setattribute(di,"category",data.category)
471        end
472    end
473
474    implement {
475        name      = "settagfigure",
476        actions   = setfigure,
477        arguments = { "string", "string", "string", "dimension", "dimension", "dimension", "string", "string" }
478    }
479
480    structurestags.setfigure = setfigure
481
482end
483
484do
485
486    local combinations     = { }
487    local combinationpairs = { }
488
489    local function setcombination(nx,ny)
490        combinations[locatedtag("combination")] = {
491            nx = nx,
492            ny = ny,
493        }
494    end
495    local function setcombinationpair(x,y)
496        combinationpairs[locatedtag("combinationpair")] = {
497            x = x,
498            y = y,
499        }
500    end
501
502    function extras.combination(di,element,n,fulltag)
503        local data = combinations[fulltag]
504        if data then
505            setattribute(di,"nx",data.nx)
506            setattribute(di,"ny",data.ny)
507        end
508    end
509    function extras.combinationpair(di,element,n,fulltag)
510        local data = combinationpairs[fulltag]
511        if data then
512            setattribute(di,"x",data.x)
513            setattribute(di,"y",data.y)
514        end
515    end
516
517    implement {
518        name      = "settagcombination",
519        actions   = setcombination,
520        arguments = { "integer", "integer" }
521    }
522    implement {
523        name      = "settagcombinationpair",
524        actions   = setcombinationpair,
525        arguments = { "integer", "integer" }
526    }
527
528    structurestags.setcombination     = setcombination
529    structurestags.setcombinationpair = setcombinationpair
530
531end
532
533do
534
535    local function hascontent(data)
536        for i=1,#data do
537            local di = data[i]
538            if not di or di.tg == "ignore" then
539                --
540            else
541                local content = di.content
542                if content == " " then
543                    --
544                elseif content then
545                    return true
546                else
547                    local d = di.data
548                    if d and #d > 0 and hascontent(d) then
549                        return true
550                    end
551                end
552            end
553        end
554    end
555
556    local tabledata = { }
557
558    local function settablecell(rows,columns,align)
559        if align > 0 or rows > 1 or columns > 1 then -- or kind > 0
560            tabledata[locatedtag("tablecell")] = {
561                rows    = rows,
562                columns = columns,
563                align   = align,
564            }
565        end
566    end
567
568    local function gettablecell(fulltag)
569        return tabledata[fulltag]
570    end
571
572    function extras.tablecell(di,element,n,fulltag)
573        local hash = tabledata[fulltag]
574        if hash then
575            local columns = hash.columns
576            if columns and columns > 1 then
577                setattribute(di,"columns",columns)
578            end
579            local rows = hash.rows
580            if rows and rows > 1 then
581                setattribute(di,"rows",rows)
582            end
583            local align = hash.align
584            if not align or align == 0 then
585                -- normal
586            elseif align == 1 then -- use numbertoalign here
587                setattribute(di,"align","flushright")
588            elseif align == 2 then
589                setattribute(di,"align","middle")
590            elseif align == 3 then
591                setattribute(di,"align","flushleft")
592            end
593        end
594    end
595
596    local tabulatedata = { }
597
598    local function settabulatecell(align,kind)
599        if align > 0 or kind > 0 then
600            tabulatedata[locatedtag("tabulatecell")] = {
601                align = align,
602                kind  = kind, -- 1 = bold head
603            }
604        end
605    end
606
607    local function gettabulatecell(fulltag)
608        return tabulatedata[fulltag]
609    end
610
611    function extras.tabulate(di,element,n,fulltag)
612        local data = di.data
613        for i=1,#data do
614            local di = data[i]
615            if di.tg == "tabulaterow" and not hascontent(di.data) then
616                di.element = "" -- or simply remove
617            end
618        end
619    end
620
621    function extras.tabulatecell(di,element,n,fulltag)
622        local hash = tabulatedata[fulltag]
623        if hash then
624            local align = hash.align
625            if not align or align == 0 then
626                -- normal
627            elseif align == 1 then
628                setattribute(di,"align","flushleft")
629            elseif align == 2 then
630                setattribute(di,"align","flushright")
631            elseif align == 3 then
632                setattribute(di,"align","middle")
633            end
634            local kind = hash.kind
635            if kind == 1 then
636                setattribute(di,"kind","strong")
637            elseif kind == 2 then
638                setattribute(di,"kind","equals")
639            end
640        end
641    end
642
643    implement {
644        name      = "settagtablecell",
645        actions   = settablecell,
646        arguments = { "integer", "integer", "integer" }
647    }
648
649    implement {
650        name      = "settagtabulatecell",
651        actions   = settabulatecell,
652        arguments = { "integer", "integer" },
653    }
654
655    structurestags.settablecell    = settablecell
656    structurestags.gettablecell    = gettablecell
657    structurestags.settabulatecell = settabulatecell
658    structurestags.gettabulatecell = gettabulatecell
659
660end
661
662do
663
664    -- todo: internal is already hashed
665
666    local p_stripper = lpeg.patterns.stripper
667
668    local function setregister(tag,n) -- check if tag is needed
669        local data = structures.registers.get(tag,n)
670        if data then
671            referencehash[locatedtag("registerlocation")] = data
672        end
673    end
674
675    function extras.registerlocation(di,element,n,fulltag)
676        local data = referencehash[fulltag]
677        if type(data) == "table" then
678            extras.addinternal(di,data.references)
679            return true
680        else
681            -- needs checking, probably bookmarks
682        end
683    end
684
685    function extras.registerpages(di,element,n,fulltag) -- ignorebreaks
686        local data = di.data
687        for i=1,#data do
688            local d = data[i]
689            if d.content == " " then
690                d.content = ""
691            end
692        end
693    end
694
695    function extras.registerseparator(di,element,n,fulltag) -- ignorespaces
696        local data = di.data
697        for i=1,#data do
698            local d = data[i]
699            local c = d.content
700            if type(c) == "string" then
701                d.content = lpegmatch(p_stripper,c)
702            end
703        end
704    end
705
706    implement {
707        name      = "settagregister",
708        actions   = setregister,
709        arguments = { "string", "integer" }
710    }
711
712    structurestags.setregister = setregister
713
714end
715
716do
717
718    -- todo: internal is already hashed
719
720    local function setlist(n)
721        local data = structures.lists.getresult(n)
722        if data then
723            referencehash[locatedtag("listitem")] = data
724        end
725    end
726
727    function extras.listitem(di,element,n,fulltag)
728        local data = referencehash[fulltag]
729        if data then
730            extras.addinternal(di,data.references)
731            return true
732        end
733    end
734
735    implement {
736        name      = "settaglist",
737        actions   = setlist,
738        arguments = "integer"
739    }
740
741    structurestags.setlist = setlist
742
743end
744
745do
746
747    local usedpublications = { }
748    local tagsindatasets   = setmetatableindex("table")
749    local serialize        = false
750
751    local function setpublication(dataset,tag,rendering)
752        usedpublications[locatedtag("publication")] = {
753            dataset   = dataset,
754            tag       = tag,
755            rendering = rendering
756        }
757        tagsindatasets[dataset][tag] = true
758        if not serialize then
759            structures.tags.registerextradata("btx",function()
760                local t = { "<btxdata>"}
761                for dataset, used in sortedhash(tagsindatasets) do
762                    t[#t+1] = publications.converttoxml(dataset,true,false,true,false,true,true)
763                end
764                t[#t+1] = "</btxdata>"
765                return concat(t,"\n")
766            end)
767        end
768    end
769
770    function extras.publication(di,element,n,fulltag)
771        local hash = usedpublications[fulltag]
772        if hash then
773            setattribute(di,"dataset",hash.dataset)
774            setattribute(di,"tag",hash.tag)
775        end
776    end
777
778    implement {
779        name      = "settagpublication",
780        actions   = setpublication,
781        arguments = "2 strings"
782    }
783
784    structurestags.setpublication = setpublication
785
786end
787
788do
789
790    local usedparagraphs = { }
791
792    local function setparagraph(align)
793        if align ~= "" then
794            usedparagraphs[locatedtag("paragraph")] = {
795                align = align,
796            }
797        end
798    end
799
800    function extras.paragraph(di,element,n,fulltag)
801        local hash = usedparagraphs[fulltag]
802        if hash then
803            setattribute(di,"align",hash.align)
804        end
805    end
806
807    implement {
808        name      = "settagparagraph",
809        actions   = setparagraph,
810        arguments = "string"
811    }
812
813    structurestags.setparagraph = setparagraph
814
815end
816
817do
818
819    local marginanchors = { }
820    local margincontent = { }
821
822    function checks.margintext(di)
823        local i = marginanchors[di.fulltag]
824        margincontent[i] = di
825    end
826
827    function checks.marginanchor(di)
828        local i = marginanchors[di.fulltag]
829        local d = margincontent[i]
830        --
831        di.attribute = d.attribute
832        di.data      = d.data
833        di.detail    = d.detail
834        di.element   = d.element
835        di.fulltag   = d.fulltag
836        di.nature    = d.nature
837        di.samepar   = true
838        di.tg        = d.tg
839        --
840        d.skip       = "ignore"
841    end
842
843    implement {
844        name      = "settagmargintext",
845        arguments = "integer",
846        actions   = function(n)
847            marginanchors[locatedtag("margintext")] = n
848        end
849    }
850
851    implement {
852        name      = "settagmarginanchor",
853        arguments = "integer",
854        actions   = function(n)
855            marginanchors[locatedtag("marginanchor")] = n
856        end
857    }
858
859end
860
861do
862
863    function fixes.linenumber(di,data,i)
864        local ni = data[i+1]
865        if ni then
866            if ni.data then
867                while true do
868                    local d = ni.data[1]
869                    if d then
870                        local e = d.element
871                        if e then
872                            if e == "line" or e == "verbatimline" then
873                                insert(d.data,1,di)
874                                data[i] = false
875                                return
876                            else
877                                ni = d
878                            end
879                        else
880                            return
881                        end
882                    else
883                        return
884                    end
885                end
886            end
887        end
888    end
889
890end
891
892
893do
894
895    local usedcodepoints = { }
896
897    local function checkcodepoint(di,element,n,fulltag)
898        local unicode = usedcodepoints[fulltag]
899        if unicode then
900            setattribute(di,"codepoint",unicode)
901        end
902    end
903
904    local function setcodepoint(tag,unicode)
905        usedcodepoints[locatedtag(tag)] = unicode
906        if not extras[tag] then
907            extras[tag] = checkcodepoint
908        end
909    end
910
911    implement {
912        name      = "settagcodepoint",
913        actions   = setcodepoint,
914        arguments = { "argument", "integer" },
915    }
916
917    structurestags.setcodepoint = setcodepoint
918
919end
920