mtx-interface.lua /size: 33 Kb    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['mtx-cache'] = {
2    version   = 1.001,
3    comment   = "companion to mtxrun.lua",
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 concat, sort, insert = table.concat, table.sort, table.insert
10local gsub, format, gmatch, find, upper = string.gsub, string.format, string.gmatch, string.find, string.upper
11local utfchar, utfgsub = utf.char, utf.gsub
12local sortedkeys, sortedhash, serialize = table.sortedkeys, table.sortedhash, table.serialize
13
14-- <subcategory>
15-- <flag name="mkii"><short>generate context mkii interface files</short></flag>
16-- </subcategory>
17
18local helpinfo = [[
19<?xml version="1.0"?>
20<application>
21 <metadata>
22  <entry name="name">mtx-interface</entry>
23  <entry name="detail">ConTeXt Interface Related Goodies</entry>
24  <entry name="version">0.13</entry>
25 </metadata>
26 <flags>
27  <category name="basic">
28   <subcategory>
29    <flag name="scite"><short>generate scite interface</short></flag>
30    <flag name="bbedit"><short>generate bbedit interface files</short></flag>
31    <flag name="jedit"><short>generate jedit interface files</short></flag>
32    <flag name="textpad"><short>generate textpad interface files</short></flag>
33    <flag name="vim"><short>generate vim interface files</short></flag>
34    <flag name="text"><short>create text files for commands and environments</short></flag>
35    <flag name="raw"><short>report commands to the console</short></flag>
36    <flag name="check"><short>generate check file</short></flag>
37    <flag name="meaning"><short>report the mening of commands</short></flag>
38    <flag name="tokens"><short>show the internal representation of commands</short></flag>
39   </subcategory>
40   <subcategory>
41    <flag name="toutf"><short>replace named characters by utf</short></flag>
42    <flag name="preprocess"><short>preprocess mkvi files to tex files [force,suffix]</short></flag>
43   </subcategory>
44   <subcategory>
45    <flag name="suffix"><short>use given suffix for output files</short></flag>
46    <flag name="force"><short>force action even when in doubt</short></flag>
47   </subcategory>
48   <subcategory>
49    <flag name="pattern"><short>a pattern for meaning lookups</short></flag>
50   </subcategory>
51  </category>
52 </flags>
53</application>
54]]
55
56local application = logs.application {
57    name     = "mtx-interface",
58    banner   = "ConTeXt Interface Related Goodies 0.13",
59    helpinfo = helpinfo,
60}
61
62local report = application.report
63
64scripts           = scripts           or { }
65scripts.interface = scripts.interface or { }
66
67local flushers          = { }
68local userinterfaces    = { 'en','cs','de','it','nl','ro','fr','pe' }
69
70local function collect(filename,class,data)
71    if data then
72        local result, r = { }, 0
73        for name, list in sortedhash(data) do
74            r = r + 1 ; result[r] = format("keywordclass.%s.%s=\\\n",class,name)
75            for i=1,#list do
76                if i%5 == 0 then
77                    r = r + 1 ; result[r] = "\\\n"
78                end
79                r = r + 1 ; result[r] = format("%s ",list[i])
80            end
81            r = r + 1 ; result[r] = "\n\n"
82        end
83        io.savedata(file.addsuffix(filename,"properties"),concat(result))
84        io.savedata(file.addsuffix(filename,"lua"),serialize(data,true))
85    else
86        os.remove(filename)
87    end
88end
89
90function flushers.scite(collected)
91    local data = { }
92--     for interface, whatever in next, collected do
93--         data[interface] = whatever.commands
94--     end
95    local function add(target,origin,field)
96        if origin then
97            local list = origin[field]
98            if list then
99                for i=1,#list do
100                    target[list[i]] = true
101                end
102            end
103        end
104    end
105    --
106    for interface, whatever in next, collected do
107        local combined = { }
108        add(combined,whatever,"commands")
109        add(combined,whatever,"environments")
110        if interface == "common" then
111            add(combined,whatever,"textnames")
112            add(combined,whatever,"mathnames")
113        end
114        data[interface] = sortedkeys(combined)
115    end
116    --
117    collect("scite-context-data-interfaces", "context",  data)
118    collect("scite-context-data-metapost",   "metapost", dofile(resolvers.findfile("mult-mps.lua")))
119    collect("scite-context-data-metafun",    "metafun",  dofile(resolvers.findfile("mult-fun.lua")))
120    collect("scite-context-data-context",    "context",  dofile(resolvers.findfile("mult-low.lua")))
121    collect("scite-context-data-tex",        "tex",      dofile(resolvers.findfile("mult-prm.lua")))
122end
123
124function flushers.jedit(collected)
125    for interface, whatever in next, collected do
126        local commands     = whatever.commands
127        local environments = whatever.environments
128        local result, r = { }, 0
129        r = r + 1 ; result[r] = "<?xml version='1.0'?>"
130        r = r + 1 ; result[r] = "<!DOCTYPE MODE SYSTEM 'xmode.dtd'>\n"
131        r = r + 1 ; result[r] = "<MODE>"
132        r = r + 1 ; result[r] = "\t<RULES>"
133        r = r + 1 ; result[r] = "\t\t<KEYWORDS>"
134        for i=1,#commands do
135            r = r + 1 ; result[r] = format("\t\t\t<KEYWORD2>%s</KEYWORD2>",commands[i])
136        end
137        r = r + 1 ; result[r] = "\t\t</KEYWORDS>"
138        r = r + 1 ; result[r] = "\t</RULES>"
139        r = r + 1 ; result[r] = "</MODE>"
140        io.savedata(format("context-jedit-%s.xml",interface), concat(result),"\n")
141    end
142end
143
144function flushers.bbedit(collected)
145    for interface, whatever in next, collected do
146        local commands     = whatever.commands
147        local environments = whatever.environments
148        local result, r = { }, 0
149        r = r + 1 ; result[r] = "<?xml version='1.0'?>"
150        r = r + 1 ; result[r] = "<key>BBLMKeywordList</key>"
151        r = r + 1 ; result[r] = "<array>"
152        for i=1,#commands do
153            r = r + 1 ; result[r] = format("\t<string>\\%s</string>",commands[i])
154        end
155        r = r + 1 ; result[r] = "</array>"
156        io.savedata(format("context-bbedit-%s.xml",interface), concat(result),"\n")
157    end
158end
159
160-- The Vim export is maintained by Nicola Vitacolonna:
161
162local function vimcollect(filename,class,data)
163    if data then
164        local result, r = { }, 0
165        local endline = " contained\n"
166        if find(class,"^meta") then
167            endline = "\n"
168        end
169        r = r + 1 ; result[r] = "vim9script\n\n"
170        r = r + 1 ; result[r] = "# Vim syntax file\n"
171        r = r + 1 ; result[r] = "# Language: ConTeXt\n"
172        r = r + 1 ; result[r] = format("# Automatically generated by mtx-interface (%s)\n\n", os.date())
173        local n = 5 -- number of keywords per row
174        for name, list in sortedhash(data) do
175            local i = 1
176            while i <= #list do
177                r = r + 1 ; result[r] = format("syn keyword %s%s", class, (gsub(name,"^%l",upper))) -- upper is fragile
178                local j = 0
179--                 while i+j <= #list and j < n do
180--                     if list[i+j] == "transparent" then -- this is a Vim keyword
181--                         r = r + 1 ; result[r] = format(" %s[]",list[i+j])
182--                     else
183--                         r = r + 1 ; result[r] = format(" %s",list[i+j])
184--                     end
185--                     j = j + 1
186--                 end
187                while j < n do
188                    local lij = list[i + j]
189                    if not lij then
190                        break
191                    elseif lij == "transparent" then -- this is a Vim keyword
192                        r = r + 1 ; result[r] = format(" %s[]",lij)
193                    else
194                        r = r + 1 ; result[r] = format(" %s",lij)
195                    end
196                    j = j + 1
197                end
198                r = r + 1 ; result[r] = endline
199                i = i + n
200            end
201        end
202        io.savedata(file.addsuffix(filename,"vim"),concat(result))
203    else
204        os.remove(filename)
205    end
206end
207
208function flushers.vim(collected)
209    local data = { }
210 -- for interface, whatever in next, collected do
211 --     data[interface] = whatever.commands
212 -- end
213    local function add(target,origin,field)
214        if origin then
215            local list = origin[field]
216            if list then
217                for i=1,#list do
218                    target[list[i]] = true
219                end
220            end
221        end
222    end
223    --
224    for interface, whatever in next, collected do
225        local combined = { }
226        add(combined,whatever,"commands")
227        add(combined,whatever,"environments")
228        if interface == "common" then
229            add(combined,whatever,"textnames")
230            add(combined,whatever,"mathnames")
231        end
232        data[interface] = sortedkeys(combined)
233    end
234    --
235    vimcollect("context-data-interfaces", "context",  data)
236 -- vimcollect("context-data-metapost",   "metapost", dofile(resolvers.findfile("mult-mps.lua")))
237    vimcollect("context-data-metafun",    "metafun",  dofile(resolvers.findfile("mult-fun.lua")))
238    vimcollect("context-data-context",    "context",  dofile(resolvers.findfile("mult-low.lua")))
239    vimcollect("context-data-tex",        "tex",      dofile(resolvers.findfile("mult-prm.lua")))
240end
241
242function flushers.raw(collected)
243    for interface, whatever in next, collected do
244        local commands     = whatever.commands
245        local environments = whatever.environments
246        for i=1,#commands do
247            report(commands[i])
248        end
249    end
250end
251
252function flushers.data(collected)
253    return collected -- table.save("cont-en-filenames.lua",collected.filenames)
254end
255
256local textpadcreator = "mtx-interface-textpad.lua"
257
258function flushers.text(collected)
259    for interface, whatever in next, collected do
260        local commands     = whatever.commands
261        local environments = whatever.environments
262        local c, cname = { }, format("context-commands-%s.txt",interface)
263        local e, ename = { }, format("context-environments-%s.txt",interface)
264        report("saving '%s'",cname)
265        for i=1,#commands do
266            c[#c+1] = format("\\%s",commands[i])
267        end
268        io.savedata(cname,concat(c,"\n"))
269        report("saving '%s'",ename)
270        for i=1,#environments do
271            e[#e+1] = format("\\start%s",environments[i])
272            e[#e+1] = format("\\stop%s", environments[i])
273        end
274        io.savedata(format("context-environments-%s.txt",interface),concat(e,"\n"))
275    end
276end
277
278function flushers.textpad(collected)
279    flushers.text(collected)
280    for interface, whatever in next, collected do
281        local commands     = whatever.commands
282        local environments = whatever.environments
283        --
284        -- plugin, this is a rewrite of a file provided by Lukas Prochazka
285        --
286        local function merge(templatedata,destinationdata,categories)
287            report("loading '%s'",templatedata)
288            local data = io.loaddata(templatedata)
289            local done = 0
290            for i=1,#categories do
291                local category = categories[i]
292                local cpattern = ";%s*category:%s*(" .. category .. ")%s*[\n\r]+"
293                local fpattern = ";%s*filename:%s*(" .. "%S+"     .. ")%s*[\n\r]+"
294                data = gsub(data,cpattern..fpattern,function(category,filename)
295                    local found = resolvers.findfile(filename) or ""
296                    local blob = found ~= "" and io.loaddata(found) or ""
297                    if blob == ""  then
298                        report("category: %s, filename: %s, not found",category,filename)
299                    else
300                        done = done + 1
301                        report("category: %s, filename: %s, merged",category,filename)
302                    end
303                    return format("; category: %s\n; filename: %s\n%s\n\n",category,filename,blob)
304                end)
305            end
306            if done > 0 then
307                report("saving '%s' (%s files merged)",destinationdata,done)
308                io.savedata(destinationdata,data)
309            else
310                report("skipping '%s' (no files merged)",destinationdata)
311            end
312        end
313        local templatename = "textpad-context-template.txt"
314        local templatedata = resolvers.findfile(templatename) or ""
315        if templatedata == "" then
316            report("unable to locate template '%s'",templatename)
317        else
318            merge(templatedata, "context.syn",       { "tex commands","context commands" })
319            if environment.argument("textpad") == "latex" then
320                merge(templatedata, "context-latex.syn", { "tex commands","context commands", "latex commands" })
321            end
322        end
323        local r = { }
324        local c = io.loaddata("context-commands-en.txt")     or "" -- sits on the same path
325        local e = io.loaddata("context-environments-en.txt") or "" -- sits on the same path
326        for s in gmatch(c,"\\(.-)%s") do
327            r[#r+1] = format("\n!TEXT=%s\n\\%s\n!",s,s)
328        end
329        for s in gmatch(e,"\\start(.-)%s+\\stop(.-)") do
330            r[#r+1] = format("\n!TEXT=%s (start/stop)\n\\start%s \\^\\stop%s\n!",s,s,s)
331        end
332        sort(r)
333        insert(r,1,"!TCL=597,\n!TITLE=ConTeXt\n!SORT=N\n!CHARSET=DEFAULT")
334        io.savedata("context.tcl",concat(r,"\n"))
335        -- cleanup
336        os.remove("context-commands-en.txt")
337        os.remove("context-environments-en.txt")
338    end
339end
340
341function scripts.interface.editor(editor,split,forcedinterfaces)
342    require("char-def")
343
344    local interfaces = forcedinterfaces or environment.files or userinterfaces
345    if not interfaces.en then
346        -- loaded as script so we have "cont-yes.*" as name
347        interfaces = { "en" }
348    end
349    --
350 -- local filename = "i-context.xml"
351    local filename = "context-en.xml"
352    local xmlfile  = resolvers.findfile(filename) or ""
353    if xmlfile == "" then
354        report("unable to locate %a",filename)
355        return
356    end
357    --
358    local filename = "mult-def.lua"
359    local deffile  = resolvers.findfile(filename) or ""
360    if deffile == "" then
361        report("unable to locate %a",filename)
362        return
363    end
364    local interface = dofile(deffile)
365    if not interface or not next(interface) then
366        report("invalid file %a",filename)
367        return
368    end
369    local variables = interface.variables
370    local constants = interface.constants
371    local commands  = interface.commands
372    local elements  = interface.elements
373    --
374    local collected = { }
375    --
376    report("generating files for %a",editor)
377    report("loading %a",xmlfile)
378    local xmlroot = xml.load(xmlfile)
379 -- xml.include(xmlroot,"cd:interfacefile","filename",true,function(s)
380 --     local fullname = resolvers.findfile(s)
381 --     if fullname and fullname ~= "" then
382 --         report("including %a",fullname)
383 --         return io.loaddata(fullname)
384 --     end
385 -- end)
386 -- local definitions = { }
387 -- for e in xml.collected(xmlroot,"cd:interface/cd:define") do
388 --     definitions[e.at.name] = e.dt
389 -- end
390 -- local function resolve(root)
391 --     for e in xml.collected(root,"*") do
392 --         if e.tg == "resolve" then
393 --             local resolved = definitions[e.at.name or ""]
394 --             if resolved then
395 --                 -- use proper replace helper
396 --                 e.__p__.dt[e.ni] = resolved
397 --                 resolved.__p__ = e.__p__
398 --                 resolve(resolved)
399 --             end
400 --         end
401 --     end
402 -- end
403 -- resolve(xmlroot)
404
405    -- todo: use sequence
406
407    for i=1,#interfaces do
408        local interface      = interfaces[i]
409        local i_commands     = { }
410        local i_environments = { }
411        local start = elements.start[interface] or elements.start.en
412        local stop  = elements.stop [interface] or elements.stop .en
413        for e in xml.collected(xmlroot,"cd:interface/cd:command") do
414            local at   = e.at
415            local name = at["name"] or ""
416            local type = at["type"]
417            if name ~= "" then
418                local c = commands[name]
419                local n = c and (c[interface] or c.en) or name
420                local sequence = xml.all(e,"/cd:sequence/*")
421                if at.generated == "yes" then
422                    for e in xml.collected(e,"/cd:instances/cd:constant") do
423                        local name = e.at.value
424                        if name then
425                            local c = variables[name]
426                            local n = c and (c[interface] or c.en) or name
427                            if sequence then
428                                local done = { }
429                                for i=1,#sequence do
430                                    local e = sequence[i]
431                                    if e.tg == "string" then
432                                        local value = e.at.value
433                                        if value then
434                                            done[i] = value
435                                        else
436                                            done = false
437                                            break
438                                        end
439                                    else
440                                        local tg = e.tg
441                                        if tg == "instance" or tg == "instance:assignment" or tg == "instance:ownnumber" then
442                                            done[i] = name
443                                        else
444                                            done = false
445                                            break
446                                        end
447                                    end
448                                end
449                                if done then
450                                    n = concat(done)
451                                end
452                            end
453                            if type ~= "environment" then
454                                i_commands[n] = true
455                            elseif split then
456                                i_environments[n] = true
457                            else
458                                i_commands[start..n] = true
459                                i_commands[stop ..n] = true
460                            end
461                        end
462                    end
463                    -- skip (for now)
464                elseif type ~= "environment" then
465                    i_commands[n] = at.file or true
466                elseif split then
467                    i_environments[n] = at.file or true
468                else
469                    -- variables ?
470                    i_commands[start..n] = at.file or true
471                    i_commands[stop ..n] = at.file or true
472                end
473            end
474        end
475        if next(i_commands) then
476            collected[interface] = {
477                commands     = i_commands,
478                environments = i_environments,
479            }
480        end
481    end
482    --
483    local commoncommands     = { }
484    local commonenvironments = { }
485    for k, v in next, collected do
486        local c = v.commands
487        local e = v.environments
488        if k == "en" then
489            for k, v in next, c do
490                commoncommands[k] = true
491            end
492            for k, v in next, e do
493                commonenvironments[k] = true
494            end
495        else
496            for k, v in next, c do
497                if not commoncommands[k] then
498                    commoncommands[k] = nil
499                end
500            end
501            for k, v in next, e do
502                if not commonenvironments[k] then
503                    commonenvironments[k] = nil
504                end
505            end
506        end
507    end
508    local filenames = { }
509    if collected.en then
510        for k, v in next, collected.en.commands do
511            if v ~= true then
512                filenames[k] = v
513            end
514        end
515        for k, v in next, collected.en.environments do
516            if v ~= true then
517                filenames[k] = v
518            end
519        end
520    end
521    for k, v in next, collected do
522        local c = v.commands
523        local e = v.environments
524        for k, v in next, commoncommands do
525            c[k] = nil
526        end
527        for k, v in next, commonenvironments do
528            e[k] = nil
529        end
530        v.commands     = sortedkeys(c)
531        v.environments = sortedkeys(e)
532    end
533    --
534    local mathnames = { }
535    local textnames = { }
536    for k, v in next, characters.data do
537        local name = v.contextname
538        if name then
539            textnames[name] = true
540        end
541        local name = v.mathname
542        if name then
543            mathnames[name] = true
544        end
545        local spec = v.mathspec
546        if spec then
547            for i=1,#spec do
548                local s = spec[i]
549                local name = s.name
550                if name then
551                    mathnames[name] = true
552                end
553            end
554        end
555    end
556    --
557    collected.common = {
558        textnames    = sortedkeys(textnames),
559        mathnames    = sortedkeys(mathnames),
560        commands     = sortedkeys(commoncommands),
561        environments = sortedkeys(commonenvironments),
562        filenames    = filenames,
563    }
564    --
565    local flusher = flushers[editor]
566    if flusher then
567        return flusher(collected)
568    end
569end
570
571function scripts.interface.check()
572    local xmlfile = resolvers.findfile("cont-en.xml") or ""
573    if xmlfile ~= "" then
574        local f = io.open("cont-en-check.tex","w")
575        if f then
576            f:write("\\starttext\n")
577            local x = xml.load(xmlfile)
578            for e, d, k in xml.elements(x,"/cd:interface/cd:command") do
579                local dk = d[k]
580                local at = dk.at
581                if at then
582                    local name = xml.filter(dk,"cd:sequence/cd:string/attribute(value)")
583                    if name and name ~= "" then
584                        if at.type == "environment" then
585                            name = "start" .. name
586                        end
587                        f:write(format("\\doifundefined{%s}{\\writestatus{check}{command '%s' is undefined}}\n",name,name))
588                    end
589                end
590            end
591            f:write("\\stoptext\n")
592            f:close()
593        end
594    end
595end
596
597-- function scripts.interface.mkii()
598--     local filename = resolvers.findfile("mult-def.lua") or ""
599--     if filename ~= "" then
600--         local interface = dofile(filename)
601--         if interface and next(interface) then
602--             local variables, constants, commands, elements = interface.variables, interface.constants, interface.commands, interface.elements
603--             local filename = resolvers.findfile("context.xml") or ""
604--             local xmldata = filename ~= "" and (io.loaddata(filename) or "")
605--             if not xmldata then
606--                 report("no valid xml file %a",filename)
607--             else
608--                 local function flush(texresult,xmlresult,language,what,tag)
609--                     local t = interface[what]
610--                     texresult[#texresult+1] = format("%% definitions for interface %s for language %s\n%%",what,language)
611--                     xmlresult[#xmlresult+1] = format("\t<!-- definitions for interface %s for language %s -->\n",what,language)
612--                     xmlresult[#xmlresult+1] = format("\t<cd:%s>",what)
613--                     local sorted = sortedkeys(t)
614--                     for i=1,#sorted do
615--                         local key = sorted[i]
616--                         local v = t[key]
617--                         local value = v[language] or v["en"]
618--                         if not value then
619--                             report("warning, no value for key '%s' for language '%s'",key,language)
620--                         else
621--                             local value = t[key][language] or t[key].en
622--                             texresult[#texresult+1] = format("\\setinterface%s{%s}{%s}",tag,key,value)
623--                             xmlresult[#xmlresult+1] = format("\t\t<cd:%s name='%s' value='%s'/>",tag,key,value)
624--                         end
625--                     end
626--                     xmlresult[#xmlresult+1] = format("\t</cd:%s>\n",what)
627--                 end
628--                 local function replace(str, element, attribute, category, othercategory, language)
629--                     return str:gsub(format("(<%s[^>]-%s=)([\"\'])([^\"\']-)([\"\'])",element,attribute), function(a,b,c)
630--                         local cc = category[c]
631--                         if not cc and othercategory then
632--                             cc = othercategory[c]
633--                         end
634--                         if cc then
635--                             ccl = cc[language]
636--                             if ccl then
637--                                 return a .. b .. ccl .. b
638--                             end
639--                         end
640--                         return a .. b .. c .. b
641--                     end)
642--                 end
643--                 -- we could just replace attributes
644--                 for language, _ in next, commands.setuplayout do
645--                     -- keyword files
646--                     local texresult, xmlresult = { }, { }
647--                     texresult[#texresult+1] = format("%% this file is auto-generated, don't edit this file\n%%")
648--                     xmlresult[#xmlresult+1] = format("<?xml version='1.0'?>\n",tag)
649--                     xmlresult[#xmlresult+1] = format("<cd:interface xmlns:cd='http://www.pragma-ade.com/commands' name='context' language='%s' version='2008.10.21 19:42'>\n",language)
650--                     flush(texresult,xmlresult,language,"variables","variable")
651--                     flush(texresult,xmlresult,language,"constants","constant")
652--                     flush(texresult,xmlresult,language,"elements", "element")
653--                     flush(texresult,xmlresult,language,"commands", "command")
654--                     texresult[#texresult+1] = format("%%\n\\endinput")
655--                     xmlresult[#xmlresult+1] = format("</cd:interface>")
656--                     local texfilename = format("mult-%s.mkii",language)
657--                     local xmlfilename = format("keys-%s.xml",language)
658--                     io.savedata(texfilename,concat(texresult,"\n"))
659--                     report("saving interface definitions '%s'",texfilename)
660--                     io.savedata(xmlfilename,concat(xmlresult,"\n"))
661--                     report("saving interface translations '%s'",xmlfilename)
662--                     -- mkii files
663--                     if language ~= "en" and xmldata ~= "" then
664--                         local newdata = xmldata:gsub("(<cd:interface.*language=.)en(.)","%1"..language.."%2",1)
665--                      -- newdata = replace(newdata, 'cd:command', 'name', interface.commands, interface.elements, language)
666--                         newdata = replace(newdata, 'cd:string', 'value', interface.commands, interface.elements, language)
667--                         newdata = replace(newdata, 'cd:variable' , 'value', interface.variables, nil, language)
668--                         newdata = replace(newdata, 'cd:parameter', 'name', interface.constants, nil, language)
669--                         newdata = replace(newdata, 'cd:constant', 'type', interface.variables, nil, language)
670--                         newdata = replace(newdata, 'cd:variable', 'type', interface.variables, nil, language)
671--                         newdata = replace(newdata, 'cd:inherit', 'name', interface.commands, interface.elements, language)
672--                         local xmlfilename = format("cont-%s.xml",language)
673--                         io.savedata(xmlfilename,newdata)
674--                         report("saving interface specification '%s'",xmlfilename)
675--                     end
676--                     -- mkiv is generated otherwise
677--                 end
678--             end
679--         else
680--             report("no file %a",filename)
681--         end
682--     else
683--         report("no file %a","mult-def")
684--     end
685-- end
686
687function scripts.interface.preprocess()
688    require("luat-mac")
689
690    local newsuffix = environment.argument("suffix") or "log"
691    local force = environment.argument("force")
692    for i=1,#environment.files do
693        local oldname = environment.files[i]
694        local newname = file.replacesuffix(oldname,newsuffix)
695        if oldname == newname then
696            report("skipping '%s' because old and new name are the same",oldname)
697        elseif io.exists(newname) and not force then
698            report("skipping '%s' because new file exists, use --force",oldname)
699        else
700            report("processing '%s' into '%s'",oldname,newname)
701            io.savedata(newname,resolvers.macros.preprocessed(io.loaddata(oldname)))
702        end
703    end
704end
705
706function scripts.interface.bidi()
707    require("char-def")
708
709    local directiondata  = { }
710    local mirrordata     = { }
711    local textclassdata  = { }
712
713    local data = {
714        comment    = "generated by: mtxrun -- script interface.lua --bidi",
715        direction  = directions,
716        mirror     = mirrors,
717        textclass  = textclasses,
718    }
719
720    for k, d in next, characters.data do
721        local direction = d.direction
722        local mirror    = d.mirror
723        local textclass = d.textclass
724        if direction and direction ~= "l" then
725            directiondata[k] = direction
726        end
727        if mirror then
728            mirrordata[k] = mirror
729        end
730        if textclass then
731            textclassdata[k] = textclass
732        end
733    end
734
735    local filename = "scite-context-data-bidi.lua"
736
737    report("saving %a",filename)
738    table.save(filename,data)
739end
740
741function scripts.interface.toutf()
742    local filename = environment.files[1]
743    if filename then
744        require("char-def")
745        local contextnames = { }
746        for unicode, data in next, characters.data do
747            local contextname = data.contextname
748            if contextname then
749                contextnames[contextname] = utf.char(unicode)
750            end
751            contextnames.uumlaut = contextnames.udiaeresis
752            contextnames.Uumlaut = contextnames.Udiaeresis
753            contextnames.oumlaut = contextnames.odiaeresis
754            contextnames.Oumlaut = contextnames.Odiaeresis
755            contextnames.aumlaut = contextnames.adiaeresis
756            contextnames.Aumlaut = contextnames.Adiaeresis
757        end
758        report("loading %a",filename)
759        local str = io.loaddata(filename) or ""
760        local done = { }
761        str = gsub(str,"(\\)([a-zA-Z][a-zA-Z][a-zA-Z]+)(%s*)", function(b,s,a)
762            local cn = contextnames[s]
763            if cn then
764                done[s] = (done[s] or 0) + 1
765                return cn
766            else
767                done[s] = (done[s] or 0) - 1
768                return b .. s .. a
769            end
770        end)
771        for k, v in table.sortedpairs(done) do
772            if v > 0 then
773                report("+ %5i : %s => %s",v,k,contextnames[k])
774            else
775                report("- %5i : %s",-v,k,contextnames[k])
776            end
777        end
778        filename = filename .. ".toutf"
779        report("saving %a",filename)
780        io.savedata(filename,str)
781    end
782end
783
784function scripts.interface.meaning()
785    local runner  = "mtxrun --silent --script context --extra=meaning --once --noconsole --nostatistics"
786    local pattern = environment.arguments.pattern
787    local files   = environment.files
788    if type(pattern) == "string" then
789        runner = runner .. ' --pattern="' .. pattern .. '"'
790    elseif files and #files > 0 then
791        for i=1,#files do
792            runner = runner .. ' "' .. files[i] .. '"'
793        end
794    else
795        return
796    end
797    local r = os.resultof(runner)
798    if type(r) == "string" then
799        r = gsub(r,"^.-(meaning%s+>)","\n%1")
800        print(r)
801    end
802end
803
804function scripts.interface.tokens()
805    local runner  = "mtxrun --silent --script context --extra=meaning --tokens --once --noconsole --nostatistics"
806    local pattern = environment.arguments.pattern
807    local files   = environment.files
808    if type(pattern) == "string" then
809        runner = runner .. ' --pattern="' .. pattern .. '"'
810    elseif files and #files > 0 then
811        for i=1,#files do
812            runner = runner .. ' "' .. files[i] .. '"'
813        end
814    else
815        return
816    end
817    local r = os.resultof(runner)
818    if type(r) == "string" then
819        r = gsub(r,"^.-(tokens%s+>)","\n%1")
820        print(r)
821    end
822end
823
824local ea = environment.argument
825
826-- if ea("mkii") then
827--     scripts.interface.mkii()
828-- elseif ea("preprocess") then
829
830if ea("preprocess") then
831    scripts.interface.preprocess()
832elseif ea("meaning") then
833    scripts.interface.meaning()
834elseif ea("tokens") then
835    scripts.interface.tokens()
836elseif ea("toutf") then
837    scripts.interface.toutf()
838elseif ea("bidi") then
839    scripts.interface.bidi()
840elseif ea("check") then
841    scripts.interface.check()
842elseif ea("scite") or ea("bbedit") or ea("jedit") or ea("textpad") or ea("vim") or ea("text") or ea("raw") then
843    if ea("scite") then
844        scripts.interface.editor("scite")
845    end
846    if ea("bbedit") then
847        scripts.interface.editor("bbedit")
848    end
849    if ea("jedit") then
850        scripts.interface.editor("jedit")
851    end
852    if ea("textpad") then
853        scripts.interface.editor("textpad",true, { "en" })
854    end
855    if ea("vim") then
856        scripts.interface.editor("vim",true, { "en" })
857    end
858    if ea("text") then
859        scripts.interface.editor("text")
860    end
861    if ea("raw") then
862        scripts.interface.editor("raw")
863    end
864elseif ea("exporthelp") then
865    application.export(ea("exporthelp"),environment.files[1])
866else
867    application.help()
868end
869