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