s-math-characters.lua /size: 17 Kb    last modification: 2025-02-21 11:03
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
37-- do
38--
39--     local chardata = characters.data
40--     local blocks   = characters.blocks
41--
42--     local ismath = { }
43--
44--     setmetatableindex(ismath,function(t,k)
45--         local function add(t,b)
46--             local m = blocks[b]
47--             for i=m.first,m.last do
48--                 t[i] = b
49--             end
50--         end
51-- --         add(t,"mathematicaloperators")
52-- --         add(t,"miscellaneousmathematicalsymbolsa")
53-- --         add(t,"miscellaneousmathematicalsymbolsb")
54-- --         add(t,"miscellaneoussymbolsandarrows")
55-- --         add(t,"miscellaneoustechnical")
56-- --         add(t,"supplementalarrowsa")
57-- --         add(t,"supplementalarrowsb")
58-- --         add(t,"supplementalarrowsc")
59-- --         add(t,"supplementalmathematicaloperators")
60--         setmetatableindex(ismath)
61--         return ismath[k]
62--     end)
63--
64--     local s = lpeg.P(" ")
65-- --         local p = lpeg.Cs(lpeg.Cc("unim") * (lpeg.P(1) * ((1 - s)^0/"") * (s^0/""))^1)
66--     local p = lpeg.Cs((lpeg.P(1) * ((1 - s)^0/"") * (s^0/""))^1)
67--
68--     local function fakename(description)
69--         return lpeg.match(p,description)
70--     end
71--
72--     local hash = { }
73--
74--     for k,v in next, chardata do
75--         if ismath[k] then
76--             local description = v.description
77--             if description then
78--                 local description = lower(description)
79--                 local somename = "unum" .. v.category .. fakename(description)
80--                 if hash[somename] then
81--                     print("!!!!!!!!!!!!!!!!!",somename,hash[somename],description)
82--                 else
83--                     hash[somename] = description
84--                 end
85--         --         print(description,somename)
86--             end
87--         end
88--     end
89--
90-- end
91
92function moduledata.math.characters.showlist(specification)
93    specification     = interfaces.checkedspecification(specification)
94    local id          = specification.number -- or specification.id
95    local list        = specification.list
96    local showvirtual = specification.virtual == "all"
97    local method      = specification.method
98    if not id then
99        id = font.current()
100    end
101    if list == "" then
102        list = nil
103    end
104    local blocks       = characters.blocks
105    local tfmdata      = fontdata[id]
106    local characters   = tfmdata.characters
107    local descriptions = tfmdata.descriptions
108    local resources    = tfmdata.resources
109    local lookuptypes  = resources.lookuptypes
110    local virtual      = tfmdata.properties.virtualized
111    local names        = { }
112    local gaps         = mathematics.gaps
113    local sorted       = { }
114    if type(list) == "string" then
115        -- also accept list
116        local b = blocks[list]
117        if b then
118            sorted = { }
119            for i=b.first,b.last do
120                sorted[#sorted+1] = gaps[i] or i
121            end
122        else
123            sorted = utilities.parsers.settings_to_array(list)
124            for i=1,#sorted do
125                sorted[i] = tonumber(sorted[i])
126            end
127        end
128    elseif type(list) == "table" then
129        sorted = list
130        for i=1,#sorted do
131            sorted[i] = tonumber(sorted[i])
132        end
133    elseif fillinthegaps then
134        sorted = table.keys(characters)
135        for k, v in next, gaps do
136            if characters[v] then
137                sorted[#sorted+1] = k
138            end
139        end
140        table.sort(sorted)
141    else
142        sorted = table.sortedkeys(characters)
143    end
144    if virtual then
145        local fonts = tfmdata.fonts
146        for i=1,#fonts do
147            local id = fonts[i].id
148            local name = fontdata[id].properties.name
149            names[i] = (name and file.basename(name)) or id
150        end
151    end
152    if check then
153        for k, v in sortedhash(blocks) do
154            if v.math then
155                local first = v.first
156                local last  = v.last
157                local f, l  = 0, 0
158                if first and last then
159                    for unicode=first,last do
160                        local code = gaps[unicode] or unicode
161                        local char = characters[code]
162                        if char and not (char.commands and not showvirtual) then
163                            f = unicode
164                            break
165                        end
166                    end
167                    for unicode=last,first,-1 do
168                        local code = gaps[unicode] or unicode
169                        local char = characters[code]
170                        if char and not (char.commands and not showvirtual) then
171                            l = unicode
172                            break
173                        end
174                    end
175                    context.showmathcharacterssetrange(k,f,l)
176                end
177            end
178        end
179    else
180
181        local function collectalllookups(tfmdata,script,language)
182            local all     = setmetatableindex(function(t,k) local v = setmetatableindex("table") t[k] = v return v end)
183            local shared  = tfmdata.shared
184            local rawdata = shared and shared.rawdata
185            if rawdata then
186                local features = rawdata.resources.features
187                if features.gsub then
188                    for kind, feature in next, features.gsub do
189                        local validlookups, lookuplist = fonts.handlers.otf.collectlookups(rawdata,kind,script,language)
190                        if validlookups then
191                            for i=1,#lookuplist do
192                                local lookup = lookuplist[i]
193                                local steps  = lookup.steps
194                                for i=1,lookup.nofsteps do
195                                    local coverage = steps[i].coverage
196                                    if coverage then
197                                        for k, v in next, coverage do
198                                            all[k][lookup.type][kind] = v
199                                        end
200                                    end
201                                end
202                            end
203                        end
204                    end
205                end
206            end
207            return all
208        end
209
210        local alllookups = collectalllookups(tfmdata,"math","dflt")
211
212        local luametatex = LUATEXENGINE == "luametatex"
213
214        -- todo: first create sparser table so no test needed
215
216if method == "manual" then
217
218        context.starttabulate { "|T||||pl|" }
219        for _, unicode in next, sorted do
220            if not limited or unicode < upperlimit then
221                local code = gaps[unicode] or unicode -- move up
222                local char = characters[code]
223                local desc = descriptions[code]
224                local info = chardata[unicode] or chardata[code]
225                if char then
226                    local mathclass   = info.mathclass
227                    local mathspec    = info.mathspec
228                    local mathsymbol  = info.mathsymbol
229                    local description = lower(info.description or no_description)
230                    local names       = { }
231                    if mathclass or mathspec then
232                        if mathclass then
233                            names[info.mathname or ""] = mathclass
234                        end
235                        if mathspec then
236                            for i=1,#mathspec do
237                                local mi = mathspec[i]
238                                names[mi.name or ""] = mi.class
239                            end
240                        end
241                    end
242--                     print(description,fakename(description))
243                    if next(names) then
244                        local doit = true
245                        for k, v in sortedhash(names) do
246                            context.NC() if doit then context("%U",unicode) end
247                            context.NC() if doit then context.char(unicode) end
248                            context.NC() if k ~= "" then context.tex(k) end
249                            context.NC() context.ex(v)
250                            context.NC() if doit then context(description) end
251                            context.NC() context.NR()
252                            doit = false
253                        end
254                    else
255                        local mathname = info.mathname
256                        context.NC() context("%U",unicode)
257                        context.NC() context.char(unicode)
258                        context.NC() if mathname then context.tex(mathname) end
259                        context.NC() context("ordinary")
260                        context.NC() context(lower(description))
261                        context.NC() context.NR()
262                    end
263                end
264            end
265        end
266        context.stoptabulate()
267
268else
269
270        context.showmathcharactersstart()
271        for _, unicode in next, sorted do
272            if not limited or unicode < upperlimit then
273                local code = gaps[unicode] or unicode -- move up
274                local char = characters[code]
275                local desc = descriptions[code]
276                local info = chardata[code]
277                if char then
278-- context(utf.char(char.smaller))
279                    local commands = char.commands
280                    if commands and not showvirtual then
281                        -- skip
282                    else
283                        local next_sizes  = char.next
284                        local vparts      = char.vparts or char.vert_variants
285                        local hparts      = char.hparts or char.horiz_variants
286                        local mathclass   = info.mathclass
287                        local mathspec    = info.mathspec
288                        local mathsymbol  = info.mathsymbol
289                        local description = info.description or no_description
290                        context.showmathcharactersstartentry(
291                        )
292                        context.showmathcharactersreference(
293                            f_unicode(unicode)
294                        )
295                        context.showmathcharactersentryhexdectit(
296                            f_unicode(code),
297                            code,
298                            lower(description)
299                        )
300                        if luametatex then
301                            context.showmathcharactersentrywdhtdpicta(
302                                code
303                            )
304                        else
305                            context.showmathcharactersentrywdhtdpicta(
306                                round(char.width     or 0),
307                                round(char.height    or 0),
308                                round(char.depth     or 0),
309                                round(char.italic    or 0),
310                                round(char.topanchor or char.topaccent or 0)
311                            )
312                        end
313                        if virtual and commands then
314                            local t = { }
315                            for i=1,#commands do
316                                local ci = commands[i]
317                                if ci[1] == "slot" then
318                                    local fnt, idx = ci[2], ci[3]
319                                    t[#t+1] = f_slot(names[fnt] or fnt,idx)
320                                end
321                            end
322                            if #t > 0 then
323                                context.showmathcharactersentryresource(concat(t,", "))
324                            end
325                        end
326                        if mathclass or mathspec then
327                            context.showmathcharactersstartentryclassspec()
328                            if mathclass then
329                                context.showmathcharactersentryclassname(mathclass,info.mathname or "no name")
330                            end
331                            if mathspec then
332                                for i=1,#mathspec do
333                                    local mi = mathspec[i]
334                                    context.showmathcharactersentryclassname(mi.class,mi.name or "no name")
335                                end
336                            end
337                            context.showmathcharactersstopentryclassspec()
338                        end
339                        if mathsymbol then
340                            context.showmathcharactersentrysymbol(f_unicode(mathsymbol),mathsymbol)
341                        end
342                        if next_sizes then
343                            local n, done = 0, { }
344                            context.showmathcharactersstartnext()
345                            while next_sizes do
346                                n = n + 1
347                                if done[next_sizes] then
348                                    context.showmathcharactersnextcycle(n)
349                                    break
350                                else
351                                    done[next_sizes] = true
352                                    context.showmathcharactersnextentry(n,f_unicode(next_sizes),next_sizes)
353                                    next_sizes = characters[next_sizes]
354                                    vparts = next_sizes.vparts or next_sizes.vert_variants  or vparts
355                                    hparts = next_sizes.hparts or next_sizes.horiz_variants or hparts
356                                    if next_sizes then
357                                        next_sizes = next_sizes.next
358                                    end
359                                end
360                            end
361                            context.showmathcharactersstopnext()
362                            if vparts or hparts then
363                                context.showmathcharactersbetweennextandvariants()
364                            end
365                        end
366                        if vparts then
367                            context.showmathcharactersstartvparts()
368                            for i=1,#vparts do -- we might go top-down in the original
369                                local vi = vparts[i]
370                                context.showmathcharactersvpartsentry(i,f_unicode(vi.glyph),vi.glyph)
371                            end
372                            context.showmathcharactersstopvparts()
373                        end
374                        if hparts then
375                            context.showmathcharactersstarthparts()
376                            for i=1,#hparts do
377                                local hi = hparts[#hparts-i+1]
378                                context.showmathcharactershpartsentry(i,f_unicode(hi.glyph),hi.glyph)
379                            end
380                            context.showmathcharactersstophparts()
381                        end
382                        local lookups = alllookups[unicode]
383                        if lookups then
384                            local variants   = { }
385                            local singles    = lookups.gsub_single
386                            local alternates = lookups.gsub_alternate
387                            if singles then
388                                for lookupname, code in next, singles do
389                                    variants[code] = lookupname
390                                end
391                            end
392                            if singles then
393                                for lookupname, codes in next, alternates do
394                                    for i=1,#codes do
395                                        variants[codes[i]] = lookupname .. " : " .. i
396                                    end
397                                end
398                            end
399                            if next(variants) then
400                                context.showmathcharactersstartlookupvariants()
401                                local i = 0
402                                for variant, lookuptype in sortedhash(variants) do
403                                    i = i + 1
404                                    context.showmathcharacterslookupvariant(i,f_unicode(variant),variant,lookuptype)
405                                end
406                                context.showmathcharactersstoplookupvariants()
407                            end
408                        end
409                        context.showmathcharactersstopentry()
410                    end
411                end
412            end
413        end
414        context.showmathcharactersstop()
415
416end
417
418    end
419end
420