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