attr-ini.lua /size: 5544 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['attr-ini'] = {
2    version   = 1.001,
3    comment   = "companion to attr-ini.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
9local next, type = next, type
10local osexit = os.exit
11
12--[[ldx--
13<p>We start with a registration system for atributes so that we can use the
14symbolic names later on.</p>
15--ldx]]--
16
17local nodes             = nodes
18local context           = context
19local storage           = storage
20local commands          = commands
21
22local implement         = interfaces.implement
23
24attributes              = attributes or { }
25local attributes        = attributes
26
27local sharedstorage     = storage.shared
28
29local texsetattribute   = tex.setattribute
30
31attributes.names        = attributes.names    or { }
32attributes.numbers      = attributes.numbers  or { }
33attributes.list         = attributes.list     or { }
34attributes.states       = attributes.states   or { }
35attributes.handlers     = attributes.handlers or { }
36attributes.unsetvalue   = -0x7FFFFFFF
37
38local currentfont       = font.current
39local currentattributes = nodes and nodes.currentattributes or node.currentattributes or node.current_attr -- no nodes table yet
40
41local names             = attributes.names
42local numbers           = attributes.numbers
43local list              = attributes.list
44
45storage.register("attributes/names",   names,   "attributes.names")
46storage.register("attributes/numbers", numbers, "attributes.numbers")
47storage.register("attributes/list",    list,    "attributes.list")
48
49-- function attributes.define(name,number) -- at the tex end
50--     if not numbers[name] then
51--         numbers[name] = number
52--         names[number] = name
53--         list[number]  = { }
54--     end
55-- end
56
57--[[ldx--
58<p>We reserve this one as we really want it to be always set (faster).</p>
59--ldx]]--
60
61names[0], numbers["fontdynamic"] = "fontdynamic", 0
62
63--[[ldx--
64<p>private attributes are used by the system and public ones are for users. We use dedicated
65ranges of numbers for them. Of course a the <l n='context'/> end a private attribute can be
66accessible too, so a private attribute can have a public appearance.</p>
67--ldx]]--
68
69sharedstorage.attributes_last_private = sharedstorage.attributes_last_private or   15 -- very private
70sharedstorage.attributes_last_public  = sharedstorage.attributes_last_public  or 1024 -- less private
71
72function attributes.private(name) -- at the lua end (hidden from user)
73    local number = numbers[name]
74    if not number then
75        local last = sharedstorage.attributes_last_private
76        if last < 1023 then
77            last = last + 1
78            sharedstorage.attributes_last_private = last
79        else
80            report_attribute("no more room for private attributes")
81            osexit()
82        end
83        number = last
84        numbers[name], names[number], list[number] = number, name, { }
85    end
86    return number
87end
88
89function attributes.public(name) -- at the lua end (hidden from user)
90    local number = numbers[name]
91    if not number then
92        local last = sharedstorage.attributes_last_public
93        if last < 65535 then
94            last = last + 1
95            sharedstorage.attributes_last_public = last
96        else
97            report_attribute("no more room for public attributes")
98            osexit()
99        end
100        number = last
101        numbers[name], names[number], list[number] = number, name, { }
102    end
103    return number
104end
105
106attributes.system = attributes.private
107
108function attributes.define(name,category)
109    return (attributes[category or "public"] or attributes["public"])(name)
110end
111
112-- tracers
113
114local report_attribute = logs.reporter("attributes")
115
116local function showlist(what,list)
117    if list then
118        local a = list.next
119        local i = 0
120        while a do
121            local number = a.number
122            local value  = a.value
123            i = i + 1
124            report_attribute("%S %2i: attribute %3i, value %4i, name %a",what,i,number,value,names[number])
125            a = a.next
126        end
127   end
128end
129
130function attributes.showcurrent()
131    showlist("current",currentattributes())
132end
133
134function attributes.ofnode(n)
135    showlist(n,n.attr)
136end
137
138-- rather special (can be optimized)
139
140local store = { }
141
142function attributes.save(name)
143    name = name or ""
144    local n = currentattributes()
145    n = n and n.next
146    local t = { }
147    while n do
148        t[n.number] = n.value
149        n = n.next
150    end
151    store[name] = {
152        attr = t,
153        font = currentfont(),
154    }
155end
156
157function attributes.restore(name)
158    name = name or ""
159    local t = store[name]
160    if t then
161        local attr = t.attr
162        local font = t.font
163        if attr then
164            for k, v in next, attr do
165                texsetattribute(k,v)
166            end
167        end
168        if font then
169         -- tex.font = font
170         -- context.getvalue(fonts.hashes.csnames[font])
171            currentfont(font)
172        end
173    end
174 -- store[name] = nil
175end
176
177implement {
178    name      = "defineattribute",
179    arguments = "2 strings",
180    actions   = { attributes.define, context }
181}
182
183-- interface
184
185implement {
186    name      = "showattributes",
187    actions   = attributes.showcurrent
188}
189
190implement {
191    name      = "savecurrentattributes",
192    arguments = "string",
193    actions   = attributes.save
194}
195
196implement {
197    name      = "restorecurrentattributes",
198    arguments = "string",
199    actions   = attributes.restore
200}
201