s-math-characters.lua /size: 12 Kb    last modification: 2023-12-21 09:45
1if not modules then modules = { } end modules['s-math-characters'] = {
2    version   = 1.001,
3    comment   = "companion to s-math-characters.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-- This is one of the oldest cld files but I'm not going to clean it up.
10
11moduledata.math            = moduledata.math            or { }
12moduledata.math.characters = moduledata.math.characters or { }
13
14local concat = table.concat
15local lower = string.lower
16local utfchar = utf.char
17local round = math.round
18local setmetatableindex = table.setmetatableindex
19local sortedhash = table.sortedhash
20
21local context        = context
22
23local fontdata       = fonts.hashes.identifiers
24local chardata       = characters.data
25local blocks         = characters.blocks
26
27local no_description = "no description, private to font"
28
29local limited        = true
30local fillinthegaps  = true
31local upperlimit     = 0x0007F
32local upperlimit     = 0xF0000
33
34local f_unicode      = string.formatters["%U"]
35local f_slot         = string.formatters["%s/%0X"]
36
37function moduledata.math.characters.showlist(specification)
38    specification     = interfaces.checkedspecification(specification)
39    local id          = specification.number -- or specification.id
40    local list        = specification.list
41    local showvirtual = specification.virtual == "all"
42    local check       = specification.check == "yes"
43    if not id then
44        id = font.current()
45    end
46    if list == "" then
47        list = nil
48    end
49    local tfmdata      = fontdata[id]
50    local characters   = tfmdata.characters
51    local descriptions = tfmdata.descriptions
52    local resources    = tfmdata.resources
53    local lookuptypes  = resources.lookuptypes
54    local virtual      = tfmdata.properties.virtualized
55    local names        = { }
56    local gaps         = mathematics.gaps
57    local sorted       = { }
58    if type(list) == "string" then
59        sorted = utilities.parsers.settings_to_array(list)
60        for i=1,#sorted do
61            sorted[i] = tonumber(sorted[i])
62        end
63    elseif type(list) == "table" then
64        sorted = list
65        for i=1,#sorted do
66            sorted[i] = tonumber(sorted[i])
67        end
68    elseif fillinthegaps then
69        sorted = table.keys(characters)
70        for k, v in next, gaps do
71            if characters[v] then
72                sorted[#sorted+1] = k
73            end
74        end
75        table.sort(sorted)
76    else
77        sorted = table.sortedkeys(characters)
78    end
79    if virtual then
80        local fonts = tfmdata.fonts
81        for i=1,#fonts do
82            local id = fonts[i].id
83            local name = fontdata[id].properties.name
84            names[i] = (name and file.basename(name)) or id
85        end
86    end
87    if check then
88        for k, v in table.sortedhash(blocks) do
89            if v.math then
90                local first = v.first
91                local last  = v.last
92                local f, l  = 0, 0
93                if first and last then
94                    for unicode=first,last do
95                        local code = gaps[unicode] or unicode
96                        local char = characters[code]
97                        if char and not (char.commands and not showvirtual) then
98                            f = unicode
99                            break
100                        end
101                    end
102                    for unicode=last,first,-1 do
103                        local code = gaps[unicode] or unicode
104                        local char = characters[code]
105                        if char and not (char.commands and not showvirtual) then
106                            l = unicode
107                            break
108                        end
109                    end
110                    context.showmathcharacterssetrange(k,f,l)
111                end
112            end
113        end
114    else
115
116        local function collectalllookups(tfmdata,script,language)
117            local all     = setmetatableindex(function(t,k) local v = setmetatableindex("table") t[k] = v return v end)
118            local shared  = tfmdata.shared
119            local rawdata = shared and shared.rawdata
120            if rawdata then
121                local features = rawdata.resources.features
122                if features.gsub then
123                    for kind, feature in next, features.gsub do
124                        local validlookups, lookuplist = fonts.handlers.otf.collectlookups(rawdata,kind,script,language)
125                        if validlookups then
126                            for i=1,#lookuplist do
127                                local lookup = lookuplist[i]
128                                local steps  = lookup.steps
129                                for i=1,lookup.nofsteps do
130                                    local coverage = steps[i].coverage
131                                    if coverage then
132                                        for k, v in next, coverage do
133                                            all[k][lookup.type][kind] = v
134                                        end
135                                    end
136                                end
137                            end
138                        end
139                    end
140                end
141            end
142            return all
143        end
144
145        local alllookups = collectalllookups(tfmdata,"math","dflt")
146
147        local luametatex = LUATEXENGINE == "luametatex"
148
149        context.showmathcharactersstart()
150        for _, unicode in next, sorted do
151            if not limited or unicode < upperlimit then
152                local code = gaps[unicode] or unicode
153                local char = characters[code]
154                local desc = descriptions[code]
155                local info = chardata[code]
156                if char then
157                    local commands    = char.commands
158                    if commands and not showvirtual then
159                        -- skip
160                    else
161                        local next_sizes  = char.next
162                        local vparts      = char.vparts or char.vert_variants
163                        local hparts      = char.hparts or char.horiz_variants
164                        local mathclass   = info.mathclass
165                        local mathspec    = info.mathspec
166                        local mathsymbol  = info.mathsymbol
167                        local description = info.description or no_description
168                        context.showmathcharactersstartentry(
169                        )
170                        context.showmathcharactersreference(
171                            f_unicode(unicode)
172                        )
173                        context.showmathcharactersentryhexdectit(
174                            f_unicode(code),
175                            code,
176                            lower(description)
177                        )
178                        if luametatex then
179                            context.showmathcharactersentrywdhtdpicta(
180                                code
181                            )
182                        else
183                            context.showmathcharactersentrywdhtdpicta(
184                                round(char.width     or 0),
185                                round(char.height    or 0),
186                                round(char.depth     or 0),
187                                round(char.italic    or 0),
188                                round(char.topanchor or char.topaccent or 0)
189                            )
190                        end
191                        if virtual and commands then
192                            local t = { }
193                            for i=1,#commands do
194                                local ci = commands[i]
195                                if ci[1] == "slot" then
196                                    local fnt, idx = ci[2], ci[3]
197                                    t[#t+1] = f_slot(names[fnt] or fnt,idx)
198                                end
199                            end
200                            if #t > 0 then
201                                context.showmathcharactersentryresource(concat(t,", "))
202                            end
203                        end
204                        if mathclass or mathspec then
205                            context.showmathcharactersstartentryclassspec()
206                            if mathclass then
207                                context.showmathcharactersentryclassname(mathclass,info.mathname or "no name")
208                            end
209                            if mathspec then
210                                for i=1,#mathspec do
211                                    local mi = mathspec[i]
212                                    context.showmathcharactersentryclassname(mi.class,mi.name or "no name")
213                                end
214                            end
215                            context.showmathcharactersstopentryclassspec()
216                        end
217                        if mathsymbol then
218                            context.showmathcharactersentrysymbol(f_unicode(mathsymbol),mathsymbol)
219                        end
220                        if next_sizes then
221                            local n, done = 0, { }
222                            context.showmathcharactersstartnext()
223                            while next_sizes do
224                                n = n + 1
225                                if done[next_sizes] then
226                                    context.showmathcharactersnextcycle(n)
227                                    break
228                                else
229                                    done[next_sizes] = true
230                                    context.showmathcharactersnextentry(n,f_unicode(next_sizes),next_sizes)
231                                    next_sizes = characters[next_sizes]
232                                    vparts = next_sizes.vparts or next_sizes.vert_variants  or vparts
233                                    hparts = next_sizes.hparts or next_sizes.horiz_variants or hparts
234                                    if next_sizes then
235                                        next_sizes = next_sizes.next
236                                    end
237                                end
238                            end
239                            context.showmathcharactersstopnext()
240                            if vparts or hparts then
241                                context.showmathcharactersbetweennextandvariants()
242                            end
243                        end
244                        if vparts then
245                            context.showmathcharactersstartvparts()
246                            for i=1,#vparts do -- we might go top-down in the original
247                                local vi = vparts[i]
248                                context.showmathcharactersvpartsentry(i,f_unicode(vi.glyph),vi.glyph)
249                            end
250                            context.showmathcharactersstopvparts()
251                        end
252                        if hparts then
253                            context.showmathcharactersstarthparts()
254                            for i=1,#hparts do
255                                local hi = hparts[#hparts-i+1]
256                                context.showmathcharactershpartsentry(i,f_unicode(hi.glyph),hi.glyph)
257                            end
258                            context.showmathcharactersstophparts()
259                        end
260                        local lookups = alllookups[unicode]
261                        if lookups then
262                            local variants   = { }
263                            local singles    = lookups.gsub_single
264                            local alternates = lookups.gsub_alternate
265                            if singles then
266                                for lookupname, code in next, singles do
267                                    variants[code] = lookupname
268                                end
269                            end
270                            if singles then
271                                for lookupname, codes in next, alternates do
272                                    for i=1,#codes do
273                                        variants[codes[i]] = lookupname .. " : " .. i
274                                    end
275                                end
276                            end
277                            context.showmathcharactersstartlookupvariants()
278                            local i = 0
279                            for variant, lookuptype in sortedhash(variants) do
280                                i = i + 1
281                                context.showmathcharacterslookupvariant(i,f_unicode(variant),variant,lookuptype)
282                            end
283                            context.showmathcharactersstoplookupvariants()
284                        end
285                        context.showmathcharactersstopentry()
286                    end
287                end
288            end
289        end
290        context.showmathcharactersstop()
291    end
292end
293