texlive[66175] Master/texmf-dist/scripts/context: ConTeXt LMTX:

commits+siepo at tug.org commits+siepo at tug.org
Sun Feb 26 15:42:54 CET 2023


Revision: 66175
          http://tug.org/svn/texlive?view=revision&revision=66175
Author:   siepo
Date:     2023-02-26 15:42:54 +0100 (Sun, 26 Feb 2023)
Log Message:
-----------
ConTeXt LMTX: scripts

Modified Paths:
--------------
    trunk/Master/texmf-dist/scripts/context/lua/mtx-cache.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-context.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-context.xml
    trunk/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-install.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-interface.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-pdf.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-synctex.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-unicode.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-update.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-vscode.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtxrun.lua

Added Paths:
-----------
    trunk/Master/texmf-dist/scripts/context/lua/mtx-ctan.lua
    trunk/Master/texmf-dist/scripts/context/lua/mtx-spell.lua

Removed Paths:
-------------
    trunk/Master/texmf-dist/scripts/context/ruby/
    trunk/Master/texmf-dist/scripts/context/stubs/

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-cache.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-cache.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-cache.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -78,7 +78,8 @@
         local kept = 0
         for i=1,#list do
             local filename = list[i]
-            if find(filename,"luatex%-cache") then
+         -- if find(filename,"luatex%-cache") then
+            if find(filename,LUATEXENGINE .. "%-cache") then
                 remove(filename)
                 if isfile(filename) then
                     kept = kept + 1

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-context.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-context.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-context.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -22,6 +22,7 @@
 
 local filejoinname  = file.join
 local filebasename  = file.basename
+local filenameonly  = file.nameonly
 local filepathpart  = file.pathpart
 local filesuffix    = file.suffix
 local fileaddsuffix = file.addsuffix
@@ -106,12 +107,14 @@
 -- -- The way we use stubs will change in a bit in 2019 (mtxrun and context). We also normalize
 -- -- the platforms to use a similar approach to this.
 
-local engine_new = file.nameonly(getargument("engine") or directives.value("system.engine"))
-local engine_old = file.nameonly(environment.ownmain) or file.nameonly(environment.ownbin)
+local engine_new = filenameonly(getargument("engine") or directives.value("system.engine"))
+local engine_old = filenameonly(environment.ownmain) or filenameonly(environment.ownbin)
 
 local function restart(engine_old,engine_new)
-    local ownname = file.join(file.dirname(environment.ownname),"mtxrun.lua")
-    local command = format("%s --luaonly %q %s --redirected",engine_new,ownname,environment.reconstructcommandline())
+    local generate  = environment.arguments.generate and (engine_new == "luatex" or engine_new == "luajittex")
+    local arguments = generate and  "--generate" or environment.reconstructcommandline()
+    local ownname   = filejoinname(filepathpart(environment.ownname),"mtxrun.lua")
+    local command   = format("%s --luaonly %q %s --redirected",engine_new,ownname,arguments)
     report(format("redirect %s -> %s: %s",engine_old,engine_new,command))
     local result = os.execute(command)
     os.exit(result == 0 and 0 or 1)
@@ -361,20 +364,29 @@
     return false
 end
 
-local f_tempfile = formatters["%s-%s-%02d.tmp"]
+local f_tempfile_i = formatters["%s-%s-%02d.tmp"]
+local f_tempfile_s = formatters["%s-%s-keep.%s"]
 
 local function backup(jobname,run,kind,filename)
-    if run == 1 then
-        for i=1,10 do
-            local tmpname = f_tempfile(jobname,kind,i)
-            if validfile(tmpname) then
-                removefile(tmpname)
-                report("removing %a",tmpname)
+    if run then
+        if run == 1 then
+            for i=1,10 do
+                local tmpname = f_tempfile_i(jobname,kind,i)
+                if validfile(tmpname) then
+                    removefile(tmpname)
+                    report("removing %a",tmpname)
+                end
             end
         end
-    end
-    if validfile(filename) then
-        local tmpname = f_tempfile(jobname,kind,run or 1)
+        if validfile(filename) then
+            local tmpname = f_tempfile_i(jobname,kind,run or 1)
+            report("copying %a into %a",filename,tmpname)
+            file.copy(filename,tmpname)
+        else
+            report("no file %a, nothing kept",filename)
+        end
+    elseif validfile(filename) then
+        local tmpname = f_tempfile_s(jobname,kind,kind)
         report("copying %a into %a",filename,tmpname)
         file.copy(filename,tmpname)
     else
@@ -395,10 +407,20 @@
     end
 end
 
+local function multipass_copypdffile(jobname,run)
+    if run then
+        local pdfname = jobname..".pdf"
+        if validfile(pdfname) then
+            backup(jobname,false,"pdf",pdfname)
+            report()
+        end
+    end
+end
+
 local function multipass_copylogfile(jobname,run)
-    local logname = jobname..".log"
-    if validfile(logname) then
-        if run then
+    if run then
+        local logname = jobname..".log"
+        if validfile(logname) then
             backup(jobname,run,"log",logname)
             report()
         end
@@ -659,6 +681,7 @@
     local a_purgeall      = getargument("purgeall")
     local a_purgeresult   = getargument("purgeresult")
     local a_global        = getargument("global")
+    local a_runpath       = getargument("runpath")
     local a_timing        = getargument("timing")
     local a_profile       = getargument("profile")
     local a_batchmode     = getargument("batchmode")
@@ -673,6 +696,7 @@
     local a_texformat     = getargument("texformat")
     local a_keeptuc       = getargument("keeptuc")
     local a_keeplog       = getargument("keeplog")
+    local a_keeppdf       = getargument("keeppdf")
     local a_export        = getargument("export")
     local a_nodates       = getargument("nodates")
     local a_trailerid     = getargument("trailerid")
@@ -692,9 +716,13 @@
         local basename = filebasename(filename) -- use splitter
         local pathname = filepathpart(filename)
         --
+        if filesuffix(filename) == "" then
+            filename = fileaddsuffix(filename,"tex")
+        end
+        --
         if pathname == "" and not a_global and filename ~= usedfiles.nop then
             filename = "./" .. filename
-            if not validfile(filename) and not validfile(filename..".tex") then
+            if not validfile(filename) then
                 report("warning: no (local) file %a, proceeding",filename)
             end
         end
@@ -715,6 +743,31 @@
                 formatfile, scriptfile = resolvers.locateformat(formatname)
             end
             --
+            local runpath = a_runpath or analysis.runpath
+            if type(runpath) == "string" and runpath ~= "" then
+                runpath = resolvers.resolve(runpath)
+                local currentdir = dir.current()
+                if not lfs.isdir(runpath) then
+                    if dir.makedirs(runpath) then
+                        report("runpath %a has been created",runpath)
+                    else
+                        report("error: runpath %a cannot be created",runpath)
+                        os.exit()
+                    end
+                end
+                if lfs.chdir(runpath) then
+                    report("changing to runpath %a",runpath)
+                else
+                    report("error: changing to runpath %a is impossible",runpath)
+                    os.exit()
+                end
+                environment.arguments.path    = currentdir
+                environment.arguments.runpath = runpath
+                if filepathpart(filename) == "." then
+                    filename = filebasename(filename)
+                end
+            end
+            --
             a_jithash       = validstring(a_jithash or analysis.jithash) or nil
             a_permitloadlib = a_permitloadlib or analysis.permitloadlib or nil
             --
@@ -733,12 +786,16 @@
                     return flag or plus -- flag wins
                 end
             end
-            local a_trackers    = analysis.trackers
-            local a_experiments = analysis.experiments
+            ----- a_trackers    = analysis.trackers
+            ----- a_experiments = analysis.experiments
             local directives    = combine("directives")
             local trackers      = combine("trackers")
             local experiments   = combine("experiments")
             --
+            local ownerpassword = environment.ownerpassword or analysis.ownerpassword
+            local userpassword  = environment.userpassword  or analysis.userpassword
+            local permissions   = environment.permissions   or analysis.permissions
+            --
             if formatfile and scriptfile then
                 local suffix     = validstring(getargument("suffix"))
                 local resultname = validstring(getargument("result"))
@@ -745,7 +802,7 @@
                 if not resultname or resultname == "" then
                     resultname = validstring(analysis.result)
                 end
-                local resultpath = file.pathpart(resultname)
+                local resultpath = filepathpart(resultname)
                 if resultpath ~= "" then
                     resultname  = nil
                 elseif suffix then
@@ -805,6 +862,10 @@
                     export         = a_export and true or nil,
                     nocompression  = a_nocompression and true or nil,
                     texmfbinpath   = os.selfdir,
+                    --
+                    ownerpassword  = ownerpassword,
+                    userpassword   = userpassword,
+                    permissions    = permissions,
                 }
                 --
                 for k, v in next, environment.arguments do
@@ -816,6 +877,14 @@
                 --
                 -- todo: --output-file=... in luatex
                 --
+                local usedname = jobname
+                local engine   = analysis.engine or "luametatex"
+                if engine == "luametatex" and (mainfile == usedfiles.yes or mainfile == usedfiles.nop) and not getargument("redirected") then
+                    mainfile = "" -- we don't need that
+                    usedname = fulljobname
+                end
+                --
+                --
                 local l_flags = {
                     ["interaction"]           = a_batchmode,
                  -- ["synctex"]               = false,       -- context has its own way
@@ -825,7 +894,8 @@
                  -- ["file-line-error-style"] = true,
 --                  ["fmt"]                   = formatfile,
 --                  ["lua"]                   = scriptfile,
-                    ["jobname"]               = jobname,
+--                  ["jobname"]               = jobname,
+                    ["jobname"]               = usedname,
                     ["jithash"]               = a_jithash,
                     ["permitloadlib"]         = a_permitloadlib,
                 }
@@ -854,11 +924,10 @@
                 --
                 -- kindofrun: 1:first run, 2:successive run, 3:once, 4:last of maxruns
                 --
-                local engine = analysis.engine or "luametatex"
-                if engine == "luametatex" and (mainfile == usedfiles.yes or mainfile == usedfiles.nop) then
-                    mainfile = "" -- we don't need that
-                end
+                -- can be used to include pages from a previous run, --keeppdf or "% keeppdf" on first-line
                 --
+                multipass_copypdffile(jobname,a_keeppdf or analysis.keeppdf)
+                --
                 for currentrun=1,maxnofruns do
                     --
                     c_flags.final      = false
@@ -913,7 +982,7 @@
                 end
                 --
                 if environment.arguments["ansilog"] then
-                    local logfile = file.replacesuffix(jobname,"log")
+                    local logfile = filenewsuffix(jobname,"log")
                     local logdata = io.loaddata(logfile) or ""
                     if logdata ~= "" then
                         io.savedata(logfile,(gsub(logdata,"%[.-m","")))
@@ -1438,7 +1507,7 @@
 function scripts.context.pages()
     local filename = environment.files[1]
     if filename then
-        local u = table.load(file.addsuffix(filename,"tuc"))
+        local u = table.load(fileaddsuffix(filename,"tuc"))
         if u then
             local p = u.structures.pages.collected
             local l = u.structures.lists.collected
@@ -1637,19 +1706,16 @@
 
 -- todo: we need to do a dummy run
 
-function scripts.context.trackers()
-    environment.files = { resolvers.findfile("m-trackers.mkiv") }
+local function showsetter()
+    environment.files = { resolvers.findfile("mtx-context-setters.tex") }
     multipass_nofruns = 1
     setargument("purgeall",true)
     scripts.context.run()
 end
 
-function scripts.context.directives()
-    environment.files = { resolvers.findfile("m-directives.mkiv") }
-    multipass_nofruns = 1
-    setargument("purgeall",true)
-    scripts.context.run()
-end
+scripts.context.trackers    = showsetter
+scripts.context.directives  = showsetter
+scripts.context.experiments = showsetter
 
 function scripts.context.logcategories()
     environment.files = { resolvers.findfile("m-logcategories.mkiv") }
@@ -1664,6 +1730,12 @@
 
 -- getting it done
 
+if getargument("pdftex") then
+    setargument("engine","pdftex")
+elseif getargument("xetex") then
+    setargument("engine","xetex")
+end
+
 if getargument("timedlog") then
     logs.settimedlog()
 end
@@ -1781,7 +1853,7 @@
 do
 
     if getargument("wipebusy") then
-        os.remove("context-is-busy.tmp")
+        removefile("context-is-busy.tmp")
     end
 
 end

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-context.xml
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-context.xml	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-context.xml	2023-02-26 14:42:54 UTC (rev 66175)
@@ -148,7 +148,7 @@
                     <short>never initializes synctex (for production runs)</short>
                 </flag>
                 <flag name="synctex">
-                    <short>run with synctex enabled (better use \setupsynctex[state=start]</short>
+                    <short>run with synctex enabled (better use \setupsynctex[state=start])</short>
                 </flag>
             </subcategory>
             <subcategory>
@@ -202,6 +202,9 @@
                 <flag name="keeptuc">
                     <short>keep previous tuc files (jobname-tuc-[run].tmp)</short>
                 </flag>
+                <flag name="keeppdf">
+                    <short>keep previous pdf files (jobname-pdf-keep.tmp)</short>
+                </flag>
                 <flag name="keeplog">
                     <short>keep previous log files (jobname-log-[run].tmp)</short>
                 </flag>
@@ -220,6 +223,17 @@
                     <short>show extras</short>
                 </flag>
             </subcategory>
+            <subcategory>
+                <flag name="ownerpassword">
+                    <short>encrypt the (pdf) file using this master password</short>
+                </flag>
+                <flag name="userpassword">
+                    <short>use an additional password for opening the document</short>
+                </flag>
+                <flag name="permissions">
+                    <short>list of: print, modify, extract, add, fillin, assemble, quality</short>
+                </flag>
+            </subcategory>
         </category>
         <category name="special">
             <subcategory>

Added: trunk/Master/texmf-dist/scripts/context/lua/mtx-ctan.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-ctan.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-ctan.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -0,0 +1,319 @@
+if not modules then modules = { } end modules ['mtx-ctan'] = {
+    version   = 1.00,
+    comment   = "companion to mtxrun.lua",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+-- This is just an experiment. Some day I want to be able to install fonts this way
+-- but maybe fetching tex live packages is also an option (I need to check if there
+-- is an api for that ... in wintertime). Normally fonts come from the web but I had
+-- to fetch newcm from ctan, so ...
+--
+-- mtxrun --script ctan --packages --pattern=computermodern
+
+-- http://www.ctan.org/json/2.0/packages
+-- http://www.ctan.org/json/2.0/pkg/name
+-- http://www.ctan.org/json/2.0/topics              : key details
+-- http://www.ctan.org/json/2.0/topic/name          : key details
+-- http://www.ctan.org/json/2.0/topic/name?ref=true : key details packages
+
+local lower, find, gsub = string.lower, string.find, string.gsub
+local write_nl = (logs and logs.writer) or (texio and texio.write_nl) or print
+local xmlconvert, xmltext, xmlattr, xmlcollected = xml.convert, xml.text, xml.attribute, xml.collected
+
+local helpinfo = [[
+<?xml version="1.0"?>
+<application>
+ <metadata>
+  <entry name="name">mtx-ctan</entry>
+  <entry name="detail">Dealing with CTAN</entry>
+  <entry name="version">1.00</entry>
+ </metadata>
+ <flags>
+  <category name="basic">
+   <subcategory>
+    <flag name="packages"><short>list available packages</short></flag>
+    <flag name="topics"><short>list available topics</short></flag>
+    <flag name="detail"><short>show details about package</short></flag>
+    <flag name="pattern" value="string"><short>use this pattern, otherwise first argument</short></flag>
+   </subcategory>
+  </category>
+ </flags>
+</application>
+]]
+
+local application = logs.application {
+    name     = "mtx-ctan",
+    banner   = "Dealing with CTAN",
+    helpinfo = helpinfo,
+}
+
+local report = application.report
+
+scripts      = scripts      or { }
+scripts.ctan = scripts.ctan or { }
+
+local okay, json = pcall(require,"util-jsn")
+local okay, curl = pcall(require,"libs-imp-curl")
+                   pcall(require,"char-ini")
+
+local jsontolua = json and json.tolua
+local shaped    = characters and characters.shaped or lower
+
+-- local ignore = {
+--     "latex",
+--     "plain",
+--     "xetex",
+-- }
+
+-- what is the url to fetch a zip
+
+-- We cannot use the socket library because we don't compile that massive amount of
+-- ssl code into lua(meta)tex. aybe some day one fo these small embedded libraries
+-- makes sense but there are so many changes in all that security stuff that it
+-- defeats long term stability of the ecosystem anyway ... just like some of my old
+-- devices suddenly are no longer accessible with modern browsers I expect it to
+-- happen everywhere. I'm not sure why ctan can't support http because I see no
+-- added value in the 's' here.
+
+local ctanurl = "https://www.ctan.org/" .. (json and "json" or "xml") .. "/2.0/"
+
+local fetched = curl and
+
+    function(str)
+        local data, message = curl.fetch {
+            url           = ctanurl .. str,
+            sslverifyhost = false,
+            sslverifypeer = false,
+        }
+        if not data then
+            report("some error: %s",message)
+        end
+        return data
+    end
+
+or
+
+    function(str)
+        -- So, no redirect to http, which means that we cannot use the built in socket
+        -- library. What if the client is happy with http?
+        local data = os.resultof("curl -sS " .. ctanurl .. str)
+        -- print(data)
+        return data
+    end
+
+-- for j=1,#ignore do
+--     if find(str,ignore[j]) then
+--         return false
+--     end
+-- end
+
+local function strfound(pattern,str)
+    if not pattern then
+        return true
+    else
+        local str = lower(shaped(str))
+        if find(str,pattern) then
+            return true
+        else
+            str = gsub(str,"[^a-zA-Z0-9]","")
+            if find(str,pattern) then
+                return true
+            else
+                return false
+            end
+        end
+    end
+end
+
+local function showresult(found)
+    if #found > 2 then
+        utilities.formatters.formatcolumns(found)
+        report("")
+        for k=1,#found do
+            report(found[k])
+        end
+        report("")
+    end
+end
+
+local function checkedpattern(pattern)
+    if pattern then
+        return lower(shaped(pattern))
+    end
+end
+
+local validdata = json and
+
+    function(data)
+        if data then
+            data = jsontolua(data)
+            if type(data) == "table" then
+                return data
+            else
+                report("unable to handle this json data")
+            end
+        else
+            report("unable to fetch packages")
+        end
+    end
+
+or
+
+    function(data)
+        if data then
+            data = xmlconvert(data)
+            if data.error then
+                report("unable to handle this json data")
+            else
+                return data
+            end
+        else
+            report("unable to fetch packages")
+        end
+    end
+
+scripts.ctan.details = json and
+
+    function(name)
+        if name then
+            local data = validdata(fetched("pkg/" .. name))
+            if data then
+                report("")
+             -- report("key     : %s",data.key or "-")
+                report("name    : %s",data.name or "-")
+                report("caption : %s",data.caption or "-")
+                report("path    : %s",data.ctan.path or "-")
+                report("")
+            end
+        end
+    end
+
+or
+
+    function (name)
+        if name then
+            local data = validdata(fetched("pkg/" .. name))
+            report("")
+         -- report("key     : %s",data.key or "-")
+            report("name    : %s",xmltext(data,"/entry/name"))
+            report("caption : %s",xmltext(data,"/entry/caption"))
+            report("path    : %s",xmlattr(data,"/entry/ctan","path"))
+            report("")
+        end
+    end
+
+scripts.ctan.packages = json and
+
+    function(pattern)
+        local data = validdata(fetched("packages"))
+        if data then
+            local found = {
+                { "key", "name", "caption" },
+                { "",    "",     ""        },
+            }
+            pattern = checkedpattern(pattern)
+            for i=1,#data do
+                local entry = data[i]
+                if strfound(pattern,entry.caption) then
+                    found[#found+1] = { entry.key, entry.name, entry.caption }
+                end
+            end
+            showresult(found)
+        end
+    end
+
+or
+
+    function(pattern)
+        local data = validdata(fetched("packages"))
+        if data then
+            local found = {
+                { "key", "name", "caption" },
+                { "",    "",     ""        },
+            }
+            pattern = checkedpattern(pattern)
+            for c in xmlcollected(data,"/packages/package") do
+                local at = c.at
+                if strfound(pattern,at.caption) then
+                    found[#found+1] = { at.key, at.name, at.caption }
+                end
+            end
+            showresult(found)
+        end
+    end
+
+scripts.ctan.topics = json and
+
+    function (pattern)
+        local data = validdata(fetched("topics"))
+        if data then
+            local found = {
+                { "key", "details" },
+                { "",    ""        },
+            }
+            pattern = checkedpattern(pattern)
+            for i=1,#data do
+                local entry = data[i]
+                if strfound(pattern,entry.details) then
+                    found[#found+1] = { entry.key or entry.name, entry.details } -- inconsistency between json and xml
+                end
+            end
+            showresult(found)
+        end
+    end
+
+or
+
+    function(pattern)
+        local data = validdata(fetched("topics"))
+        if data then
+            local found = {
+                { "name", "details" },
+                { "",     ""        },
+            }
+            pattern = checkedpattern(pattern)
+            for c in xmlcollected(data,"/topics/topic") do
+                local at = c.at
+                if strfound(pattern,at.caption) then
+                    found[#found+1] = { at.key or at.name, at.details } -- inconsistency between json and xml
+                end
+            end
+            showresult(found)
+        end
+    end
+
+local function whatever()
+    report("")
+    report("using %s interface", json and "json"    or "xml")
+    report("using curl %s",      curl and "library" or "binary")
+    report("")
+end
+
+if environment.argument("packages") then
+    whatever()
+    scripts.ctan.packages(environment.argument("pattern") or environment.files[1])
+elseif environment.argument("topics") then
+    whatever()
+    scripts.ctan.topics(environment.argument("pattern") or environment.files[1])
+elseif environment.argument("details") then
+    whatever()
+    scripts.ctan.details(environment.files[1])
+elseif environment.argument("exporthelp") then
+    application.export(environment.argument("exporthelp"),environment.files[1])
+else
+    application.help()
+end
+
+-- scripts.ctan.packages(environment.argument("pattern") or environment.files[1])
+-- scripts.ctan.packages("font")
+-- scripts.ctan.details("tex")
+-- scripts.ctan.details("ipaex")
+
+-- scripts.ctan.packages("Półtawskiego")
+-- scripts.ctan.packages("Poltawskiego")
+
+-- scripts.ctan.topics("font")
+-- scripts.ctan.topics()

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -12,11 +12,11 @@
 
 local suffix, addsuffix, removesuffix, replacesuffix = file.suffix, file.addsuffix, file.removesuffix, file.replacesuffix
 local nameonly, basename, joinpath, collapsepath = file.nameonly, file.basename, file.join, file.collapsepath
-local lower = string.lower
+local lower, gsub = string.lower, string.gsub
 local concat = table.concat
 local write_nl = (logs and logs.writer) or (texio and texio.write_nl) or print
 
-local otlversion  = 3.113
+local otlversion  = 3.133
 
 local helpinfo = [[
 <?xml version="1.0"?>
@@ -60,6 +60,10 @@
     <example><command>mtxrun --script font --list somename (== --pattern=*somename*)</command></example>
    </subcategory>
    <subcategory>
+    <example><command>mtxrun --script font --list --file filename</command></example>
+    <example><command>mtxrun --script font --list --name --pattern=*somefile*</command></example>
+   </subcategory>
+   <subcategory>
     <example><command>mtxrun --script font --list --name somename</command></example>
     <example><command>mtxrun --script font --list --name --pattern=*somename*</command></example>
    </subcategory>
@@ -123,7 +127,7 @@
 loadmodule("font-cff.lua")
 loadmodule("font-ttf.lua")
 loadmodule("font-tmp.lua")
-loadmodule("font-dsp.lua")
+loadmodule("font-dsp.lua") -- autosuffix
 loadmodule("font-oup.lua")
 
 loadmodule("font-otl.lua")
@@ -183,6 +187,9 @@
     local simplelist = { "ttf", "otf", "ttc", alsotypeone and "afm" or nil }
     local name = "luatex-fonts-names.lua"
     local path = collapsepath(caches.getwritablepath("..","..","generic","fonts","data"))
+
+    path = gsub(path, "luametatex%-cache", "luatex-cache") -- maybe have an option to force it
+
     fonts.names.filters.list = simplelist
     fonts.names.version = simpleversion -- this number is the same as in font-dum.lua
     report("generating font database for 'luatex-fonts' version %s",fonts.names.version)
@@ -288,7 +295,7 @@
                         else
                             done = true
                         end
-                        report("  % -8s % -8s % -8s",f,s,concat(table.sortedkeys(ss), " ")) -- todo: padd 4
+                        report("  %-8s %-8s %-8s",f,s,concat(table.sortedkeys(ss), " ")) -- todo: padd 4
                     end
                 end
             end
@@ -310,7 +317,7 @@
             report("  method   feature         formats")
             report()
             for k, v in table.sortedhash(methods) do
-                report("  % -8s % -14s  %s",k,v.feature,v.format)
+                report("  %-8s %-14s  %s",k,v.feature,v.format)
             end
         end
     end
@@ -406,12 +413,12 @@
 
     if getargument("name") then
         if pattern then
-            --~ mtxrun --script font --list --name --pattern=*somename*
+            -- mtxrun --script font --list --name --pattern=*somename*
             list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info)
         elseif filter then
             report("not supported: --list --name --filter",name)
         elseif given then
-            --~ mtxrun --script font --list --name somename
+            -- mtxrun --script font --list --name somename
             list_matches(fonts.names.list(given,reload,all),info)
         else
             report("not supported: --list --name <no specification>",name)
@@ -418,13 +425,13 @@
         end
     elseif getargument("spec") then
         if pattern then
-            --~ mtxrun --script font --list --spec --pattern=*somename*
+            -- mtxrun --script font --list --spec --pattern=*somename*
             report("not supported: --list --spec --pattern",name)
         elseif filter then
-            --~ mtxrun --script font --list --spec --filter="fontname=somename"
+            -- mtxrun --script font --list --spec --filter="fontname=somename"
             list_specifications(fonts.names.getlookups(filter),info)
         elseif given then
-            --~ mtxrun --script font --list --spec somename
+            -- mtxrun --script font --list --spec somename
             list_specifications(fonts.names.collectspec(given,reload,all),info)
         else
             report("not supported: --list --spec <no specification>",name)
@@ -431,21 +438,21 @@
         end
     elseif getargument("file") then
         if pattern then
-            --~ mtxrun --script font --list --file --pattern=*somename*
+            -- mtxrun --script font --list --file --pattern=*somename*
             list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all),info)
         elseif filter then
             report("not supported: --list --spec",name)
         elseif given then
-            --~ mtxrun --script font --list --file somename
+            -- mtxrun --script font --list --file somename
             list_specifications(fonts.names.collectfiles(given,reload,all),info)
         else
             report("not supported: --list --file <no specification>",name)
         end
     elseif pattern then
-        --~ mtxrun --script font --list --pattern=*somename*
+        -- mtxrun --script font --list --pattern=*somename*
         list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info)
     elseif given then
-        --~ mtxrun --script font --list somename
+        -- mtxrun --script font --list somename
         list_matches(fonts.names.list(given,reload,all),info)
     elseif all then
         pattern = "*"

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-install.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-install.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-install.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -14,7 +14,7 @@
  <metadata>
   <entry name="name">mtx-install</entry>
   <entry name="detail">ConTeXt Installer</entry>
-  <entry name="version">2.00</entry>
+  <entry name="version">2.01</entry>
  </metadata>
  <flags>
   <category name="basic">
@@ -28,6 +28,7 @@
     <flag name="update"><short>update context</short></flag>
     <flag name="erase"><short>wipe the cache</short></flag>
     <flag name="identify"><short>create list of files</short></flag>
+    <flag name="secure"><short>use curl for https</short></flag>
    </subcategory>
   </category>
  </flags>
@@ -34,6 +35,7 @@
 </application>
 ]]
 
+local type, tonumber = type, tonumber
 local gsub, find, escapedpattern = string.gsub, string.find, string.escapedpattern
 local round = math.round
 local savetable, loadtable, sortedhash = table.save, table.load, table.sortedhash
@@ -40,15 +42,41 @@
 local copyfile, joinfile, filesize, dirname, addsuffix, basename = file.copy, file.join, file.size, file.dirname, file.addsuffix, file.basename
 local isdir, isfile, walkdir, pushdir, popdir, currentdir = lfs.isdir, lfs.isfile, lfs.dir, lfs.chdir, dir.push, dir.pop, currentdir
 local mkdirs, globdir = dir.mkdirs, dir.glob
-local osremove, osexecute, ostype = os.remove, os.execute, os.type
+local osremove, osexecute, ostype, resultof = os.remove, os.execute, os.type, os.resultof
 local savedata = io.savedata
 local formatters = string.formatters
+local httprequest = socket.http.request
 
-local fetch = socket.http.request
+local usecurl = false
 
+local function checkcurl()
+    local s = resultof("curl --version")
+    return type(s) == "string" and find(s,"libcurl") and find(s,"rotocols")
+end
+
+local function fetch(url)
+    local data   = nil
+    local detail = nil
+    if usecurl and find(url,"^https") then
+        data = resultof("curl " .. url)
+    else
+        data, detail = httprequest(url)
+    end
+    if type(data) ~= "string" then
+        data = false
+    elseif #data < 2048 then
+        local n, t = find(data,"<head>%s*<title>%s*(%d+)%s(.-)</title>")
+        if tonumber(n) then
+            data   = false
+            detail = n .. " " .. t
+        end
+    end
+    return data, detail
+end
+
 local application = logs.application {
     name     = "mtx-install",
-    banner   = "ConTeXt Installer 2.00",
+    banner   = "ConTeXt Installer 2.01",
     helpinfo = helpinfo,
 }
 
@@ -75,11 +103,14 @@
     ["windows"]        = "mswin",
     ["win32"]          = "mswin",
     ["win"]            = "mswin",
+    ["arm32"]          = "windows-arm32",
+    ["windows-arm32"]  = "windows-arm32",
     --
     ["mswin-64"]       = "win64",
     ["windows-64"]     = "win64",
     ["win64"]          = "win64",
     ["arm64"]          = "windows-arm64",
+    ["windows-arm64"]  = "windows-arm64",
     --
     ["linux"]          = "linux",
     ["linux-32"]       = "linux",
@@ -93,9 +124,9 @@
     --
     ["linux-armhf"]    = "linux-armhf",
     --
-    ["openbsd"]        = "openbsd6.8",
-    ["openbsd-i386"]   = "openbsd6.8",
-    ["openbsd-amd64"]  = "openbsd6.8-amd64",
+    ["openbsd"]        = "openbsd7.2",
+    ["openbsd-i386"]   = "openbsd7.2",
+    ["openbsd-amd64"]  = "openbsd7.2-amd64",
     --
     ["freebsd"]        = "freebsd",
     ["freebsd-i386"]   = "freebsd",
@@ -121,10 +152,8 @@
     ["macosx"]         = "osx-64",
     ["osx"]            = "osx-64",
     ["osx-64"]         = "osx-64",
---     ["osx-arm"]        = "osx-arm64",
---     ["osx-arm64"]      = "osx-arm64",
-    ["osx-arm"]        = "osx-64",
-    ["osx-arm64"]      = "osx-64",
+    ["osx-arm"]        = "osx-arm64",
+    ["osx-arm64"]      = "osx-arm64",
     --
  -- ["solaris-intel"]  = "solaris-intel",
     --
@@ -589,6 +618,11 @@
     end
     run("%s --make en", contextbin)
 
+    -- in case we also install luatex:
+
+    run("%s --luatex --generate",contextbin)
+    run("%s --luatex --make en", contextbin)
+
     -- in calling script: update mtxrun.exe and mtxrun.lua
 
     report("")
@@ -602,6 +636,14 @@
     report("update, done")
 end
 
+if environment.argument("secure") then
+    usecurl = checkcurl()
+    if not usecurl then
+        report("no curl installed, quitting")
+        os.exit()
+    end
+end
+
 if environment.argument("identify") then
     install.identify()
 elseif environment.argument("install") then

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-interface.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-interface.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-interface.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -7,9 +7,9 @@
 }
 
 local concat, sort, insert = table.concat, table.sort, table.insert
-local gsub, format, gmatch, find = string.gsub, string.format, string.gmatch, string.find
+local gsub, format, gmatch, find, upper = string.gsub, string.format, string.gmatch, string.find, string.upper
 local utfchar, utfgsub = utf.char, utf.gsub
-local sortedkeys = table.sortedkeys
+local sortedkeys, sortedhash, serialize = table.sortedkeys, table.sortedhash, table.serialize
 
 local helpinfo = [[
 <?xml version="1.0"?>
@@ -32,6 +32,7 @@
     <flag name="bbedit"><short>generate bbedit interface files</short></flag>
     <flag name="jedit"><short>generate jedit interface files</short></flag>
     <flag name="textpad"><short>generate textpad interface files</short></flag>
+    <flag name="vim"><short>generate vim interface files</short></flag>
     <flag name="text"><short>create text files for commands and environments</short></flag>
     <flag name="raw"><short>report commands to the console</short></flag>
     <flag name="check"><short>generate check file</short></flag>
@@ -71,19 +72,19 @@
 
 local function collect(filename,class,data)
     if data then
-        local result = { }
-        for name, list in table.sortedhash(data) do
-            result[#result+1] = format("keywordclass.%s.%s=\\\n",class,name)
+        local result, r = { }, 0
+        for name, list in sortedhash(data) do
+            r = r + 1 ; result[r] = format("keywordclass.%s.%s=\\\n",class,name)
             for i=1,#list do
                 if i%5 == 0 then
-                    result[#result+1] = "\\\n"
+                    r = r + 1 ; result[r] = "\\\n"
                 end
-                result[#result+1] = format("%s ",list[i])
+                r = r + 1 ; result[r] = format("%s ",list[i])
             end
-            result[#result+1] = "\n\n"
+            r = r + 1 ; result[r] = "\n\n"
         end
         io.savedata(file.addsuffix(filename,"properties"),concat(result))
-        io.savedata(file.addsuffix(filename,"lua"),       table.serialize(data,true))
+        io.savedata(file.addsuffix(filename,"lua"),serialize(data,true))
     else
         os.remove(filename)
     end
@@ -127,18 +128,18 @@
     for interface, whatever in next, collected do
         local commands     = whatever.commands
         local environments = whatever.environments
-        local result = { }
-        result[#result+1] = "<?xml version='1.0'?>"
-        result[#result+1] = "<!DOCTYPE MODE SYSTEM 'xmode.dtd'>\n"
-        result[#result+1] = "<MODE>"
-        result[#result+1] = "\t<RULES>"
-        result[#result+1] = "\t\t<KEYWORDS>"
+        local result, r = { }, 0
+        r = r + 1 ; result[r] = "<?xml version='1.0'?>"
+        r = r + 1 ; result[r] = "<!DOCTYPE MODE SYSTEM 'xmode.dtd'>\n"
+        r = r + 1 ; result[r] = "<MODE>"
+        r = r + 1 ; result[r] = "\t<RULES>"
+        r = r + 1 ; result[r] = "\t\t<KEYWORDS>"
         for i=1,#commands do
-            result[#result+1] = format("\t\t\t<KEYWORD2>%s</KEYWORD2>",commands[i])
+            r = r + 1 ; result[r] = format("\t\t\t<KEYWORD2>%s</KEYWORD2>",commands[i])
         end
-        result[#result+1] = "\t\t</KEYWORDS>"
-        result[#result+1] = "\t</RULES>"
-        result[#result+1] = "</MODE>"
+        r = r + 1 ; result[r] = "\t\t</KEYWORDS>"
+        r = r + 1 ; result[r] = "\t</RULES>"
+        r = r + 1 ; result[r] = "</MODE>"
         io.savedata(format("context-jedit-%s.xml",interface), concat(result),"\n")
     end
 end
@@ -147,18 +148,100 @@
     for interface, whatever in next, collected do
         local commands     = whatever.commands
         local environments = whatever.environments
-        local result = {}
-        result[#result+1] = "<?xml version='1.0'?>"
-        result[#result+1] = "<key>BBLMKeywordList</key>"
-        result[#result+1] = "<array>"
+        local result, r = { }, 0
+        r = r + 1 ; result[r] = "<?xml version='1.0'?>"
+        r = r + 1 ; result[r] = "<key>BBLMKeywordList</key>"
+        r = r + 1 ; result[r] = "<array>"
         for i=1,#commands do
-            result[#result+1]  = format("\t<string>\\%s</string>",commands[i])
+            r = r + 1 ; result[r] = format("\t<string>\\%s</string>",commands[i])
         end
-        result[#result+1] = "</array>"
+        r = r + 1 ; result[r] = "</array>"
         io.savedata(format("context-bbedit-%s.xml",interface), concat(result),"\n")
     end
 end
 
+-- The Vim export is maintained by Nicola Vitacolonna:
+
+local function vimcollect(filename,class,data)
+    if data then
+        local result, r = { }, 0
+        local endline = " contained\n"
+        if find(class,"^meta") then
+            endline = "\n"
+        end
+        r = r + 1 ; result[r] = "vim9script\n\n"
+        r = r + 1 ; result[r] = "# Vim syntax file\n"
+        r = r + 1 ; result[r] = "# Language: ConTeXt\n"
+        r = r + 1 ; result[r] = format("# Automatically generated by mtx-interface (%s)\n\n", os.date())
+        local n = 5 -- number of keywords per row
+        for name, list in sortedhash(data) do
+            local i = 1
+            while i <= #list do
+                r = r + 1 ; result[r] = format("syn keyword %s%s", class, (gsub(name,"^%l",upper))) -- upper is fragile
+                local j = 0
+--                 while i+j <= #list and j < n do
+--                     if list[i+j] == "transparent" then -- this is a Vim keyword
+--                         r = r + 1 ; result[r] = format(" %s[]",list[i+j])
+--                     else
+--                         r = r + 1 ; result[r] = format(" %s",list[i+j])
+--                     end
+--                     j = j + 1
+--                 end
+                while j < n do
+                    local lij = list[i + j]
+                    if not lij then
+                        break
+                    elseif lij == "transparent" then -- this is a Vim keyword
+                        r = r + 1 ; result[r] = format(" %s[]",lij)
+                    else
+                        r = r + 1 ; result[r] = format(" %s",lij)
+                    end
+                    j = j + 1
+                end
+                r = r + 1 ; result[r] = endline
+                i = i + n
+            end
+        end
+        io.savedata(file.addsuffix(filename,"vim"),concat(result))
+    else
+        os.remove(filename)
+    end
+end
+
+function flushers.vim(collected)
+    local data = { }
+ -- for interface, whatever in next, collected do
+ --     data[interface] = whatever.commands
+ -- end
+    local function add(target,origin,field)
+        if origin then
+            local list = origin[field]
+            if list then
+                for i=1,#list do
+                    target[list[i]] = true
+                end
+            end
+        end
+    end
+    --
+    for interface, whatever in next, collected do
+        local combined = { }
+        add(combined,whatever,"commands")
+        add(combined,whatever,"environments")
+        if interface == "common" then
+            add(combined,whatever,"textnames")
+            add(combined,whatever,"mathnames")
+        end
+        data[interface] = sortedkeys(combined)
+    end
+    --
+    vimcollect("context-data-interfaces", "context",  data)
+ -- vimcollect("context-data-metapost",   "metapost", dofile(resolvers.findfile("mult-mps.lua")))
+    vimcollect("context-data-metafun",    "metafun",  dofile(resolvers.findfile("mult-fun.lua")))
+    vimcollect("context-data-context",    "context",  dofile(resolvers.findfile("mult-low.lua")))
+    vimcollect("context-data-tex",        "tex",      dofile(resolvers.findfile("mult-prm.lua")))
+end
+
 function flushers.raw(collected)
     for interface, whatever in next, collected do
         local commands     = whatever.commands
@@ -749,7 +832,7 @@
     scripts.interface.bidi()
 elseif ea("check") then
     scripts.interface.check()
-elseif ea("scite") or ea("bbedit") or ea("jedit") or ea("textpad") or ea("text") or ea("raw") then
+elseif ea("scite") or ea("bbedit") or ea("jedit") or ea("textpad") or ea("vim") or ea("text") or ea("raw") then
     if ea("scite") then
         scripts.interface.editor("scite")
     end
@@ -762,6 +845,9 @@
     if ea("textpad") then
         scripts.interface.editor("textpad",true, { "en" })
     end
+    if ea("vim") then
+        scripts.interface.editor("vim",true, { "en" })
+    end
     if ea("text") then
         scripts.interface.editor("text")
     end

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -93,7 +93,7 @@
  -- { "ar",  "hyph-ar",            "arabic" },
  -- { "as",  "hyph-as",            "assamese" },
     { "bg",  "hyph-bg",            "bulgarian" },
- -- { "bn",  "hyph-bn",            "bengali" },
+    { "bn",  "hyph-bn",            "bengali" },
     { "ca",  "hyph-ca",            "catalan" },
  -- { "??",  "hyph-cop",           "coptic" },
     { "cs",  "hyph-cs",            "czech" },
@@ -102,8 +102,8 @@
     { "deo", "hyph-de-1901",       "german, old spelling" },
     { "de",  "hyph-de-1996",       "german, new spelling" },
  -- { "??",  "hyph-de-ch-1901",    "swiss german" },
- -- { "??",  "hyph-el-monoton",    "greek" },
- -- { "gr",  "hyph-el-polyton",    "greek" },
+ -- { "??",  "hyph-el-polyton",    "greek" },
+    { "gr",  "hyph-el-monoton",    "greek" },
     { "agr", "hyph-grc",           "ancient greek", ignored_ancient_greek },
     { "gb",  "hyph-en-gb",         "british english" },
     { "us",  "hyph-en-us",         "american english" },
@@ -116,8 +116,8 @@
     { "fr",  "hyph-fr",            "french", ignored_french },
  -- { "??",  "hyph-ga",            "irish" },
  -- { "??",  "hyph-gl",            "galician" },
- -- { "gu",  "hyph-gu",            "gujarati" },
- -- { "hi",  "hyph-hi",            "hindi" },
+    { "gu",  "hyph-gu",            "gujarati" },
+    { "hi",  "hyph-hi",            "hindi" },
     { "hr",  "hyph-hr",            "croatian" },
  -- { "??",  "hyph-hsb",           "upper sorbian" },
     { "hu",  "hyph-hu",            "hungarian" },
@@ -127,7 +127,7 @@
     { "is",  "hyph-is",            "icelandic" },
     { "it",  "hyph-it",            "italian" },
  -- { "??",  "hyph-kmr",           "kurmanji" },
- -- { "kn",  "hyph-kn",            "kannada" },
+    { "kn",  "hyph-kn",            "kannada" },
     { "la",  "hyph-la",            "latin" },
     { "ala", "hyph-la-x-classic",  "ancient latin" },
  -- { "lo",  "hyph-lo",            "lao" },
@@ -147,15 +147,16 @@
     { "pt",  "hyph-pt",            "portuguese" },
     { "ro",  "hyph-ro",            "romanian" },
     { "ru",  "hyph-ru",            "russian" },
- -- { "sa",  "hyph-sa",            "sanskrit" },
+    { "sa",  "hyph-sa",            "sanskrit" },
     { "sk",  "hyph-sk",            "slovak" },
     { "sl",  "hyph-sl",            "slovenian" },
-    { "sr",  "hyph-sr",            "serbian", false, { "hyph-sr-cyrl", "hyph-sr-latn" }, },
+    { "sq",  "hyph-sq",            "albanian" },
+    { "sr",  "hyph-sr",            "serbian", false, { "hyph-sh-cyrl", "hyph-sh-latn" }, },
  -- { "sr",  "hyph-sr-cyrl",       "serbian", false },
  -- { "sr",  "hyph-sr-latn",       "serbian" },
     { "sv",  "hyph-sv",            "swedish" },
- -- { "ta",  "hyph-ta",            "tamil" },
- -- { "te",  "hyph-te",            "telugu" },
+    { "ta",  "hyph-ta",            "tamil" },
+    { "te",  "hyph-te",            "telugu" },
     { "th",  "hyph-th",            "thai" },
     { "tk",  "hyph-tk",            "turkmen" },
     { "tr",  "hyph-tr",            "turkish" },
@@ -186,6 +187,7 @@
     local splitpatternsold, splithyphenationsold = { }, { }
     local usedpatterncharactersnew, usedhyphenationcharactersnew = { }, { }
     if merged then
+        -- no version info
         report("using merged txt files %s.[hyp|pat|lic].txt",name)
         for i=1,#merged do
             local fullname = file.join(path,merged[i])
@@ -194,11 +196,13 @@
             hyphenations = hyphenations  .. (io.loaddata(addsuffix(fullname,"hyp.txt")) or "") .. "\n\n"
         end
     elseif lfs.isfile(patfile) then
+        -- no version info
         report("using txt files %s.[hyp|pat|lic].txt",name)
         comment      = io.loaddata(licfile) or ""
         patterns     = io.loaddata(patfile) or ""
         hyphenations = io.loaddata(hypfile) or ""
     elseif lfs.isfile(texfile) then
+        -- version info in comment blob
         report("using tex file %s.txt",name)
         local data = io.loaddata(texfile) or ""
         if data ~= "" then

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-pdf.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-pdf.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-pdf.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -7,7 +7,7 @@
 }
 
 local tonumber = tonumber
-local format, gmatch, gsub = string.format, string.gmatch, string.gsub
+local format, gmatch, gsub, match, find = string.format, string.gmatch, string.gsub, string.match, string.find
 local utfchar = utf.char
 local concat = table.concat
 local setmetatableindex, sortedhash, sortedkeys = table.setmetatableindex, table.sortedhash, table.sortedkeys
@@ -27,11 +27,13 @@
     <flag name="metadata"><short>show metadata xml blob</short></flag>
     <flag name="pretty"><short>replace newlines in metadata</short></flag>
     <flag name="fonts"><short>show used fonts (<ref name="detail)"/></short></flag>
+    <flag name="object"><short>show object"/></short></flag>
    </subcategory>
    <subcategory>
     <example><command>mtxrun --script pdf --info foo.pdf</command></example>
     <example><command>mtxrun --script pdf --metadata foo.pdf</command></example>
     <example><command>mtxrun --script pdf --metadata --pretty foo.pdf</command></example>
+    <example><command>mtxrun --script pdf --stream=4 foo.pdf</command></example>
    </subcategory>
   </category>
  </flags>
@@ -46,10 +48,14 @@
 
 local report = application.report
 
-if pdfe then
+if not pdfe then
+    dofile(resolvers.findfile("lpdf-epd.lua","tex"))
+elseif CONTEXTLMTXMODE then
+    dofile(resolvers.findfile("util-dim.lua","tex"))
+    dofile(resolvers.findfile("lpdf-ini.lmt","tex"))
+    dofile(resolvers.findfile("lpdf-pde.lmt","tex"))
+else
     dofile(resolvers.findfile("lpdf-pde.lua","tex"))
-else
-    dofile(resolvers.findfile("lpdf-epd.lua","tex"))
 end
 
 scripts     = scripts     or { }
@@ -271,6 +277,7 @@
                         chars[i] = c
                         freqs[i] = format("U+%05X  %s  %s",k,counts[k] > 1 and "+" or " ", c)
                     else
+                        chars[i] = k == 32 and "SPACE" or format("U+%03X",k)
                         freqs[i] = format("U+%05X  %s  --",k,counts[k] > 1 and "+" or " ")
                     end
                 end
@@ -349,6 +356,15 @@
     end
 end
 
+function scripts.pdf.object(filename,n)
+    if n then
+        local pdffile = loadpdffile(filename)
+        if pdffile then
+            print(lpdf.epdf.verboseobject(pdffile,n) or "no object with number " .. n)
+        end
+    end
+end
+
 -- scripts.pdf.info("e:/tmp/oeps.pdf")
 -- scripts.pdf.metadata("e:/tmp/oeps.pdf")
 -- scripts.pdf.fonts("e:/tmp/oeps.pdf")
@@ -364,6 +380,8 @@
     scripts.pdf.metadata(filename,environment.argument("pretty"))
 elseif environment.argument("fonts") then
     scripts.pdf.fonts(filename)
+elseif environment.argument("object") then
+    scripts.pdf.object(filename,tonumber(environment.argument("object")))
 elseif environment.argument("exporthelp") then
     application.export(environment.argument("exporthelp"),filename)
 else

Added: trunk/Master/texmf-dist/scripts/context/lua/mtx-spell.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-spell.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-spell.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -0,0 +1,346 @@
+if not modules then modules = { } end modules ['mtx-patterns'] = {
+    version   = 1.001,
+    comment   = "companion to mtxrun.lua",
+    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+    copyright = "PRAGMA ADE / ConTeXt Development Team",
+    license   = "see context related readme files"
+}
+
+local find, gsub, match = string.find, string.gsub, string.match
+local concat = table.concat
+local P, R, S, C, Ct, Cmt, Cc, Cs =  lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cc, lpeg.Cs
+local patterns = lpeg.patterns
+local lpegmatch = lpeg.match
+
+local helpinfo = [[
+<?xml version="1.0"?>
+<application>
+ <metadata>
+  <entry name="name">mtx-spell</entry>
+  <entry name="detail">ConTeXt Word Filtering</entry>
+  <entry name="version">0.10</entry>
+ </metadata>
+ <flags>
+  <category name="basic">
+   <subcategory>
+    <flag name="expand"><short>expand hunspell dics and aff files</short></flag>
+    <flag name="dictionary"><short>word file (.dics)</short></flag>
+    <flag name="specification"><short>affix specification file (.aff)</short></flag>
+    <flag name="result"><short>destination file</short></flag>
+   </subcategory>
+  </category>
+ </flags>
+ <examples>
+  <category>
+   <title>Examples</title>
+   <subcategory>
+    <example><command>mtxrun --script spell --expand --dictionary="en_US.dic" --specification="en_US.txt" --result="data-us.txt"</command></example>
+   </subcategory>
+  </category>
+ </examples>
+</application>
+]]
+
+
+local application = logs.application {
+    name     = "mtx-spell",
+    banner   = "ConTeXt Word Filtering 0.10",
+    helpinfo = helpinfo,
+}
+
+local report = application.report
+local trace  = false
+
+scripts       = scripts       or { }
+scripts.spell = scripts.spell or { }
+
+---------------
+
+require("char-def")
+require("char-utf")
+
+-- nl: ij => ij
+
+do
+
+    local prefixes, suffixes, affixes, continue, collected
+
+    local function resetall()
+        prefixes  = table.setmetatableindex("table")
+        suffixes  = table.setmetatableindex("table")
+        affixes   = table.setmetatableindex("table")
+        continue  = { }
+        collected = { }
+    end
+
+    local uppers   = { }
+    local chardata = characters.data
+    for k, v in next, chardata do
+        if v.category == "lu" then
+            uppers[utf.char(k)] = true
+        end
+    end
+
+    local newline = patterns.newline
+    local digit   = patterns.digit
+    local skipped = digit + lpeg.utfchartabletopattern(uppers)
+    local ignored = 1 - newline
+    local garbage = S("'-")
+
+    local function fixeddata(data)
+        data = gsub(data,"ij","ij")
+        return data
+    end
+
+    local function registersuffix(tag,f)
+        table.insert(suffixes[tag],f)
+        table.insert(affixes [tag],f)
+    end
+
+    local function registerprefix(tag,f)
+        table.insert(prefixes[tag],f)
+        table.insert(affixes [tag],f)
+    end
+
+    local function getfixes(specification)
+
+        local data  = fixeddata(io.loaddata(specification) or "")
+        local lines = string.splitlines(data)
+
+        -- /* in two
+        -- Y/N continuation
+
+        -- [^...] [...] ...
+
+        local p0 = nil
+
+        local p1 = P("[^") * Cs((1-P("]"))^1) * P("]") / function(s)
+            local t = utf.split(s)
+            local p = 1 - lpeg.utfchartabletopattern(t)
+            p0 = p0 and (p0 * p) or p
+        end
+        local p2 = P("[") * Cs((1-P("]"))^1) * P("]") / function(s)
+            local t = utf.split(s)
+            local p = lpeg.utfchartabletopattern(t)
+            p0 = p0 and (p0 * p) or p
+        end
+        local p3 = (patterns.utf8char - S("[]"))^1 / function(s)
+            local p = P(s)
+            p0 = p0 and (p0 * p) or p
+        end
+
+        local p = (p1 + p2 + p3)^1
+
+        local function makepattern(s)
+            p0 = nil
+            lpegmatch(p,s)
+            return p0
+        end
+
+        local i = 1
+        while i <= #lines do
+            local line = lines[i]
+            local tag, continuation, n = match(line,"PFX%s+(%S+)%s+(%S+)%s+(%d+)")
+            if tag then
+                n = tonumber(n) or 0
+                continue[tag] = continuation == "Y"
+                for j=1,n do
+                    i = i + 1
+                    line = lines[i]
+                    if not find(line,"[-']") then
+                        local tag, one, two, three = match(line,"PFX%s+(%S+)%s+(%S+)%s+([^%s/]+)%S*%s+(%S+)")
+                        if tag then
+                            if one == "0" and two and three == "." then
+                                -- simple case: PFX A 0 re .
+                                registerprefix(tag,function(str)
+                                    local new = two .. str
+                                    if trace then
+                                        print("p 1",str,new)
+                                    end
+                                    return new
+                                end)
+                            elseif one == "0" and two and three then
+                            -- strip begin
+                                if trace then
+                                    print('2',line)
+                                end
+                            elseif one and two and three then
+                                if trace then
+                                    print('3',line)
+                                end
+                            else
+                                if trace then
+                                    print('4',line)
+                                end
+                            end
+                        end
+                    end
+                end
+            end
+            local tag, continuation, n = match(line,"SFX%s+(%S+)%s+(%S+)%s+(%S+)")
+            if tag then
+                n = tonumber(n) or 0
+                continue[tag] = continuation == "Y"
+                for j=1,n do
+                    i = i + 1
+                    line = lines[i]
+                    if not find(line,"[-']") then
+                        local tag, one, two, three = match(line,"SFX%s+(%S+)%s+(%S+)%s+([^%s/]+)%S*%s+(%S+)")
+                        if tag then
+                            if one == "0" and two and three == "." then
+                                -- SFX Y 0 ly .
+                                registersuffix(tag,function(str)
+                                    local new = str .. two
+                                    if trace then
+                                        print("s 1",str,new)
+                                    end
+                                    return new
+                                end)
+                            elseif one == "0" and two and three then
+                                -- SFX G 0 ing [^e]
+                                local final = makepattern(three) * P(-1)
+                                local check = (1 - final)^0 * final
+                                registersuffix(tag,function(str)
+                                    if lpegmatch(check,str) then
+                                        local new = str .. two
+                                        if trace then
+                                            print("s 2",str,new)
+                                        end
+                                        return new
+                                    end
+                                end)
+                            elseif one and two and three then
+                                -- SFX G match$ suffix old$ (dutch has sloppy matches, use english as reference)
+                                local final   = makepattern(three) * P(-1)
+                                local check   = (1 - final)^1 * final
+                                local final   = makepattern(one) * P(-1)
+                                local replace = Cs((1 - final)^1 * (final/two))
+                                registersuffix(tag,function(str)
+                                    if lpegmatch(check,str) then
+                                        local new = lpegmatch(replace,str)
+                                        if new then
+                                            if trace then
+                                                print("s 3",str,new)
+                                            end
+                                            return new
+                                        end
+                                    end
+                                end)
+                            else
+                                if trace then
+                                    print('4',line)
+                                end
+                            end
+                        end
+                    end
+                end
+            end
+            i = i + 1
+        end
+    end
+
+    local function expand(_,_,word,spec)
+        if spec then
+            local w = { word }
+            local n = 1
+            for i=1,#spec do
+                local s = spec[i]
+                local affix = affixes[s]
+                if affix then
+                    for i=1,#affix do
+                        local ai = affix[i]
+                        local wi = ai(word)
+                        if wi then
+                            n = n + 1
+                            w[n] = wi
+                            if not continue[s] then
+                                break
+                            end
+                        end
+                    end
+                end
+            end
+            for i=1,n do
+                collected[w[i]] = true
+            end
+        elseif not find(word,"/") then
+            collected[word] = true
+        end
+        return true
+    end
+
+    local function getwords(dictionary)
+        local data = fixeddata(io.loaddata(dictionary) or "")
+        local keys = { }
+        for k, v in next, prefixes do
+            keys[k] = true
+        end
+        for k, v in next, suffixes do
+            keys[k] = true
+        end
+        local validkeys = lpeg.utfchartabletopattern(keys)
+        local specifier = P("/") * Ct(C(validkeys)^1)^0 * newline
+        local pattern   = (
+            newline^1
+          + skipped * (1-newline)^0
+          + Cmt(C((1-specifier-newline-garbage)^1) * specifier^0, expand)
+          + ignored^1 * newline^1
+        )^0
+        lpegmatch(pattern,data)
+        collected = table.keys(collected)
+        table.sort(collected)
+        return collected
+    end
+
+    local function saveall(result)
+        if result then
+            io.savedata(result,concat(collected,"\n"))
+        end
+    end
+
+    function scripts.spell.expand(arguments)
+        if arguments then
+            local dictionary    = environment.arguments.dictionary
+            local specification = environment.arguments.specification
+            local result        = environment.arguments.result
+            if type(dictionary) ~= "string" or dictionary == "" then
+                report("missing --dictionary=name")
+            elseif type(specification) ~= "string" or specification == "" then
+                report("missing --specification=name")
+            elseif type(result) ~= "string" or result == "" then
+                resetall()
+                getfixes(specification)
+                getwords(dictionary)
+                saveall(result)
+                return collected
+            end
+        end
+    end
+
+end
+
+-- spell.dicaff {
+--     dictionary    = "e:/context/spell/lo/en_US.dic.txt",
+--     specification = "e:/context/spell/lo/en_US.aff.txt",
+--     result        = "e:/context/spell/lo/data-en.txt",
+-- }
+
+-- spell.dicaff {
+--     dictionary    = "e:/context/spell/lo/en_GB.dic.txt",
+--     specification = "e:/context/spell/lo/en_GB.aff.txt",
+--     result        = "e:/context/spell/lo/data-uk.txt",
+-- }
+
+-- spell.dicaff {
+--     dictionary    = "e:/context/spell/lo/nl_NL.dic.txt",
+--     specification = "e:/context/spell/lo/nl_NL.aff.txt",
+--     result        = "e:/context/spell/lo/data-nl.txt",
+-- }
+
+if environment.argument("expand") then
+    scripts.spell.expand(environment.arguments)
+elseif environment.argument("exporthelp") then
+    application.export(environment.argument("exporthelp"),environment.files[1])
+else
+    application.help()
+end

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-synctex.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-synctex.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-synctex.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -10,8 +10,9 @@
 -- InverseSearchCmdLine = mtxrun.exe --script synctex --edit --name="%f" --line="%l" $
 
 local tonumber = tonumber
-local find, match, gsub = string.find, string.match, string.gsub
+local find, match, gsub, formatters = string.find, string.match, string.gsub, string.formatters
 local isfile = lfs.isfile
+local max = math.max
 local longtostring = string.longtostring
 
 local helpinfo = [[
@@ -20,15 +21,16 @@
  <metadata>
   <entry name="name">mtx-synctex</entry>
   <entry name="detail">SyncTeX Checker</entry>
-  <entry name="version">1.00</entry>
+  <entry name="version">1.01</entry>
  </metadata>
  <flags>
   <category name="basic">
    <subcategory>
     <flag name="edit"><short>open file at line: --line=.. --editor=.. sourcefile</short></flag>
-    <flag name="list"><short>show blob: synctexfile</short></flag>
-    <flag name="goto"><short>open file at position: --page=.. --x=.. --y=.. --editor=.. synctexfile</short></flag>
-    <flag name="report"><short>show file and line: --page=.. --x=.. --y=.. --console synctexfile</short></flag>
+    <flag name="list"><short>show all areas: synctexfile</short></flag>
+    <flag name="goto"><short>open file at position: --page=.. --x=.. --y=.. [--tolerance=] --editor=.. synctexfile</short></flag>
+    <flag name="report"><short>show (tex) file and line: [--direct] --page=.. --x=.. --y=.. [--tolerance=] --console synctexfile</short></flag>
+    <flag name="find"><short>find (pdf) page and box: [--direct] --file=.. --line=.. synctexfile</short></flag>
    </subcategory>
   </category>
  </flags>
@@ -37,15 +39,22 @@
 
 local application = logs.application {
     name     = "mtx-synctex",
-    banner   = "ConTeXt SyncTeX Checker 1.00",
+    banner   = "ConTeXt SyncTeX Checker 1.01",
     helpinfo = helpinfo,
 }
 
 local report = application.report
 
+local template_show = "page=%i llx=%r lly=%r urx=%r ury=%r"
+local template_goto = "filename=%a linenumber=%a tolerance=%a"
+
+local function reportdirect(template,...)
+    print(formatters[template](...))
+end
+
 local editors = {
     console = function(specification)
-        print(string.formatters["%q %i"](specification.filename,specification.linenumber or 1))
+        print(string.formatters["%q %i %i"](specification.filename,specification.linenumber or 1,specification.tolerance))
     end,
     scite = sandbox.registerrunner {
         name     = "scite",
@@ -69,7 +78,7 @@
     end
 end
 
-local function editfile(filename,line,editor)
+local function editfile(filename,line,tolerance,editor)
     if not validfile(filename) then
         return
     end
@@ -77,6 +86,7 @@
     runner {
         filename   = filename,
         linenumber = tonumber(line) or 1,
+        tolerance  = tolerance,
     }
 end
 
@@ -184,18 +194,142 @@
     end
 end
 
-local function showlocation(filename)
+local function findlocation(filename,page,xpos,ypos,tolerance)
     if not validfile(filename) then
         return
+    elseif not page then
+        page = 1
+    elseif not xpos or not ypos then
+        report("provide x and y coordinates (unit: basepoints)")
+        return
     end
     local files = { }
     local found = false
+    local skip  = false
+    local fi    = 0
+    local ln    = 0
+    local tl    = 0
+    local lines = { }
+    for line in io.lines(filename) do
+        if found then
+            if find(line,"^}") then
+                local function locate(x,y)
+                    local dx = false
+                    local dy = false
+                    local px = (xpos + x) / factor
+                    local py = (ypos + y) / factor
+                    for i=1,#lines do
+                        local line = lines[i]
+                        -- we only look at positive cases
+                        local f, l, x, y, w, h, d = match(line,"^h(.-),(.-):(.-),(.-):(.-),(.-),(.-)$")
+                        if f and f ~= 0 then
+-- print(x,y,f)
+                            x = tonumber(x)
+                            if px >= x then
+                                w = tonumber(w)
+                                if px <= x + w then
+                                    y = tonumber(y)
+                                    d = tonumber(d)
+                                    if py >= y - d then
+                                        h = tonumber(h)
+                                        if py <= y + h then
+                                            if quit then
+                                                -- we have no overlapping boxes
+                                                fi = f
+                                                ln = l
+                                                return
+                                            else
+                                                local lx = px - x
+                                                local rx = x + w - px
+                                                local by = py - y + d
+                                                local ty = y + h - py
+                                                mx = lx < rx and lx or rx
+                                                my = by < ty and by or ty
+                                                if not dx then
+                                                    dx = mx
+                                                    dy = my
+                                                    fi = f
+                                                    ln = l
+                                                else
+                                                    if mx < dx then
+                                                        dx = mx
+                                                        di = f
+                                                        ln = l
+                                                    end
+                                                    if my < dy then
+                                                        dy = my
+                                                        fi = f
+                                                        ln = l
+                                                    end
+                                                end
+                                            end
+                                        end
+                                    end
+                                end
+                            end
+                        end
+                    end
+                end
+                locate(0,0)
+                if fi ~= 0 then
+                    return files[fi], ln, 0
+                end
+                if not tolerance then
+                    tolerance = 10
+                end
+                for s=1,tolerance,max(tolerance//10,1) do
+                    locate( s, 0) if fi ~= 0 then tl = s ; goto done end
+                    locate(-s, 0) if fi ~= 0 then tl = s ; goto done end
+                    locate( s, s) if fi ~= 0 then tl = s ; goto done end
+                    locate( s,-s) if fi ~= 0 then tl = s ; goto done end
+                    locate(-s, s) if fi ~= 0 then tl = s ; goto done end
+                    locate(-s,-s) if fi ~= 0 then tl = s ; goto done end
+                end
+                break
+            else
+                lines[#lines+1] = line
+            end
+        elseif skip then
+            if find(line,"^}") then
+                skip = false
+            end
+        elseif find(line,"^{(%d+)") then
+            local p = tonumber(match(line,"^{(%d+)"))
+            if p == page then
+                found = true
+            else
+                skip = true
+            end
+        elseif find(line,"^Input:") then
+            local id, name = match(line,"^Input:(.-):(.-)$")
+            if id then
+                files[id] = name
+            end
+        end
+    end
+ ::done::
+    if fi ~= 0 then
+        return files[fi], ln, tl
+    end
+end
+
+local function showlocation(filename,sourcename,linenumber,direct)
+    if not validfile(filename) then
+        return
+    end
+    local files = { }
+    local found = false
     local page  = 0
+    if sourcename then
+        sourcename = file.collapsepath(sourcename)
+    end
     for line in io.lines(filename) do
         if found then
             if find(line,"^}") then
                 found = false
-                report("end page: %i",page)
+                if not sourcename then
+                    report("end page: %i",page)
+                end
             else
                 local f, l, x, y, w, h, d = match(line,"^h(.-),(.-):(.-),(.-):(.-),(.-),(.-)$")
                 if f then
@@ -206,8 +340,13 @@
                     local urx = factor * ( x + tonumber(w) )
                     local ury = factor * ( y + tonumber(h) )
                     f = files[f]
-                    if f then
+                    if not f then
+                        --
+                    elseif not sourcename then
                         report("  [% 4r % 4r % 4r % 4r] : % 5i : %s",llx,lly,urx,ury,l,f)
+                    elseif f == sourcename and l == linenumber then
+                        (direct and reportdirect or report)(template_show,page,llx,lly,urx,ury)
+                        return
                     end
                 end
             end
@@ -214,7 +353,9 @@
         elseif find(line,"^{(%d+)") then
             page  = tonumber(match(line,"^{(%d+)"))
             found = true
-            report("begin page: %i",page)
+            if not sourcename then
+                report("begin page: %i",page)
+            end
         elseif find(line,"^Input:") then
             local id, name = match(line,"^Input:(.-):(.-)$")
             if id then
@@ -224,14 +365,14 @@
     end
 end
 
-local function gotolocation(filename,page,xpos,ypos,editor)
+local function gotolocation(filename,page,xpos,ypos,editor,direct,tolerance)
     if filename then
-        local target, line = findlocation(filename,tonumber(page),tonumber(xpos),tonumber(ypos))
+        local target, line, t = findlocation(filename,tonumber(page),tonumber(xpos),tonumber(ypos),tonumber(tolerance))
         if target and line then
             if editor then
-                editfile(target,line,editor)
+                editfile(target,line,t,editor)
             else
-                report("filename=%a linenumber=%a",target,line)
+                (direct and reportdirect or report)(template_goto,target,line,t)
             end
         end
     end
@@ -248,11 +389,13 @@
 if argument("edit") then
     editfile(filename,argument("line"),argument("editor"))
 elseif argument("goto") then
-    gotolocation(filename,argument("page"),argument("x"),argument("y"),argument("editor"))
+    gotolocation(filename,argument("page"),argument("x"),argument("y"),argument("editor"),argument("direct"),argument("tolerance"))
 elseif argument("report") then
-    gotolocation(filename,argument("page"),argument("x"),argument("y"),"console")
+    gotolocation(filename,argument("page"),argument("x"),argument("y"),"console",argument("direct"),argument("tolerance"))
 elseif argument("list") then
     showlocation(filename)
+elseif argument("find") then
+    showlocation(filename,argument("file"),argument("line"),argument("direct"))
 elseif argument("exporthelp") then
     application.export(argument("exporthelp"),filename)
 else

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-unicode.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-unicode.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-unicode.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -143,6 +143,7 @@
     local eastasianwidth       = texttables.eastasianwidth
     local standardizedvariants = texttables.standardizedvariants
     local arabicshaping        = texttables.arabicshaping
+    local casefolding          = texttables.casefolding
     local index                = texttables.index
     local characterdata        = characters.data
     --
@@ -164,6 +165,8 @@
                 local cjkwd     = ed and lower(ed[2] or "n")
                 local mirror    = bd and tonumber(bd[2],16)
                 local arabic    = nil
+                local lccode    = false
+                local uccode    = false
                 descriptions[description] = unicode
                 if sparse and direction == "l" then
                     direction = nil
@@ -203,6 +206,40 @@
                 if not combining or combining == 0 then
                     combining = nil
                 end
+                --
+                local cf = casefolding[unicode]
+                if cf and  tonumber(cf[1],16) == unicode then
+                    local how = cf[2]
+                    if how == "C" or how == "S" then
+                        local fold = tonumber(cf[3],16)
+                        if fold == unicode then
+                         -- print("SKIPPING",description)
+                        elseif category == "ll" then
+                            uccode = fold
+                        elseif category == "lu" then
+                            lccode = fold
+                        end
+                    elseif how == "F" then
+                        -- we can use the first
+                        local folding = { }
+                        for s in gmatch(cf[3],"%S+") do
+                            folding[#folding+1] = tonumber(s,16)
+                        end
+                        if category == "ll" then
+                            uccode = folding
+                        elseif category == "ul" then
+                            lccode = folding
+                        end
+                    else
+                        -- we skip these
+                     -- print(description)
+                     -- inspect(cf)
+                    end
+                end
+                --
+-- if specials and specials[1] == "font" then
+--     specials = nil
+-- end
                 if not char then
                     report("%U : adding entry %a",unicode,description)
                     char = {
@@ -218,9 +255,34 @@
                         specials    = specials,
                         arabic      = arabic,
                         combining   = combining,
+                        uccode      = uccode and uccode or nil,
+                        lccode      = lccode and lccode or nil,
                     }
                     characterdata[unicode] = char
                 else
+                    -- we have more case mapping (e.g. cherokee)
+                    if lccode then
+                        if type(lccode) == "table" then
+                            if type(char.lccode) ~= "table" or not are_equal(lccode,char.lccode) then
+                                report("%U : setting lccode to % t, %a",unicode,lccode,description)
+                                char.lccode = lccode
+                            end
+                        elseif char.lccode ~= lccode then
+                            report("%U : setting lccode to %a, %a, %a",unicode,lccode,description)
+                            char.lccode = lccode
+                        end
+                    end
+                    if uccode then
+                        if type(uccode) == "table" then
+                            if type(char.uccode) ~= "table" or not are_equal(uccode,char.uccode) then
+                                report("%U : setting uccode to % t, %a",unicode,uccode,description)
+                                char.uccode = uccode
+                            end
+                        elseif char.uccode ~= uccode then
+                            report("%U : setting uccode to %a, %a",unicode,uccode,description)
+                            char.uccode = uccode
+                        end
+                    end
                     if direction then
                         if char.direction ~= direction then
                             report("%U : setting direction to %a, %a",unicode,direction,description)
@@ -295,6 +357,7 @@
                     else
                         local specials = char.specials
                         if specials then
+-- if specials and specials[1] ~= "font" then
                             local t = { } for i=2,#specials do t[i] = formatters["%U"](specials[i]) end
                             if false then
                                 char.comment = nil
@@ -306,7 +369,7 @@
                                 elseif not find(comment,"check special") then
                                     char.comment = comment .. ", check special"
                                 end
-                                report("%U : check specials % + t, %a",unicode,t,description)
+                             -- report("%U : check specials % + t, %a",unicode,t,description)
                             end
                         end
                     end
@@ -397,7 +460,7 @@
                     mark = descriptions["SOLIDUS"] -- SLASH
                 end
                 if base and mark then
-                    report("adding extra char special for %a",description)
+                 -- report("adding extra char special for %a",description)
                     data.specials = { "with", base, mark }
                     data.comment  = nil
                 end
@@ -414,7 +477,7 @@
         if first then
             local d = characterdata[first]
             if d then
-                local v = d.variants
+             -- local v = d.variants
                 local v = rawget(d,"variants")
                 if not v then
                     v = { }
@@ -429,7 +492,7 @@
     end
     for unicode, ud in table.sortedpairs(characterdata) do
         if not rawget(ud,"category") and rawget(ud,"variants") then
-            report("stripping %U (variant, takes from metacharacter)",unicode)
+         -- report("stripping %U (variant, takes from metacharacter)",unicode)
             characterdata[unicode] = nil
         end
     end
@@ -437,7 +500,7 @@
 
 local preamble
 
-local function splitdefinition(str,index)
+local function splitdefinition(filename,str,index)
     local l = splitlines(str)
     local t = { }
     if index then
@@ -459,7 +522,7 @@
                             t[k] = d
                         end
                     else
-                        report("problem: %s",s)
+                        report("problem: %i %s => %s",i,filename,s)
                     end
                 end
             end
@@ -521,6 +584,7 @@
             eastasianwidth       = resolvers.findfile("eastasianwidth.txt")       or "",
             standardizedvariants = resolvers.findfile("standardizedvariants.txt") or "",
             arabicshaping        = resolvers.findfile("arabicshaping.txt")        or "",
+            casefolding          = resolvers.findfile("casefolding.txt")          or "",
             index                = resolvers.findfile("index.txt")                or "",
         }
         --
@@ -531,15 +595,17 @@
             eastasianwidth       = textfiles.eastasianwidth       ~= "" and io.loaddata(textfiles.eastasianwidth)       or "",
             standardizedvariants = textfiles.standardizedvariants ~= "" and io.loaddata(textfiles.standardizedvariants) or "",
             arabicshaping        = textfiles.arabicshaping        ~= "" and io.loaddata(textfiles.arabicshaping)        or "",
+            casefolding          = textfiles.casefolding          ~= "" and io.loaddata(textfiles.casefolding)          or "",
             index                = textfiles.index                ~= "" and io.loaddata(textfiles.index)                or "",
         }
         texttables = {
-            unicodedata          = splitdefinition(textdata.unicodedata,true),
-            bidimirroring        = splitdefinition(textdata.bidimirroring,true),
-            linebreak            = splitdefinition(textdata.linebreak,true),
-            eastasianwidth       = splitdefinition(textdata.eastasianwidth,true),
-            standardizedvariants = splitdefinition(textdata.standardizedvariants,false),
-            arabicshaping        = splitdefinition(textdata.arabicshaping,true),
+            unicodedata          = splitdefinition(textfiles.unicodedata,textdata.unicodedata,true),
+            bidimirroring        = splitdefinition(textfiles.bidimirroring,textdata.bidimirroring,true),
+            linebreak            = splitdefinition(textfiles.linebreak,textdata.linebreak,true),
+            eastasianwidth       = splitdefinition(textfiles.eastasianwidth,textdata.eastasianwidth,true),
+            standardizedvariants = splitdefinition(textfiles.standardizedvariants,textdata.standardizedvariants,false),
+            arabicshaping        = splitdefinition(textfiles.arabicshaping,textdata.arabicshaping,true),
+            casefolding          = splitdefinition(textfiles.casefolding,textdata.casefolding,true),
             index                = splitindex(textdata.index),
         }
         --
@@ -563,11 +629,88 @@
 --    [0xFE01]="centered form",
 -- }
 
+-- local variants_style={
+--    [0xFE00]="chancery style",
+--    [0xFE01]="roundhand style",
+-- }
+
+-- local variants_90={
+--    [0xFE00]="rotated 90 degrees",
+-- }
+--
+-- local variants_180={
+--    [0xFE01]="rotated 180 degrees",
+-- }
+--
+-- local variants_270={
+--    [0xFE02]="rotated 270 degrees",
+-- }
+--
+-- local variants_expanded={
+--    [0xFE00]="expanded",
+-- }
+--
+-- local variants_90_180={
+--    [0xFE00]="rotated 90 degrees",
+--    [0xFE01]="rotated 180 degrees",
+-- }
+--
+-- local variants_90_180_270={
+--    [0xFE00]="rotated 90 degrees",
+--    [0xFE01]="rotated 180 degrees",
+--    [0xFE02]="rotated 270 degrees",
+-- }
+--
+-- local variants_180_270={
+--    [0xFE01]="rotated 180 degrees",
+--    [0xFE02]="rotated 270 degrees",
+-- }
+--
+-- local variants_90_270={
+--    [0xFE00]="rotated 90 degrees",
+--    [0xFE02]="rotated 270 degrees",
+-- }
+
 function scripts.unicode.save(filename)
     if preamble then
         local data = table.serialize(characters.data,"characters.data", { hexify = true, noquotes = true })
-        data = gsub(data,"%{%s+%[0xFE0E%]=\"text style\",%s+%[0xFE0F%]=\"emoji style\",%s+%}","variants_emoji")
-        data = gsub(data,"%{%s+%[0xFE00%]=\"corner%-justified form\",%s+%[0xFE01%]=\"centered form\",%s+%}","variants_forms")
+        data = gsub(data,
+            "%{%s+%[0xFE0E%]=\"text style\",%s+%[0xFE0F%]=\"emoji style\",%s+%}",
+            "variants_emoji"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE00%]=\"corner%-justified form\",%s+%[0xFE01%]=\"centered form\",%s+%}",
+            "variants_forms"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE00%]=\"chancery style\",%s+%[0xFE01%]=\"roundhand style\",%s+%}",
+            "variants_style"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE00%]=\"dotted form\",%s+%}",
+            "variants_dotted"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE00%]=\"expanded\",%s+%}",
+            "variants_expanded"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE0%d%]=\"rotated (%d+) degrees\",%s+%}",
+            "variants_%1"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE0%d%]=\"rotated (%d+) degrees\"," ..
+              "%s*%[0xFE0%d%]=\"rotated (%d+) degrees\"," ..
+              "%s+%}",
+            "variants_%1_%2"
+        )
+        data = gsub(data,
+            "%{%s+%[0xFE0%d%]=\"rotated (%d+) degrees\"," ..
+              "%s*%[0xFE0%d%]=\"rotated (%d+) degrees\"," ..
+              "%s*%[0xFE0%d%]=\"rotated (%d+) degrees\"," ..
+              "%s+%}",
+            "variants_%1_%2_%3"
+        )
         io.savedata(filename,preamble .. data)
     end
 end
@@ -764,7 +907,7 @@
         scripts.unicode.save("char-def-new.lua")
         scripts.unicode.emoji("char-emj-new.lua")
         report("saved file %a","char-def-new.lua")
-        report("saved file %a (current 12.0, check for updates, see above!)","char-emj-new.lua")
+        report("saved file %a (current 14.0, check for updates, see above!)","char-emj-new.lua")
     else
         report("nothing to do")
     end

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-update.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-update.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-update.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -157,66 +157,6 @@
     },
 }
 
--- update.platforms = {
---     ["mswin"]          = "mswin",
---     ["windows"]        = "mswin",
---     ["win32"]          = "mswin",
---     ["win"]            = "mswin",
---  -- ["mswin"]          = "win32",
---  -- ["windows"]        = "win32",
---  -- ["win32"]          = "win32",
---  -- ["win"]            = "win32",
---     --
---  -- ["mswin-64"]       = "mswin-64",
---  -- ["windows-64"]     = "mswin-64",
---  -- ["win64"]          = "mswin-64",
---     ["mswin-64"]       = "win64",
---     ["windows-64"]     = "win64",
---     ["win64"]          = "win64",
---     --
---     ["linux"]          = "linux",
---     ["linux-32"]       = "linux",
---     ["linux32"]        = "linux",
---     --
---     ["linux-64"]       = "linux-64",
---     ["linux64"]        = "linux-64",
---     --
---     ["linuxmusl-64"]   = "linuxmusl-64",
---     --
---     ["linux-armhf"]    = "linux-armhf",
---     --
---     ["freebsd"]        = "freebsd",
---     --
---     ["freebsd-amd64"]  = "freebsd-amd64",
---     --
---     ["kfreebsd"]       = "kfreebsd-i386",
---     ["kfreebsd-i386"]  = "kfreebsd-i386",
---     --
---     ["kfreebsd-amd64"] = "kfreebsd-amd64",
---     --
---     ["linux-ppc"]      = "linux-ppc",
---     ["ppc"]            = "linux-ppc",
---     --
---     ["osx"]            = "osx-intel",
---     ["macosx"]         = "osx-intel",
---     ["osx-intel"]      = "osx-intel",
---     ["osxintel"]       = "osx-intel",
---     --
---     ["osx-ppc"]        = "osx-ppc",
---     ["osx-powerpc"]    = "osx-ppc",
---     ["osxppc"]         = "osx-ppc",
---     ["osxpowerpc"]     = "osx-ppc",
---     --
---     ["osx-64"]         = "osx-64",
---     --
---     ["solaris-intel"]  = "solaris-intel",
---     --
---     ["solaris-sparc"]  = "solaris-sparc",
---     ["solaris"]        = "solaris-sparc",
---     --
---     ["unknown"]        = "unknown",
--- }
-
 update.platforms = {
     ["mswin"]          = "mswin",
     ["windows"]        = "mswin",
@@ -238,9 +178,9 @@
     --
     ["linux-armhf"]    = "linux-armhf",
     --
-    ["openbsd"]        = "openbsd6.8",
-    ["openbsd-i386"]   = "openbsd6.8",
-    ["openbsd-amd64"]  = "openbsd6.8-amd64",
+    ["openbsd"]        = "openbsd7.2",
+    ["openbsd-i386"]   = "openbsd7.2",
+    ["openbsd-amd64"]  = "openbsd7.2-amd64",
     --
     ["freebsd"]        = "freebsd",
     ["freebsd-i386"]   = "freebsd",
@@ -266,7 +206,8 @@
     ["macosx"]         = "osx-64",
     ["osx"]            = "osx-64",
     ["osx-64"]         = "osx-64",
-    ["osx-arm64"]      = "osx-64",
+    ["osx-arm"]        = "osx-arm64",
+    ["osx-arm64"]      = "osx-arm64",
     --
  -- ["solaris-intel"]  = "solaris-intel",
     --

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtx-vscode.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtx-vscode.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtx-vscode.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -62,7 +62,9 @@
 -- me (too many different folders with source code, documentation etc). It's kind of
 -- strange because simple runners are provided by many editors. I don't want to program
 -- a lot to get such simple things done so, awaiting global tasks I stick to using the
--- terminal. But we're prepared.
+-- terminal. Also, having .vscode folderd in every place where a file sits makes no
+-- sense and clutters my disk too much. There is not much progress in this area but we
+-- are prepared.
 
 -- Another showstopper is the fact that we cannot disable utf8 for languages (like pdf,
 -- which is just bytes). I couldn't figure out how to set it in the extension.
@@ -138,7 +140,9 @@
   <category name="basic">
    <subcategory>
     <flag name="generate"><short>generate extension in sync with current version</short></flag>
+    <flag name="program"><short>use the given binary (e.g. codium, default: code)</short></flag>
     <flag name="start"><short>start vscode with extension context</short></flag>
+    <flag name="lsfile"><short>generate language server file (work in progress)</short></flag>
    </subcategory>
   </category>
  </flags>
@@ -149,6 +153,7 @@
     <example><command>mtxrun --script vscode --generate e:/vscode/extensions</command></example>
     <example><command>mtxrun --script vscode --generate</command></example>
     <example><command>mtxrun --script vscode --start</command></example>
+    <example><command>mtxrun --script vscode --program=codium --start</command></example>
    </subcategory>
   </category>
  </examples>
@@ -161,6 +166,8 @@
     helpinfo = helpinfo,
 }
 
+local concat = table.concat
+
 local report = application.report
 
 require("util-jsn")
@@ -278,6 +285,20 @@
 
     end
 
+ -- local function registersettings()
+ --
+ --     local filename = "./settings.json"
+ --
+ --     local data = {
+ --         ["editor.bracketPairColorization.enabled"]                            = false,
+ --         ["editor.bracketPairColorization.independentColorPoolPerBracketType"] = false,
+ --     }
+ --
+ --     report("saving settings %a",filename)
+ --
+ --     io.savedata(filename,data)
+ -- end
+
     local function registertheme(theme)
 
         local category = theme.category
@@ -294,6 +315,7 @@
             ["name"]        = category,
             ["colors"]      = theme.colors,
             ["tokenColors"] = theme.styles,
+            ["settings"]    = theme.settings,
         }
 
         report("saving theme %a in %a",category,filename)
@@ -353,11 +375,13 @@
             displayName = "ConTeXt",
             description = "ConTeXt Syntax Highlighting",
             publisher   = "ConTeXt Development Team",
+            publisher   = "cdt",
             version     = "1.0.0",
             engines     = {
                 vscode = "*"
             },
             categories = {
+                "Programming Languages",
                 "Lexers",
                 "Syntaxes"
             },
@@ -414,42 +438,69 @@
             tippanel  = "#444444",
             right     = "#0000FF",
             wrong     = "#FF0000",
+            default   = "#000000",
+            reverse   = "#FFFFFF",
+
+            -- some day a dark:
+
+--     red       = "#CC4444",
+--     green     = "#44CC44",
+--     blue      = "#4444FF",
+--     cyan      = "#55BBBB",
+--     magenta   = "#BB55BB",
+--     yellow    = "#BBBB55",
+--     orange    = "#B07F00",
+--     white     = "#FFFFFF",
+--     light     = "#CFCFCF",
+--     grey      = "#808080",
+--     dark      = "#4F4F4F",
+--     black     = "#000000",
+--     selection = "#F7F7F7",
+--     logpanel  = "#E7E7E7",
+--     textpanel = "#1E1E1E", -- VS "#101010",
+--     linepanel = "#A7A7A7",
+--     tippanel  = "#444444",
+--     right     = "#0000FF",
+--     wrong     = "#FF0000",
+--     default   = "#D4D4D4",
+--     reverse   = "#000000",
+
         }
 
         local colors = {
             ["editor.background"]               = mycolors.textpanel,
-            ["editor.foreground"]               = mycolors.black,
-            ["editorLineNumber.foreground"]     = mycolors.black,
+            ["editor.foreground"]               = mycolors.default,
+            ["editorLineNumber.foreground"]     = mycolors.default,
             ["editorIndentGuide.background"]    = mycolors.textpanel,
             ["editorBracketMatch.background"]   = mycolors.textpanel,
             ["editorBracketMatch.border"]       = mycolors.orange,
             ["editor.lineHighlightBackground"]  = mycolors.textpanel,
-            ["focusBorder"]                     = mycolors.black,
+            ["focusBorder"]                     = mycolors.default,
 
-            ["activityBar.background"]          = mycolors.black,
+            ["activityBar.background"]          = mycolors.default,
 
-            ["sideBar.background"]              = mycolors.linepanel,
-            ["sideBar.foreground"]              = mycolors.black,
-            ["sideBar.border"]                  = mycolors.white,
-            ["sideBarTitle.foreground"]         = mycolors.black,
+            ["editorGutter.background"]         = mycolors.linepanel,
+            ["editorGutter.foreground"]         = mycolors.default,
+            ["editorGutter.border"]             = mycolors.reverse,
+            ["sideBarTitle.foreground"]         = mycolors.default,
             ["sideBarSectionHeader.background"] = mycolors.linepanel,
-            ["sideBarSectionHeader.foreground"] = mycolors.black,
+            ["sideBarSectionHeader.foreground"] = mycolors.default,
 
-            ["statusBar.foreground"]            = mycolors.black,
+            ["statusBar.foreground"]            = mycolors.default,
             ["statusBar.background"]            = mycolors.linepanel,
-            ["statusBar.border"]                = mycolors.white,
-            ["statusBar.noFolderForeground"]    = mycolors.black,
+            ["statusBar.border"]                = mycolors.reverse,
+            ["statusBar.noFolderForeground"]    = mycolors.default,
             ["statusBar.noFolderBackground"]    = mycolors.linepanel,
-            ["statusBar.debuggingForeground"]   = mycolors.black,
+            ["statusBar.debuggingForeground"]   = mycolors.default,
             ["statusBar.debuggingBackground"]   = mycolors.linepanel,
 
-            ["notification.background"]         = mycolors.black,
+            ["notification.background"]         = mycolors.default,
         }
 
         local styles = {
 
             { scope = "context.whitespace",              settings = { } },
-            { scope = "context.default",                 settings = { foreground = mycolors.black } },
+            { scope = "context.default",                 settings = { foreground = mycolors.default } },
             { scope = "context.number",                  settings = { foreground = mycolors.cyan } },
             { scope = "context.comment",                 settings = { foreground = mycolors.yellow } },
             { scope = "context.keyword",                 settings = { foreground = mycolors.blue, fontStyle = "bold" } },
@@ -457,8 +508,8 @@
             { scope = "context.error",                   settings = { foreground = mycolors.red } },
             { scope = "context.label",                   settings = { foreground = mycolors.red, fontStyle = "bold"  } },
             { scope = "context.nothing",                 settings = { } },
-            { scope = "context.class",                   settings = { foreground = mycolors.black, fontStyle = "bold" } },
-            { scope = "context.function",                settings = { foreground = mycolors.black, fontStyle = "bold" } },
+            { scope = "context.class",                   settings = { foreground = mycolors.default, fontStyle = "bold" } },
+            { scope = "context.function",                settings = { foreground = mycolors.default, fontStyle = "bold" } },
             { scope = "context.constant",                settings = { foreground = mycolors.cyan, fontStyle = "bold" } },
             { scope = "context.operator",                settings = { foreground = mycolors.blue } },
             { scope = "context.regex",                   settings = { foreground = mycolors.magenta } },
@@ -465,22 +516,22 @@
             { scope = "context.preprocessor",            settings = { foreground = mycolors.yellow, fontStyle = "bold" } },
             { scope = "context.tag",                     settings = { foreground = mycolors.cyan } },
             { scope = "context.type",                    settings = { foreground = mycolors.blue } },
-            { scope = "context.variable",                settings = { foreground = mycolors.black } },
+            { scope = "context.variable",                settings = { foreground = mycolors.default } },
             { scope = "context.identifier",              settings = { } },
             { scope = "context.linenumber",              settings = { background = mycolors.linepanel } },
             { scope = "context.bracelight",              settings = { foreground = mycolors.orange, fontStyle = "bold" } },
             { scope = "context.bracebad",                settings = { foreground = mycolors.orange, fontStyle = "bold" } },
             { scope = "context.controlchar",             settings = { } },
-            { scope = "context.indentguide",             settings = { foreground = mycolors.linepanel, back = colors.white } },
-            { scope = "context.calltip",                 settings = { foreground = mycolors.white, back = colors.tippanel } },
+            { scope = "context.indentguide",             settings = { foreground = mycolors.linepanel, back = colors.reverse } },
+            { scope = "context.calltip",                 settings = { foreground = mycolors.reverse, back = colors.tippanel } },
             { scope = "context.invisible",               settings = { background = mycolors.orange } },
             { scope = "context.quote",                   settings = { foreground = mycolors.blue, fontStyle = "bold" } },
             { scope = "context.special",                 settings = { foreground = mycolors.blue } },
             { scope = "context.extra",                   settings = { foreground = mycolors.yellow } },
-            { scope = "context.embedded",                settings = { foreground = mycolors.black, fontStyle = "bold" } },
+            { scope = "context.embedded",                settings = { foreground = mycolors.default, fontStyle = "bold" } },
             { scope = "context.char",                    settings = { foreground = mycolors.magenta } },
             { scope = "context.reserved",                settings = { foreground = mycolors.magenta, fontStyle = "bold" } },
-            { scope = "context.definition",              settings = { foreground = mycolors.black, fontStyle = "bold" } },
+            { scope = "context.definition",              settings = { foreground = mycolors.default, fontStyle = "bold" } },
             { scope = "context.okay",                    settings = { foreground = mycolors.dark } },
             { scope = "context.warning",                 settings = { foreground = mycolors.orange } },
             { scope = "context.standout",                settings = { foreground = mycolors.orange, fontStyle = "bold" } },
@@ -492,12 +543,12 @@
             { scope = "context.plain",                   settings = { foreground = mycolors.dark, fontStyle = "bold" } },
             { scope = "context.user",                    settings = { foreground = mycolors.green } },
             { scope = "context.data",                    settings = { foreground = mycolors.cyan, fontStyle = "bold" } },
-            { scope = "context.text",                    settings = { foreground = mycolors.black } },
+            { scope = "context.text",                    settings = { foreground = mycolors.default } },
 
             { scope = { "emphasis" }, settings = { fontStyle = "italic" } },
             { scope = { "strong"   }, settings = { fontStyle = "bold"   } },
 
-            { scope = { "comment"  }, settings = { foreground = mycolors.black  } },
+            { scope = { "comment"  }, settings = { foreground = mycolors.default  } },
             { scope = { "string"   }, settings = { foreground = mycolors.magenta } },
 
             {
@@ -541,7 +592,7 @@
                     "entity.name.function.shell"
                 },
                 settings = {
-                    foreground = mycolors.black,
+                    foreground = mycolors.default,
                 }
             },
 
@@ -550,7 +601,7 @@
                     "entity.name.tag",
                 },
                 settings = {
-                    foreground = mycolors.black,
+                    foreground = mycolors.default,
                 }
             },
 
@@ -563,6 +614,8 @@
             styles      = styles,
         }
 
+     -- registersettings()
+
     end
 
     do
@@ -576,34 +629,36 @@
             clear            = true,
         }
 
+        -- chcp 65001 ; ...
+
         local tasks = {
             {
                 group   = "build",
                 label   = "process tex file",
                 type    = "shell",
-                command =                          "context     --autogenerate --autopdf ${file}",
-                windows = { command = "chcp 65001 ; context.exe --autogenerate --autopdf ${file}" },
+                command =             "context     --autogenerate --autopdf ${file}",
+                windows = { command = "context.exe --autogenerate --autopdf ${file}" },
             },
             {
                 group   = "build",
                 label   = "check tex file",
                 type    = "shell",
-                command =                          "mtxrun     --autogenerate --script check ${file}",
-                windows = { command = "chcp 65001 ; mtxrun.exe --autogenerate --script check ${file}" },
+                command =             "mtxrun     --autogenerate --script check ${file}",
+                windows = { command = "mtxrun.exe --autogenerate --script check ${file}" },
             },
             {
                 group   = "build",
                 label   = "identify fonts",
                 type    = "shell",
-                command =                          "mtxrun     --script fonts --reload --force",
-                windows = { command = "chcp 65001 ; mtxrun.exe --script fonts --reload --force" },
+                command =             "mtxrun     --script fonts --reload --force",
+                windows = { command = "mtxrun.exe --script fonts --reload --force" },
             },
             {
                 group   = "build",
                 label   = "process lua file",
                 type    = "shell",
-                command =                          "mtxrun     --script ${file}",
-                windows = { command = "chcp 65001 ; mtxrun.exe --script ${file}" },
+                command =             "mtxrun     --script ${file}",
+                windows = { command = "mtxrun.exe --script ${file}" },
             },
         }
 
@@ -610,7 +665,7 @@
         for i=1,#tasks do
             local task = tasks[i]
             if not task.windows then
-                task.windows = {  command = "chcp 65001 ; " .. task.command }
+                task.windows = {  command = task.command }
             end
             if not task.presentation then
                 task.presentation = presentation
@@ -697,7 +752,7 @@
         for i=1,#t do
             result[i] = string.gsub(t[i],".",escapes)
         end
-        return table.concat(result,"|")
+        return concat(result,"|")
     end
 
     local function capture(str)
@@ -869,12 +924,12 @@
         -- mp argument {...text}
         local function words(list)
             table.sort(list,sorter)
-            return "\\\\(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z])"
+            return "\\\\(" .. concat(list,"|") .. ")" .. "(?=[^a-zA-Z])"
         end
 
         local function bwords(list)
             table.sort(list,sorter)
-            return "(\\\\(" .. table.concat(list,"|") .. "))\\s*(\\{)"
+            return "(\\\\(" .. concat(list,"|") .. "))\\s*(\\{)"
         end
 
         local function ewords()
@@ -883,7 +938,7 @@
 
         local function environments(list)
             table.sort(list,sorter)
-            last = table.concat(list,"|")
+            last = concat(list,"|")
             if #list > 1 then
                 last = "(?:" .. last .. ")"
             end
@@ -975,7 +1030,7 @@
 
                 comment = {
                     name  = style("context.comment", "comment"),
-                    match = texcomment,
+                    match = comment,
                 },
 
                 constant = {
@@ -1188,7 +1243,7 @@
 
         local function words(list)
             table.sort(list,sorter)
-            return "(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z\\_@!?\127-\255])"
+            return "(" .. concat(list,"|") .. ")" .. "(?=[^a-zA-Z\\_@!?\127-\255])"
         end
 
         local capturedshortcuts          = oneof(mergedshortcuts)
@@ -1401,7 +1456,7 @@
 
         local function words(list)
             table.sort(list,sorter)
-            return "(" .. table.concat(list,"|") .. ")" .. "(?=[^a-zA-Z])"
+            return "(" .. concat(list,"|") .. ")" .. "(?=[^a-zA-Z])"
         end
 
         local capturedkeywords = words {
@@ -1642,7 +1697,7 @@
 
             category    = "cld",
             description = "ConTeXt CLD",
-            suffixes    = { "lua", "luc", "cld", "tuc", "luj", "lum", "tma", "lfg", "luv", "lui" },
+            suffixes    = { "lmt", "lua", "luc", "cld", "tuc", "luj", "lum", "tma", "lfg", "luv", "lui" },
             version     = lualexer.version,
             setup       = lualexer.setup,
 
@@ -2118,7 +2173,7 @@
 
         local function words(list)
             table.sort(list,sorter)
-            local str = table.concat(list,"|")
+            local str = concat(list,"|")
             return "(" .. str .. "|" .. string.upper(str) .. ")" .. "(?=[^a-zA-Z])"
         end
 
@@ -2501,7 +2556,7 @@
 
         local function words(list)
             table.sort(list,sorter)
-            return "\\b(" .. table.concat(list,"|") .. ")\\b"
+            return "\\b(" .. concat(list,"|") .. ")\\b"
         end
 
         local capturedkeywords = words { -- copied from cpp.lua
@@ -3157,10 +3212,272 @@
 
 end
 
+-- {name: 'inherits: \\setupframed'}
+
+function scripts.vscode.ls(forcedinterface)
+
+    local interfaces = forcedinterfaces or environment.files or userinterfaces
+    if not interfaces.en then
+        -- loaded as script so we have "cont-yes.*" as name
+        interfaces = { "en" }
+    end
+    --
+    local filename = "context-en.xml"
+    local xmlfile  = resolvers.findfile(filename) or ""
+    if xmlfile == "" then
+        report("unable to locate %a",filename)
+        return
+    end
+    --
+    local filename = "mult-def.lua"
+    local deffile  = resolvers.findfile(filename) or ""
+    if deffile == "" then
+        report("unable to locate %a",filename)
+        return
+    end
+    local interface = dofile(deffile)
+    if not interface or not next(interface) then
+        report("invalid file %a",filename)
+        return
+    end
+    local variables = interface.variables
+    local constants = interface.constants
+    local commands  = interface.commands
+    local elements  = interface.elements
+    --
+    local collected = { }
+    --
+    report("loading %a",xmlfile)
+    local xmlroot = xml.load(xmlfile)
+
+    local interfaces = { "en" }
+
+--     <cd:keywords list="yes">
+--      <cd:inherit name="setupalign"/>
+--     </cd:keywords>
+
+    local function arguments(e)
+        local p = { }
+        for e in xml.collected(e,"/cd:arguments/*") do
+            local tg = e.tg
+            if tg == "keywords" then
+                local a = { }
+                for e in xml.collected(e,"/*") do
+                    a[#a+1] = {
+                        name = e.at.type
+                    }
+                end
+                p[#p+1] = {
+                    type       = tg,
+                    attributes = #a > 0 and a or nil,
+                    optional   = e.at.optional == "yes" or nil
+                }
+            elseif tg == "assignments" then
+                local a = { }
+                for e in xml.collected(e,"/parameter") do
+                 -- local c = { e.at.name, "=" }
+                    local c = { }
+                    for e in xml.collected(e,"/constant") do
+                        c[#c+1] = e.at.type
+                    end
+                 -- if #c > 0 then
+                 --     a[#a+1] = {
+                 --         name = concat(c, " ") -- maybe "|"
+                 --     }
+                 -- end
+                    a[#a+1] = {
+                        name = e.at.name .. "=" .. concat(c, " ") -- maybe "|"
+                    }
+                end
+                p[#p+1] = {
+                    type       = tg,
+                    attributes = #a > 0 and a or nil,
+                    optional   = e.at.optional == "yes" or nil
+                }
+            else -- e.g. "content"
+                p[#p+1] = {
+                    type     = tg,
+                    optional = e.at.optional == "yes" or nil
+                }
+            end
+        end
+        return p
+    end
+
+    local function details(e, f)
+        local d = { "\\" .. f }
+        local n = 0
+        for e in xml.collected(e,"/cd:arguments/*") do
+            local tg = e.tg
+            if tg == "keywords" then
+                n = n + 1
+                if e.at.optional == "yes" then
+                    d[#d+1] = "[optional " .. n .. ":..,..]"
+                else
+                    d[#d+1] = "[mandate "  .. n .. ":..,..]"
+                end
+            elseif tg == "assignments" then
+                n = n + 1
+                if e.at.optional == "yes" then
+                    d[#d+1] = "[optional " .. n .. ":key=val,key=val,..]"
+                else
+                    d[#d+1] = "[mandate "  .. n .. ":key=val,key=val,..]"
+                end
+            else
+                d[#d+1] = "{ content }"
+            end
+        end
+        return concat(d, " ")
+    end
+
+    -- this one is a bit weird as it could be assembled in the languages server on the fly and
+    -- it bloats the file
+
+    local function documentation(c)
+        local d = { c.detail }
+        local p = c.params
+        if p then
+            local n = 0
+            for i=1,#p do
+                local pi = p[i]
+                local ti = pi.type
+                local ai = pi.attributes
+                if ti == "keywords" then
+                    n = n + 1
+                    if pi.optional then
+                        d[#d+1] = "[optional keywords " .. n .. "]"
+                    else
+                        d[#d+1] = "[mandate  keywords " .. n .. "]"
+                    end
+                    if ai then
+                        local t = { }
+                        for j=1,#ai do
+                            t[#t+1] = ai[j].name
+                        end
+                        if #t > 0 then
+                            d[#d+1] = concat(t," ")
+                        end
+                    end
+                elseif ti == "assignments" then
+                    n = n + 1
+                    if pi.optional then
+                        d[#d+1] = "[optional assignments " .. n .. "]"
+                    else
+                        d[#d+1] = "[mandate  assignments " .. n .. "]"
+                    end
+                    if ai then
+                        local t = { }
+                        for j=1,#ai do
+                            t[#t+1] = ai[j].name
+                        end
+                        if #t > 0 then
+                            d[#d+1] = concat(t,"\n")
+                        end
+                    end
+                else
+                    if pi.optional then
+                        d[#d+1] = "{ optional content }"
+                    else
+                        d[#d+1] = "{ mandate content }"
+                    end
+                end
+            end
+        end
+        c.documentation = concat(d,"\n")
+--         inspect(c.documentation)
+    end
+
+    if not xml.expand then
+        -- will be in next version
+        function xml.expand(root,pattern,whatever)
+            local collected = xml.applylpath(root,pattern)
+            if collected then
+                for c=1,#collected do
+                    local e = collected[c]
+                    local p = e.__p__
+                    if p then
+                        local d = p.dt
+                        local n = e.ni
+                        local t = whatever(e,p)
+                        if type(t) == "table" then
+                            d[n] = t[1]
+                            for i=2,#t do
+                                n = n + 1
+                                table.insert(d,n,t[i])
+                            end
+                        elseif t then
+                            d[n] = t
+                        end
+                    end
+                end
+            end
+        end
+    end
+
+    do
+        local c = { }
+        xml.expand(xmlroot,"/cd:interface/cd:interface/cd:command/**/inherit",function(e)
+            local f = c[e.at.name]
+            if not f then
+                f = xml.first(xmlroot,"/cd:interface/cd:interface/cd:command[@name='" .. e.at.name .. "']/cd:arguments")
+                c[e.at.name] = f
+            end
+            return f and f.dt
+        end)
+    end
+
+    for i=1,#interfaces do
+        local interface = interfaces[i]
+        local start = elements.start[interface] or elements.start.en
+        local stop  = elements.stop [interface] or elements.stop .en
+        for e in xml.collected(xmlroot,"cd:interface/cd:command") do
+            local at   = e.at
+            local name = at["name"] or ""
+            local type = at["type"]
+            if name ~= "" then
+                local c = commands[name]
+                local n = (c and (c[interface] or c.en)) or c or name
+                local sequence = xml.all(e,"/cd:sequence/*")
+                if at.generated == "yes" then
+                    -- skip (for now)
+                elseif type ~= "environment" then
+                    collected[#collected+1] = {
+                        name   = n,
+                        detail = details(e, n),
+                        params = arguments(e), -- why not "parameters"
+                    }
+                else
+                    local f = start .. n
+                    collected[#collected+1] = {
+                        name   = f,
+                        start  = f,
+                        stop   = stop  .. n,
+                        detail = details(e, f),
+                        params = arguments(e), -- why not "parameters"
+                    }
+                end
+            end
+        end
+    end
+    for i=1,#collected do
+        documentation(collected[i])
+    end
+    local jsonname = "vscode-context-ls.json"
+ -- local exmlname = "vscode-context-ls.xml"
+    report("")
+    report("vscode ls file saved: %s",jsonname)
+    report("")
+    io.savedata(jsonname,utilities.json.tojson(collected))
+ -- io.savedata(exmlname,tostring(xmlroot))
+end
+
 function scripts.vscode.start()
     local path = locate()
     if path then
-        local command = 'start "vs code context" code --reuse-window --ignore-gpu-blacklist --extensions-dir "' .. path .. '" --install-extension context'
+        local codecmd = environment.arguments.program or "code" -- can be codium
+     -- local command = 'start "vs code context" ' .. codecmd .. ' --reuse-window --ignore-gpu-blacklist --extensions-dir "' .. path .. '" --install-extension context'
+     -- local command = 'start "vs code context" ' .. codecmd .. ' --reuse-window --extensions-dir "' .. path .. '" --install-extension context'
+        local command = 'start "vs code context" ' .. codecmd .. ' --reuse-window --extensions-dir "' .. path .. '" --verbose --force --install-extension cdt.context'
         report("running command: %s",command)
         os.execute(command)
     end
@@ -3168,6 +3485,8 @@
 
 if environment.arguments.generate then
     scripts.vscode.generate()
+elseif environment.arguments.lsfile then
+    scripts.vscode.ls()
 elseif environment.arguments.start then
     scripts.vscode.start()
 elseif environment.arguments.exporthelp then
@@ -3176,4 +3495,6 @@
     application.help()
 end
 
-scripts.vscode.generate([[t:/vscode/data/context/extensions]])
+-- scripts.vscode.ls()
+
+-- scripts.vscode.generate([[t:/vscode/data/context/extensions]])

Modified: trunk/Master/texmf-dist/scripts/context/lua/mtxrun.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/context/lua/mtxrun.lua	2023-02-26 14:42:15 UTC (rev 66174)
+++ trunk/Master/texmf-dist/scripts/context/lua/mtxrun.lua	2023-02-26 14:42:54 UTC (rev 66175)
@@ -1201,7 +1201,7 @@
 
 package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true
 
--- original size: 38703, stripped down to: 19489
+-- original size: 38742, stripped down to: 19489
 
 if not modules then modules={} end modules ['l-lpeg']={
  version=1.001,
@@ -2004,7 +2004,7 @@
 
 package.loaded["l-string"] = package.loaded["l-string"] or true
 
--- original size: 6644, stripped down to: 3410
+-- original size: 6955, stripped down to: 3504
 
 if not modules then modules={} end modules ['l-string']={
  version=1.001,
@@ -2014,7 +2014,7 @@
  license="see context related readme files"
 }
 local string=string
-local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower
+local sub,gmatch,format,char,byte,rep,lower,find=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower,string.find
 local lpegmatch,patterns=lpeg.match,lpeg.patterns
 local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs
 local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote
@@ -2024,10 +2024,18 @@
 function string.quoted(str)
  return format("%q",str) 
 end
-function string.count(str,pattern) 
+function string.count(str,pattern)
  local n=0
- for _ in gmatch(str,pattern) do 
-  n=n+1
+ local i=1
+ local l=#pattern
+ while true do
+  i=find(str,pattern,i)
+  if i then
+   n=n+1
+   i=i+l
+  else
+   break
+  end
  end
  return n
 end
@@ -3285,7 +3293,7 @@
 
 package.loaded["l-io"] = package.loaded["l-io"] or true
 
--- original size: 11829, stripped down to: 6331
+-- original size: 11988, stripped down to: 6430
 
 if not modules then modules={} end modules ['l-io']={
  version=1.001,
@@ -3352,9 +3360,12 @@
   flush()
  end
 end
-function io.savedata(filename,data,joiner)
- local f=open(filename,"wb")
+function io.savedata(filename,data,joiner,append)
+ local f=open(filename,append and "ab" or "wb")
  if f then
+  if append and joiner and f:seek("end")>0 then
+   f:write(joiner)
+  end
   if type(data)=="table" then
    f:write(concat(data,joiner or ""))
   elseif type(data)=="function" then
@@ -3637,17 +3648,17 @@
 
 package.loaded["l-number"] = package.loaded["l-number"] or true
 
--- original size: 5720, stripped down to: 2176
+-- original size: 4588, stripped down to: 2159
 
 if not modules then modules={} end modules ['l-number']={
  version=1.001,
- comment="companion to luat-lib.mkiv",
+ comment="companion to luat-lib.mkxl",
  author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
  copyright="PRAGMA ADE / ConTeXt Development Team",
  license="see context related readme files"
 }
 local tostring,tonumber=tostring,tonumber
-local format,floor,match,rep=string.format,math.floor,string.match,string.rep
+local format,match,rep=string.format,string.match,string.rep
 local concat,insert=table.concat,table.insert
 local lpegmatch=lpeg.match
 local floor=math.floor
@@ -3837,7 +3848,7 @@
 
 package.loaded["l-os"] = package.loaded["l-os"] or true
 
--- original size: 19409, stripped down to: 10419
+-- original size: 20585, stripped down to: 10701
 
 if not modules then modules={} end modules ['l-os']={
  version=1.001,
@@ -3847,10 +3858,10 @@
  license="see context related readme files"
 }
 local os=os
-local date,time=os.date,os.time
+local date,time,difftime=os.date,os.time,os.difftime
 local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
 local concat=table.concat
-local random,ceil,randomseed=math.random,math.ceil,math.randomseed
+local random,ceil,randomseed,modf=math.random,math.ceil,math.randomseed,math.modf
 local type,setmetatable,tonumber,tostring=type,setmetatable,tonumber,tostring
 do
  local selfdir=os.selfdir
@@ -3948,7 +3959,7 @@
    osenv[K]=v
   end
   function os.getenv(k)
-   local K=upper(k)
+   local K=upper(k) 
    local v=osenv[K] or osgetenv(K) or osgetenv(k)
    if v=="" then
     return nil
@@ -3966,22 +3977,6 @@
   setmetatable(os.env,{ __index=__index,__newindex=__newindex } )
  end
 end
-local execute=os.execute
-local iopopen=io.popen
-local function resultof(command)
- local handle=iopopen(command,"r") 
- if handle then
-  local result=handle:read("*all") or ""
-  handle:close()
-  return result
- else
-  return ""
- end
-end
-os.resultof=resultof
-function os.pipeto(command)
- return iopopen(command,"w") 
-end
 if not io.fileseparator then
  if find(os.getenv("PATH"),";",1,true) then
   io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows"
@@ -3996,229 +3991,232 @@
 else
  os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' }
 end
-local launchers={
- windows="start %s",
- macosx="open %s",
- unix="xdg-open %s &> /dev/null &",
-}
-function os.launch(str)
- local command=format(launchers[os.name] or launchers.unix,str)
- execute(command)
+do
+ local execute=os.execute
+ local iopopen=io.popen
+ local ostype=os.type
+ local function resultof(command)
+  local handle=iopopen(command,ostype=="windows" and "rb" or "r")
+  if handle then
+   local result=handle:read("*all") or ""
+   handle:close()
+   return result
+  else
+   return ""
+  end
+ end
+ os.resultof=resultof
+ function os.pipeto(command)
+  return iopopen(command,"w") 
+ end
+ local launchers={
+  windows="start %s",
+  macosx="open %s",
+  unix="xdg-open %s &> /dev/null &",
+ }
+ function os.launch(str)
+  local command=format(launchers[os.name] or launchers.unix,str)
+  execute(command)
+ end
 end
-local gettimeofday=os.gettimeofday or os.clock
-os.gettimeofday=gettimeofday
-local startuptime=gettimeofday()
-function os.runtime()
- return gettimeofday()-startuptime
+do
+ local gettimeofday=os.gettimeofday or os.clock
+ os.gettimeofday=gettimeofday
+ local startuptime=gettimeofday()
+ function os.runtime()
+  return gettimeofday()-startuptime
+ end
 end
-local resolvers=os.resolvers or {}
-os.resolvers=resolvers
-setmetatable(os,{ __index=function(t,k)
- local r=resolvers[k]
- return r and r(t,k) or nil 
-end })
-local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or ""
-if platform~="" then
- os.platform=platform
-elseif os.type=="windows" then
- function resolvers.platform(t,k)
-  local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or ""
-  local platform=""
-  if find(architecture,"AMD64",1,true) then
-   platform="win64"
+do
+ local name=os.name or "linux"
+ local platform=os.getenv("MTX_PLATFORM") or ""
+ local architecture=os.uname and os.uname().machine 
+ local bits=os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
+ if platform~="" then
+ elseif os.type=="windows" then
+  architecture=string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
+  if architecture=="x86_64" then
+   bits,platform=64,"win64"
+  elseif find(architecture,"amd64") then
+   bits,platform=64,"win64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"windows-arm64"
+  elseif find(architecture,"arm32") then
+   bits,platform=32,"windows-arm32"
   else
-   platform="mswin"
+   bits,platform=32,"mswin"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-elseif name=="linux" then
- function resolvers.platform(t,k)
-  local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or ""
-  local platform=os.getenv("MTX_PLATFORM") or ""
+ elseif name=="linux" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
   local musl=find(os.selfdir or "","linuxmusl")
-  if platform~="" then
-  elseif find(architecture,"x86_64",1,true) then
-   platform=musl and "linuxmusl" or "linux-64"
-  elseif find(architecture,"ppc",1,true) then
-   platform="linux-ppc"
+  if find(architecture,"x86_64") then
+   bits,platform=64,musl and "linuxmusl" or "linux-64"
+  elseif find(architecture,"ppc") then
+   bits,platform=32,"linux-ppc" 
   else
-   platform=musl and "linuxmusl" or "linux"
+   bits,platform=32,musl and "linuxmusl" or "linux"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-elseif name=="macosx" then
- function resolvers.platform(t,k)
-  local architecture=resultof("echo $HOSTTYPE") or ""
-  local platform=""
+ elseif name=="macosx" then
+  architecture=architecture or resultof("echo $HOSTTYPE") or ""
   if architecture=="" then
-   platform="osx-intel"
-  elseif find(architecture,"i386",1,true) then
-   platform="osx-intel"
-  elseif find(architecture,"x86_64",1,true) then
-   platform="osx-64"
-  elseif find(architecture,"arm64",1,true) then
-   platform="osx-64"
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"i386") then
+   bits,platform=64,"osx-intel"
+  elseif find(architecture,"x86_64") then
+   bits,platform=64,"osx-64"
+  elseif find(architecture,"arm64") then
+   bits,platform=64,"osx-arm"
   else
-   platform="osx-ppc"
+   bits,platform=32,"osx-ppc"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-elseif name=="sunos" then
- function resolvers.platform(t,k)
-  local architecture=resultof("uname -m") or ""
-  local platform=""
-  if find(architecture,"sparc",1,true) then
-   platform="solaris-sparc"
+ elseif name=="sunos" then
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"sparc") then
+   bits,platform=32,"solaris-sparc"
   else 
-   platform="solaris-intel"
+   bits,platform=32,"solaris-intel"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-elseif name=="freebsd" then
- function resolvers.platform(t,k)
-  local architecture=resultof("uname -m") or ""
-  local platform=""
-  if find(architecture,"amd64",1,true) then
-   platform="freebsd-amd64"
+ elseif name=="freebsd" then
+  architecture=architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
+  if find(architecture,"amd64") or find(architecture,"AMD64") then
+   bits,platform=64,"freebsd-amd64"
   else
-   platform="freebsd"
+   bits,platform=32,"freebsd"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-elseif name=="kfreebsd" then
- function resolvers.platform(t,k)
-  local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or ""
-  local platform=""
-  if find(architecture,"x86_64",1,true) then
-   platform="kfreebsd-amd64"
+ elseif name=="kfreebsd" then
+  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+  if architecture=="x86_64" then
+   bits,platform=64,"kfreebsd-amd64"
   else
-   platform="kfreebsd-i386"
+   bits,platform=32,"kfreebsd-i386"
   end
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
+ else
+  architecture=architecture or resultof("uname -m") or ""
+  if find(architecture,"aarch64") then
+   bits,platform="linux-aarch64"
+  elseif find(architecture,"armv7l") then
+   bits,platform=32,"linux-armhf"
+  elseif find(architecture,"mips64") or find(architecture,"mips64el") then
+   bits,platform=64,"linux-mipsel"
+  elseif find(architecture,"mipsel") or find(architecture,"mips") then
+   bits,platform=32,"linux-mipsel"
+  else
+   bits,platform=64,"linux-64" 
+  end
  end
-else
- function resolvers.platform(t,k)
-  local platform="linux"
-  os.setenv("MTX_PLATFORM",platform)
-  os.platform=platform
-  return platform
- end
-end
-os.newline=name=="windows" and "\013\010" or "\010" 
-function resolvers.bits(t,k)
- local bits=find(os.platform,"64",1,true) and 64 or 32
+ os.setenv("MTX_PLATFORM",platform)
+ os.setenv("MTX_BITS",bits)
+ os.platform=platform
  os.bits=bits
- return bits
+ os.newline=name=="windows" and "\013\010" or "\010" 
 end
-local t={ 8,9,"a","b" }
-function os.uuid()
- return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
-  random(0xFFFF),random(0xFFFF),
-  random(0x0FFF),
-  t[ceil(random(4))] or 8,random(0x0FFF),
-  random(0xFFFF),
-  random(0xFFFF),random(0xFFFF),random(0xFFFF)
- )
+do
+ local t={ 8,9,"a","b" }
+ function os.uuid()
+  return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
+   random(0xFFFF),random(0xFFFF),
+   random(0x0FFF),
+   t[ceil(random(4))] or 8,random(0x0FFF),
+   random(0xFFFF),
+   random(0xFFFF),random(0xFFFF),random(0xFFFF)
+  )
+ end
 end
-local d
-function os.timezone(delta)
- d=d or ((tonumber(date("%H")) or 0)-(tonumber(date("!%H")) or 0))
- if delta then
-  if d>0 then
-   return format("+%02i:00",d)
+do
+ local hour,min
+ function os.timezone(difference)
+  if not hour then
+   local current=time()
+   local utcdate=date("!*t",current)
+   local localdate=date("*t",current)
+   localdate.isdst=false
+   local timediff=difftime(time(localdate),time(utcdate))
+   hour,min=modf(timediff/3600)
+   min=min*60
+  end
+  if difference then
+   return hour,min
   else
-   return format("-%02i:00",-d)
+   return format("%+03d:%02d",hour,min) 
   end
- else
-  return 1
  end
-end
-local timeformat=format("%%s%s",os.timezone(true))
-local dateformat="!%Y-%m-%d %H:%M:%S"
-local lasttime=nil
-local lastdate=nil
-function os.fulltime(t,default)
- t=t and tonumber(t) or 0
- if t>0 then
- elseif default then
-  return default
- else
-  t=time()
+ local timeformat=format("%%s%s",os.timezone())
+ local dateformat="%Y-%m-%d %H:%M:%S"
+ local lasttime=nil
+ local lastdate=nil
+ function os.fulltime(t,default)
+  t=t and tonumber(t) or 0
+  if t>0 then
+  elseif default then
+   return default
+  else
+   t=time()
+  end
+  if t~=lasttime then
+   lasttime=t
+   lastdate=format(timeformat,date(dateformat))
+  end
+  return lastdate
  end
- if t~=lasttime then
-  lasttime=t
-  lastdate=format(timeformat,date(dateformat))
+ local dateformat="%Y-%m-%d %H:%M:%S"
+ local lasttime=nil
+ local lastdate=nil
+ function os.localtime(t,default)
+  t=t and tonumber(t) or 0
+  if t>0 then
+  elseif default then
+   return default
+  else
+   t=time()
+  end
+  if t~=lasttime then
+   lasttime=t
+   lastdate=date(dateformat,t)
+  end
+  return lastdate
  end
- return lastdate
-end
-local dateformat="%Y-%m-%d %H:%M:%S"
-local lasttime=nil
-local lastdate=nil
-function os.localtime(t,default)
- t=t and tonumber(t) or 0
- if t>0 then
- elseif default then
-  return default
- else
-  t=time()
+ function os.converttime(t,default)
+  local t=tonumber(t)
+  if t and t>0 then
+   return date(dateformat,t)
+  else
+   return default or "-"
+  end
  end
- if t~=lasttime then
-  lasttime=t
-  lastdate=date(dateformat,t)
+ function os.today()
+  return date("!*t")
  end
- return lastdate
-end
-function os.converttime(t,default)
- local t=tonumber(t)
- if t and t>0 then
-  return date(dateformat,t)
- else
-  return default or "-"
+ function os.now()
+  return date("!%Y-%m-%d %H:%M:%S")
  end
 end
-local memory={}
-local function which(filename)
- local fullname=memory[filename]
- if fullname==nil then
-  local suffix=file.suffix(filename)
-  local suffixes=suffix=="" and os.binsuffixes or { suffix }
-  for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
-   local df=file.join(directory,filename)
-   for i=1,#suffixes do
-    local dfs=file.addsuffix(df,suffixes[i])
-    if io.exists(dfs) then
-     fullname=dfs
-     break
+do
+ local cache={}
+ local function which(filename)
+  local fullname=cache[filename]
+  if fullname==nil then
+   local suffix=file.suffix(filename)
+   local suffixes=suffix=="" and os.binsuffixes or { suffix }
+   for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+    local df=file.join(directory,filename)
+    for i=1,#suffixes do
+     local dfs=file.addsuffix(df,suffixes[i])
+     if io.exists(dfs) then
+      fullname=dfs
+      break
+     end
     end
    end
+   if not fullname then
+    fullname=false
+   end
+   cache[filename]=fullname
   end
-  if not fullname then
-   fullname=false
-  end
-  memory[filename]=fullname
+  return fullname
  end
- return fullname
+ os.which=which
+ os.where=which
 end
-os.which=which
-os.where=which
-function os.today()
- return date("!*t") 
-end
-function os.now()
- return date("!%Y-%m-%d %H:%M:%S") 
-end
 if not os.sleep then
  local socket=socket
  function os.sleep(n)
@@ -4228,65 +4226,69 @@
   socket.sleep(n)
  end
 end
-local function isleapyear(year)
- return (year%4==0) and (year%100~=0 or year%400==0)
-end
-os.isleapyear=isleapyear
-local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
-local function nofdays(year,month,day)
- if not month then
-  return isleapyear(year) and 365 or 364
- elseif not day then
-  return month==2 and isleapyear(year) and 29 or days[month]
- else
-  for i=1,month-1 do
-   day=day+days[i]
+do
+ local function isleapyear(year)
+  return (year%4==0) and (year%100~=0 or year%400==0)
+ end
+ os.isleapyear=isleapyear
+ local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
+ local function nofdays(year,month,day)
+  if not month then
+   return isleapyear(year) and 365 or 364
+  elseif not day then
+   return month==2 and isleapyear(year) and 29 or days[month]
+  else
+   for i=1,month-1 do
+    day=day+days[i]
+   end
+   if month>2 and isleapyear(year) then
+    day=day+1
+   end
+   return day
   end
-  if month>2 and isleapyear(year) then
-   day=day+1
-  end
-  return day
  end
-end
-os.nofdays=nofdays
-function os.weekday(day,month,year)
- return date("%w",time { year=year,month=month,day=day })+1
-end
-function os.validdate(year,month,day)
- if month<1 then
-  month=1
- elseif month>12 then
-  month=12
+ os.nofdays=nofdays
+ function os.weekday(day,month,year)
+  return date("%w",time { year=year,month=month,day=day })+1
  end
- if day<1 then
-  day=1
- else
-  local max=nofdays(year,month)
-  if day>max then
-   day=max
+ function os.validdate(year,month,day)
+  if month<1 then
+   month=1
+  elseif month>12 then
+   month=12
   end
+  if day<1 then
+   day=1
+  else
+   local max=nofdays(year,month)
+   if day>max then
+    day=max
+   end
+  end
+  return year,month,day
  end
- return year,month,day
-end
-function os.date(fmt,...)
- if not fmt then
-  fmt="%Y-%m-%d %H:%M"
+ function os.date(fmt,...)
+  if not fmt then
+   fmt="%Y-%m-%d %H:%M"
+  end
+  return date(fmt,...)
  end
- return date(fmt,...)
 end
-local osexit=os.exit
-local exitcode=nil
-function os.setexitcode(code)
- exitcode=code
-end
-function os.exit(c)
- if exitcode~=nil then
-  return osexit(exitcode)
+do
+ local osexit=os.exit
+ local exitcode=nil
+ function os.setexitcode(code)
+  exitcode=code
  end
- if c~=nil then
-  return osexit(c)
+ function os.exit(c)
+  if exitcode~=nil then
+   return osexit(exitcode)
+  end
+  if c~=nil then
+   return osexit(c)
+  end
+  return osexit()
  end
- return osexit()
 end
 
 
@@ -4296,7 +4298,7 @@
 
 package.loaded["l-file"] = package.loaded["l-file"] or true
 
--- original size: 22175, stripped down to: 10302
+-- original size: 22186, stripped down to: 10313
 
 if not modules then modules={} end modules ['l-file']={
  version=1.001,
@@ -4552,7 +4554,7 @@
  if not two then
   return one=="" and one or lpegmatch(reslasher,one)
  end
- if one=="" then
+ if not one or one=="" then
   return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
  end
  if lpegmatch(isnetwork,one) then
@@ -4714,7 +4716,7 @@
 
 package.loaded["l-gzip"] = package.loaded["l-gzip"] or true
 
--- original size: 5115, stripped down to: 1699
+-- original size: 268, stripped down to: 216
 
 if not modules then modules={} end modules ['l-gzip']={
  version=1.001,
@@ -4722,76 +4724,6 @@
  copyright="PRAGMA ADE / ConTeXt Development Team",
  license="see context related readme files"
 }
-gzip=gzip or {} 
-if not zlib then
- zlib=xzip 
-elseif not xzip then
- xzip=zlib
-end
-if zlib then
- local suffix=file.suffix
- local suffixes=file.suffixes
- local find=string.find
- local openfile=io.open
- local gzipwindow=15+16 
- local gziplevel=3
- local identifier="^\x1F\x8B\x08"
- local compress=zlib.compress
- local decompress=zlib.decompress
- function gzip.load(filename)
-  local f=openfile(filename,"rb")
-  if not f then
-  else
-   local data=f:read("*all")
-   f:close()
-   if data and data~="" then
-    if suffix(filename)=="gz" then
-     data=decompress(data,gzipwindow)
-    end
-    return data
-   end
-  end
- end
- function gzip.save(filename,data,level)
-  if suffix(filename)~="gz" then
-   filename=filename..".gz"
-  end
-  local f=openfile(filename,"wb")
-  if f then
-   data=compress(data or "",level or gziplevel,nil,gzipwindow)
-   f:write(data)
-   f:close()
-   return #data
-  end
- end
- function gzip.suffix(filename)
-  local suffix,extra=suffixes(filename)
-  local gzipped=extra=="gz"
-  return suffix,gzipped
- end
- function gzip.compressed(s)
-  return s and find(s,identifier)
- end
- function gzip.compress(s,level)
-  if s and not find(s,identifier) then 
-   if not level then
-    level=gziplevel
-   elseif level<=0 then
-    return s
-   elseif level>9 then
-    level=9
-   end
-   return compress(s,level or gziplevel,nil,gzipwindow) or s
-  end
- end
- function gzip.decompress(s)
-  if s and find(s,identifier) then
-   return decompress(s,gzipwindow)
-  else
-   return s
-  end
- end
-end
 
 
 end -- of closure
@@ -4926,7 +4858,7 @@
 
 package.loaded["l-url"] = package.loaded["l-url"] or true
 
--- original size: 14755, stripped down to: 6981
+-- original size: 14713, stripped down to: 6981
 
 if not modules then modules={} end modules ['l-url']={
  version=1.001,
@@ -5190,7 +5122,7 @@
 
 package.loaded["l-dir"] = package.loaded["l-dir"] or true
 
--- original size: 18253, stripped down to: 10816
+-- original size: 18217, stripped down to: 10792
 
 if not modules then modules={} end modules ['l-dir']={
  version=1.001,
@@ -5380,15 +5312,15 @@
 if onwindows then 
  local slash=S("/\\")/"/"
  pattern={
-  [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
-  [2]=Cs(((1-S("*?/\\"))^0*slash)^0),
-  [3]=Cs(P(1)^0)
+  (Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
+  Cs(((1-S("*?/\\"))^0*slash)^0),
+  Cs(P(1)^0)
  }
 else
  pattern={
-  [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
-  [2]=C(((1-S("*?/"))^0*P("/"))^0),
-  [3]=C(P(1)^0)
+  (C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
+  C(((1-S("*?/"))^0*P("/"))^0),
+  C(P(1)^0)
  }
 end
 local filter=Cs ((
@@ -6509,7 +6441,7 @@
 
 package.loaded["l-math"] = package.loaded["l-math"] or true
 
--- original size: 2555, stripped down to: 1831
+-- original size: 2679, stripped down to: 1909
 
 if not modules then modules={} end modules ['l-math']={
  version=1.001,
@@ -6522,8 +6454,14 @@
  math.ceiling=math.ceil
 end
 if not math.round then
- local floor=math.floor
- function math.round(x) return floor(x+0.5) end
+ if xmath then
+  math.round=xmath.round
+ else
+  local floor=math.floor
+  function math.round(x)
+   return x<0 and -floor(-x+0.5) or floor(x+0.5)
+  end
+ end
 end
 if not math.div then
  local floor=math.floor
@@ -6593,7 +6531,7 @@
 end
 if not math.ult then
  local floor=math.floor
- function math.tointeger(m,n)
+ function math.ult(m,n)
   return floor(m)<floor(n) 
  end
 end
@@ -6605,7 +6543,7 @@
 
 package.loaded["util-str"] = package.loaded["util-str"] or true
 
--- original size: 45129, stripped down to: 23525
+-- original size: 46322, stripped down to: 24128
 
 if not modules then modules={} end modules ['util-str']={
  version=1.001,
@@ -6617,12 +6555,13 @@
 utilities=utilities or {}
 utilities.strings=utilities.strings or {}
 local strings=utilities.strings
-local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
+local format,gsub,rep,sub,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
 local load,dump=load,string.dump
 local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
 local unpack,concat=table.unpack,table.concat
 local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc
 local patterns,lpegmatch=lpeg.patterns,lpeg.match
+local tsplitat=lpeg.tsplitat
 local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
 local loadstripped=function(str,shortcuts)
  if shortcuts then
@@ -6976,6 +6915,14 @@
 function string.escapedquotes(s)
  return lpegmatch(pattern,s)
 end
+local pattern=(1-P("\\"))^1;pattern=Cs (
+ pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
+)
+patterns.unescapedquotes=pattern
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
 local preamble=""
 local environment={
  global=global or _G,
@@ -7511,7 +7458,6 @@
  return f_16_16(n/65536.0)
 end
 if not string.explode then
- local tsplitat=lpeg.tsplitat
  local p_utf=patterns.utf8character
  local p_check=C(p_utf)*(P("+")*Cc(true))^0
  local p_split=Ct(C(p_utf)^0)
@@ -7531,6 +7477,20 @@
   end
  end
 end
+do
+ local p_whitespace=patterns.whitespace^1
+ local cache=setmetatable({},{ __index=function(t,k)
+  local p=tsplitat(p_whitespace*P(k)*p_whitespace)
+  local v=function(s)
+   return lpegmatch(p,s)
+  end
+  t[k]=v
+  return v
+ end })
+ function string.wordsplitter(s)
+  return cache[s]
+ end
+end
 
 
 end -- of closure
@@ -7539,7 +7499,7 @@
 
 package.loaded["util-tab"] = package.loaded["util-tab"] or true
 
--- original size: 32815, stripped down to: 18257
+-- original size: 34148, stripped down to: 18419
 
 if not modules then modules={} end modules ['util-tab']={
  version=1.001,
@@ -7866,9 +7826,6 @@
   return concat(fastserialize(t,true))
  end
 else
- local f_v=formatters["[%q]=%q,"]
- local f_t=formatters["[%q]="]
- local f_q=formatters["%q,"]
  function table.fastserialize(t,prefix) 
   local r={ type(prefix)=="string" and prefix or "return" }
   local m=1
@@ -7880,7 +7837,7 @@
     local v=t[0]
     if v then
      m=m+1
-     r[m]="[0]='"
+     r[m]="[0]="
      if type(v)=="table" then
       fastserialize(v)
      else
@@ -8277,6 +8234,21 @@
   return function() end
  end
 end
+function combine(target,source)
+ if target then
+  for k,v in next,source do
+   if type(v)=="table" then
+      target[k]=combine(target[k],source[k])
+   else
+      target[k]=v
+   end
+  end
+  return target
+ else
+  return source
+ end
+end
+table.combine=combine
 
 
 end -- of closure
@@ -8285,7 +8257,7 @@
 
 package.loaded["util-fil"] = package.loaded["util-fil"] or true
 
--- original size: 11552, stripped down to: 9023
+-- original size: 11474, stripped down to: 8973
 
 if not modules then modules={} end modules ['util-fil']={
  version=1.001,
@@ -8452,20 +8424,20 @@
  end
 end
 function files.readfixed2(f)
- local a,b=byte(f:read(2),1,2)
- if a>=0x80 then
-  tonumber((a-0x100).."."..b)
- else
-  tonumber((a    ).."."..b)
+ local n1,n2=byte(f:read(2),1,2)
+ if n1>=0x80 then
+  n1=n1-0x100
  end
+ return n1+n2/0xFF
 end
 function files.readfixed4(f)
  local a,b,c,d=byte(f:read(4),1,4)
- if a>=0x80 then
-  tonumber((0x100*a+b-0x10000).."."..(0x100*c+d))
- else
-  tonumber((0x100*a+b    ).."."..(0x100*c+d))
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
  end
+ return n1+n2/0xFFFF
 end
 if bit32 then
  local extract=bit32.extract
@@ -8654,7 +8626,7 @@
 
 package.loaded["util-sac"] = package.loaded["util-sac"] or true
 
--- original size: 12968, stripped down to: 9523
+-- original size: 14071, stripped down to: 10417
 
 if not modules then modules={} end modules ['util-sac']={
  version=1.001,
@@ -8881,12 +8853,11 @@
  local i=f[2]
  local j=i+1
  f[2]=j+1
- local a,b=byte(f[1],i,j)
- if a>=0x80 then
-  return tonumber((a-0x100).."."..b) or 0
- else
-  return tonumber((a  ).."."..b) or 0
+ local n1,n2=byte(f[1],i,j)
+ if n1>=0x80 then
+  n1=n1-0x100
  end
+ return n1+n2/0xFF
 end
 function streams.readfixed4(f)
  local i=f[2]
@@ -8893,11 +8864,12 @@
  local j=i+3
  f[2]=j+1
  local a,b,c,d=byte(f[1],i,j)
- if a>=0x80 then
-  return tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) or 0
- else
-  return tonumber((0x100*a+b    ).."."..(0x100*c+d)) or 0
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+  n1=n1-0x10000
  end
+ return n1+n2/0xFFFF
 end
 if bit32 then
  local extract=bit32.extract
@@ -8986,10 +8958,10 @@
   f[2]=i+4
   return readfixed4(f[1],i)
  end
- function streams.read2dot4(f)
+ function streams.read2dot14(f)
   local i=f[2]
   f[2]=i+2
-  return read2dot4(f[1],i)
+  return read2dot14(f[1],i)
  end
  function streams.readbytes(f,n)
   local i=f[2]
@@ -9095,10 +9067,10 @@
   function io.newreader(str,method)
    local f,m
    if method=="string" then
-    f=openstring(str)
+    f=openstring(str,true)
     m=streams
    elseif method=="stream" then
-    f=openstream(str)
+    f=openstream(str,true)
     m=streams
    else
     f=openfile(str,"rb")
@@ -9129,6 +9101,33 @@
   end
  end
 end
+if bit32 and not streams.tocardinal1 then
+ local extract=bit32.extract
+ local char=string.char
+    streams.tocardinal1=char
+ function streams.tocardinal2(n)   return char(extract(8,8),extract(0,8)) end
+ function streams.tocardinal3(n)   return char(extract(16,8),extract(8,8),extract(0,8)) end
+ function streams.tocardinal4(n)   return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end
+    streams.tocardinal1le=char
+ function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end
+ function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end
+ function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end
+end
+if not streams.readcstring then
+ local readchar=streams.readchar
+ local concat=table.concat
+ function streams.readcstring(f)
+  local t={}
+  while true do
+   local c=readchar(f)
+   if c and c~="\0" then
+    t[#t+1]=c
+   else
+    return concat(t)
+   end
+  end
+ end
+end
 
 
 end -- of closure
@@ -9308,7 +9307,7 @@
 
 package.loaded["util-prs"] = package.loaded["util-prs"] or true
 
--- original size: 24683, stripped down to: 16431
+-- original size: 25542, stripped down to: 16783
 
 if not modules then modules={} end modules ['util-prs']={
  version=1.001,
@@ -9357,8 +9356,8 @@
 local nobracket=1-(lbracket+rbracket)
 local escape,left,right=P("\\"),P('{'),P('}')
 lpegpatterns.balanced=P {
- [1]=((escape*(left+right))+(1-(left+right))+V(2))^0,
- [2]=left*V(1)*right
+ ((escape*(left+right))+(1-(left+right))+V(2))^0,
+ left*V(1)*right
 }
 local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace }
 local nestedparents=P { lparent*(noparent+V(1))^0*rparent }
@@ -9366,11 +9365,12 @@
 local spaces=space^0
 local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/""))
 local content=(1-endofstring)^0
-lpegpatterns.nestedbraces=nestedbraces  
-lpegpatterns.nestedparents=nestedparents 
-lpegpatterns.nested=nestedbraces  
-lpegpatterns.argument=argument   
-lpegpatterns.content=content    
+lpegpatterns.nestedbraces=nestedbraces   
+lpegpatterns.nestedparents=nestedparents  
+lpegpatterns.nestedbrackets=nestedbrackets 
+lpegpatterns.nested=nestedbraces   
+lpegpatterns.argument=argument    
+lpegpatterns.content=content  
 local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0)
 local key=C((1-equal-comma)^1)
 local pattern_a=(space+comma)^0*(key*equal*value+key*C(""))
@@ -9776,15 +9776,24 @@
   action(first)
  end
 end
-local cardinal=lpegpatterns.cardinal/tonumber
+local cardinal=(lpegpatterns.hexadecimal+lpegpatterns.cardinal)/tonumber
 local spacers=lpegpatterns.spacer^0
 local endofstring=lpegpatterns.endofstring
 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1
 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring 
 function parsers.stepper(str,n,action)
+ local ts=type(str)
  if type(n)=="function" then
-  lpegmatch(stepper,str,1,false,n or print)
- else
+  if ts=="number" then
+   n(str)
+  elseif ts=="table" then
+   for i=1,#str do
+    n(str[i])
+   end
+  else
+   lpegmatch(stepper,str,1,false,n or print)
+  end
+ elseif ts=="string" then
   lpegmatch(stepper,str,1,n,action or print)
  end
 end
@@ -9802,7 +9811,7 @@
 local spaces=lpegpatterns.space^0
 local dummy=function() end
 setmetatableindex(cache,function(t,k)
- local separator=P(k)
+ local separator=S(k) 
  local value=(1-separator)^0
  local pattern=spaces*C(value)*separator^0*Cp()
  t[k]=pattern
@@ -9882,8 +9891,11 @@
 local pattern=Cf(Ct("")*(
   (Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("day")*cardinal)
   )+(Cg(Cc("day")*cardinal)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+  )+(Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)
+  )+(Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
   )
- )*P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1
+ )*(
+   P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1+P(-1) )
 ,rawset)
 lpegpatterns.splittime=pattern
 function parsers.totime(str)
@@ -12809,7 +12821,7 @@
 
 package.loaded["trac-set"] = package.loaded["trac-set"] or true
 
--- original size: 13901, stripped down to: 9175
+-- original size: 14568, stripped down to: 9644
 
 if not modules then modules={} end modules ['trac-set']={ 
  version=1.001,
@@ -12952,6 +12964,9 @@
    end
    local s=fnc 
    fnc=function(value) set(t,s,value) end
+  elseif typ=="table" then
+   functions.values=fnc
+   fnc=nil
   elseif typ~="function" then
    fnc=nil
   end
@@ -12996,35 +13011,42 @@
  end
  return user,system
 end
-local function show_setter(t)
+local function show_setter(t,pattern)
  local list=list_setter(t)
  t.report()
  for k=1,#list do
   local name=list[k]
-  local functions=t.data[name]
-  if functions then
-   local value=functions.value
-   local default=functions.default
-   local modules=#functions
-   if default==nil then
-    default="unset"
-   elseif type(default)=="table" then
-    default=concat(default,"|")
-   else
-    default=tostring(default)
+  if not pattern or find(name,pattern) then
+   local functions=t.data[name]
+   if functions then
+    local value=functions.value
+    local default=functions.default
+    local values=functions.values
+    local modules=#functions
+    if default==nil then
+     default="unset"
+    elseif type(default)=="table" then
+     default=concat(default,"|")
+    else
+     default=tostring(default)
+    end
+    if value==nil then
+     value="unset"
+    elseif type(value)=="table" then
+     value=concat(value,"|")
+    else
+     value=tostring(value)
+    end
+    t.report(name)
+    t.report("    modules : %i",modules)
+    t.report("    default : %s",default)
+    t.report("    value   : %s",value)
+   if values then
+    local v={} for i=1,#values do v[i]=tostring(values[i]) end
+    t.report("    values  : % t",v)
    end
-   if value==nil then
-    value="unset"
-   elseif type(value)=="table" then
-    value=concat(value,"|")
-   else
-    value=tostring(value)
+    t.report()
    end
-   t.report(name)
-   t.report("    modules : %i",modules)
-   t.report("    default : %s",default)
-   t.report("    value   : %s",value)
-   t.report()
   end
  end
 end
@@ -13043,6 +13065,10 @@
  local d=setter.data[name]
  return d and (d.value or d.default)
 end
+local function setter_values(setter,name)
+ local d=setter.data[name]
+ return d and d.values
+end
 local function new_setter(name) 
  local setter 
  setter={
@@ -13057,6 +13083,7 @@
   show=function(...)   show_setter (setter,...) end,
   default=function(...)  return setter_default (setter,...) end,
   value=function(...)  return setter_value   (setter,...) end,
+  values=function(...)  return setter_values  (setter,...) end,
  }
  data[name]=setter
  return setter
@@ -13128,7 +13155,7 @@
 end
 if texconfig then
  local function set(k,v)
-  v=tonumber(v)
+  local v=tonumber(v)
   if v then
    texconfig[k]=v
   end
@@ -14231,7 +14258,7 @@
 
 package.loaded["util-deb"] = package.loaded["util-deb"] or true
 
--- original size: 10136, stripped down to: 6832
+-- original size: 10593, stripped down to: 7102
 
 if not modules then modules={} end modules ['util-deb']={
  version=1.001,
@@ -14525,6 +14552,22 @@
  end
 end
 debugger.showtraceback=showtraceback
+if luac then
+ local show,dump=luac.print,string.dump
+ function luac.inspect(v)
+  if type(v)=="function" then
+   local ok,str=xpcall(dump,function() end,v)
+   if ok then
+    v=str
+   end
+  end
+  if type(v)=="string" then
+   show(v,true)
+  else
+   print(v)
+  end
+ end
+end
 
 
 end -- of closure
@@ -14686,7 +14729,7 @@
 
 package.loaded["util-sbx"] = package.loaded["util-sbx"] or true
 
--- original size: 21084, stripped down to: 13214
+-- original size: 21145, stripped down to: 13271
 
 if not modules then modules={} end modules ['util-sbx']={
  version=1.001,
@@ -14939,7 +14982,7 @@
     if chktype=="verbose" then
     else
      local checker=validators[chktype]
-     if checker then
+     if checker and type(value)=="string" then
       value=checker(unquoted(value),strict)
       if value then
        variables[variable]=optionalquoted(value)
@@ -14958,7 +15001,7 @@
     if not value or value=="" then
      local chktype=checkers[variable]
      if chktype=="verbose" then
-     else
+     elseif type(default)=="string" then
       local checker=validators[chktype]
       if checker then
        default=checker(unquoted(default),strict)
@@ -15759,7 +15802,7 @@
 
 package.loaded["util-zip"] = package.loaded["util-zip"] or true
 
--- original size: 19496, stripped down to: 10858
+-- original size: 23730, stripped down to: 14293
 
 if not modules then modules={} end modules ['util-zip']={
  version=1.001,
@@ -15768,12 +15811,20 @@
  license="see context related readme files"
 }
 local type,tostring,tonumber=type,tostring,tonumber
-local sort=table.sort
+local sort,concat=table.sort,table.concat
 local find,format,sub,gsub=string.find,string.format,string.sub,string.gsub
 local osdate,ostime,osclock=os.date,os.time,os.clock
 local ioopen=io.open
 local loaddata,savedata=io.loaddata,io.savedata
 local filejoin,isdir,dirname,mkdirs=file.join,lfs.isdir,file.dirname,dir.mkdirs
+local suffix,suffixes=file.suffix,file.suffixes
+local openfile=io.open
+gzip=gzip or {} 
+if not zlib then
+ zlib=xzip 
+elseif not xzip then
+ xzip=zlib
+end
 local files=utilities.files
 local openfile=files.open
 local closefile=files.close
@@ -15785,19 +15836,16 @@
 local band=bit32.band
 local rshift=bit32.rshift
 local lshift=bit32.lshift
-local decompress,expandsize,calculatecrc
- local zlibdecompress=zlib.decompress
- local zlibexpandsize=zlib.expandsize
- local zlibchecksum=zlib.crc32
- decompress=function(source)
-  return zlibdecompress(source,-15) 
- end
- expandsize=zlibexpandsize and function(source,targetsize)
-  return zlibexpandsize(source,targetsize,-15) 
- end or decompress
- calculatecrc=function(buffer,initial)
-  return zlibchecksum(initial or 0,buffer)
- end
+local zlibdecompress=zlib.decompress
+local zlibdecompresssize=zlib.decompresssize
+local zlibchecksum=zlib.crc32
+if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+ local cs=zlibchecksum
+ zlibchecksum=function(str,n) return cs(n or 0,str) end
+end
+local decompress=function(source)   return zlibdecompress (source,-15)   end 
+local decompresssize=function(source,targetsize) return zlibdecompresssize(source,targetsize,-15) end 
+local calculatecrc=function(buffer,initial) return zlibchecksum   (initial or 0,buffer)   end
 local zipfiles={}
 utilities.zipfiles=zipfiles
 local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist  do
@@ -15922,8 +15970,8 @@
     setposition(handle,position)
     local result=readstring(handle,compressed)
     if data.method==8 then
-     if expandsize then
-      result=expandsize(result,data.uncompressed)
+     if decompresssize then
+      result=decompresssize(result,data.uncompressed)
      else
       result=decompress(result)
      end
@@ -16187,7 +16235,127 @@
  zipfiles.zipdir=zipdir
  zipfiles.unzipdir=unzipdir
 end
-zipfiles.gunzipfile=gzip.load
+local pattern="^\x1F\x8B\x08"
+local gziplevel=3
+function gzip.suffix(filename)
+ local suffix,extra=suffixes(filename)
+ local gzipped=extra=="gz"
+ return suffix,gzipped
+end
+function gzip.compressed(s)
+ return s and find(s,pattern)
+end
+local getdecompressed
+local putcompressed
+if gzip.compress then
+ local gzipwindow=15+16 
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ getdecompressed=function(str)
+  return decompress(str,gzipwindow) 
+ end
+ putcompressed=function(str,level)
+  return compress(str,level or gziplevel,nil,gzipwindow)
+ end
+else
+ local gzipwindow=-15 
+ local identifier="\x1F\x8B"
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ local zlibchecksum=zlib.crc32
+ if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+  local cs=zlibchecksum
+  zlibchecksum=function(str,n) return cs(n or 0,str) end
+ end
+ local streams=utilities.streams
+ local openstream=streams.openstring
+ local closestream=streams.close
+ local getposition=streams.getposition
+ local readbyte=streams.readbyte
+ local readcardinal4=streams.readcardinal4le
+ local readcardinal2=streams.readcardinal2le
+ local readstring=streams.readstring
+ local readcstring=streams.readcstring
+ local skipbytes=streams.skip
+ local tocardinal1=streams.tocardinal1
+ local tocardinal4=streams.tocardinal4le
+ getdecompressed=function(str)
+  local s=openstream(str)
+  local identifier=readstring(s,2)
+  local method=readbyte(s,1)
+  local flags=readbyte(s,1)
+  local timestamp=readcardinal4(s)
+  local compression=readbyte(s,1)
+  local operating=readbyte(s,1)
+  local isjusttext=band(flags,0x01)~=0 and true    or false
+  local extrasize=band(flags,0x04)~=0 and readcardinal2(s) or 0
+  local filename=band(flags,0x08)~=0 and readcstring(s)   or ""
+  local comment=band(flags,0x10)~=0 and readcstring(s)   or ""
+  local checksum=band(flags,0x02)~=0 and readcardinal2(s) or 0
+  local compressed=readstring(s,#str)
+  local data=decompress(compressed,gzipwindow) 
+  return data
+ end
+ putcompressed=function(str,level,originalname)
+  return concat {
+   identifier,
+   tocardinal1(0x08),
+   tocardinal1(0x08),
+   tocardinal4(os.time()),
+   tocardinal1(0x02),
+   tocardinal1(0xFF),
+   (originalname or "unknownname").."\0",
+   compress(str,level,nil,gzipwindow),
+   tocardinal4(zlibchecksum(str)),
+   tocardinal4(#str),
+  }
+ end
+end
+function gzip.load(filename)
+ local f=openfile(filename,"rb")
+ if not f then
+ else
+  local data=f:read("*all")
+  f:close()
+  if data and data~="" then
+   if suffix(filename)=="gz" then
+    data=getdecompressed(data)
+   end
+   return data
+  end
+ end
+end
+function gzip.save(filename,data,level,originalname)
+ if suffix(filename)~="gz" then
+  filename=filename..".gz"
+ end
+ local f=openfile(filename,"wb")
+ if f then
+  data=putcompressed(data or "",level or gziplevel,originalname)
+  f:write(data)
+  f:close()
+  return #data
+ end
+end
+function gzip.compress(s,level)
+ if s and not find(s,pattern) then
+  if not level then
+   level=gziplevel
+  elseif level<=0 then
+   return s
+  elseif level>9 then
+   level=9
+  end
+  return putcompressed(s,level or gziplevel) or s
+ end
+end
+function gzip.decompress(s)
+ if s and find(s,pattern) then
+  return getdecompressed(s)
+ else
+  return s
+ end
+end
 
 
 end -- of closure
@@ -16196,7 +16364,7 @@
 
 package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true
 
--- original size: 61808, stripped down to: 36227
+-- original size: 62810, stripped down to: 36225
 
 if not modules then modules={} end modules ['lxml-tab']={
  version=1.001,
@@ -16430,8 +16598,7 @@
 local function add_text(text)
  if text=="" then
   return
- end
- if cleanup then
+ elseif cleanup then
   if nt>0 then
    local s=dt[nt]
    if type(s)=="string" then
@@ -17001,7 +17168,7 @@
  local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0
  local parsedtext=text_parsed   
  local unparsedtext=text_unparsed/add_text
- local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } 
+ local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" }
  local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty
  local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin
  local endelement=(spacing*open*slash*name*optionalspace*close)/add_end
@@ -17043,8 +17210,7 @@
  local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset
  local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset
  local simpledoctype=(anything-close)^1 
- local somedoctype=C((somespace*(
-publicentityfile+publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0)
+ local somedoctype=C((somespace*(publicentityfile+publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0)
  local instruction=(spacing*begininstruction*someinstruction*endinstruction)/function(...) add_special("@pi@",...) end
  local comment=(spacing*begincomment*somecomment*endcomment )/function(...) add_special("@cm@",...) end
  local cdata=(spacing*begincdata*somecdata*endcdata   )/function(...) add_special("@cd@",...) end
@@ -17654,7 +17820,7 @@
     local tg=d.tg
     if tg=="@cd@" then
      return "cdata"
-    elseif tg=="@cm" then
+    elseif tg=="@cm@" then
      return "comment"
     elseif tg=="@pi@" then
      return "instruction"
@@ -17679,7 +17845,7 @@
 
 package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true
 
--- original size: 54667, stripped down to: 31258
+-- original size: 54733, stripped down to: 31258
 
 if not modules then modules={} end modules ['lxml-lpt']={
  version=1.001,
@@ -18999,7 +19165,7 @@
 
 package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true
 
--- original size: 33708, stripped down to: 20953
+-- original size: 34661, stripped down to: 21511
 
 if not modules then modules={} end modules ['lxml-aux']={
  version=1.001,
@@ -19265,6 +19431,36 @@
   end
  end
 end
+function xml.expand(root,pattern,whatever)
+ local collected=root and xmlapplylpath(root,pattern)
+ if collected then
+  for c=1,#collected do
+   local e=collected[c]
+   local p=e.__p__
+   if p then
+    if trace_manipulations then
+     report('expanding',pattern,c,e)
+    end
+    local d=p.dt
+    local n=e.ni
+    local t=whatever(e,p)
+    if t then
+     if type(t)=="table" then
+      t=xmlcopy(t)
+      d[n]=t[1]
+      for i=2,#t do
+       n=n+1
+       insert(d,n,t[i])
+      end
+     else
+      d[n]=t
+     end
+     redo_ni(d) 
+    end
+   end
+  end
+ end
+end
 local function wrap(e,wrapper)
  local t={
   rn=e.rn,
@@ -21199,7 +21395,7 @@
 
 package.loaded["data-env"] = package.loaded["data-env"] or true
 
--- original size: 9501, stripped down to: 6411
+-- original size: 9501, stripped down to: 6413
 
 if not modules then modules={} end modules ['data-env']={
  version=1.001,
@@ -21291,8 +21487,8 @@
    names={ "mp" },
    variable='MPINPUTS',
    suffixes=CONTEXTLMTXMODE>0
-    and { 'mp','mpxl','mpvi','mpiv','mpii' }
-    or  { 'mp','mpvi','mpiv','mpii' },
+    and { 'mpxl','mpvi','mpiv','mpii','mp' }
+    or  {   'mpvi','mpiv','mpii','mp' },
    usertype=true,
   },
   tex={
@@ -21486,7 +21682,7 @@
 
 package.loaded["data-tmp"] = package.loaded["data-tmp"] or true
 
--- original size: 16409, stripped down to: 11591
+-- original size: 16456, stripped down to: 11636
 
 if not modules then modules={} end modules ['data-tmp']={
  version=1.100,
@@ -21532,7 +21728,7 @@
 local usedreadables={}
 local compilelua=luautilities.compile
 local luasuffixes=luautilities.suffixes
-caches.base=caches.base or "luatex-cache"  
+caches.base=caches.base or (LUATEXENGINE and LUATEXENGINE.."-cache") or "luatex-cache"  
 caches.more=caches.more or "context"    
 caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" }
 local direct_cache=false 
@@ -23686,7 +23882,7 @@
 
 package.loaded["data-pre"] = package.loaded["data-pre"] or true
 
--- original size: 5088, stripped down to: 3144
+-- original size: 5872, stripped down to: 3691
 
 if not modules then modules={} end modules ['data-pre']={
  version=1.001,
@@ -23695,6 +23891,7 @@
  copyright="PRAGMA ADE / ConTeXt Development Team",
  license="see context related readme files"
 }
+local ipairs=ipairs
 local insert,remove=table.insert,table.remove
 local resolvers=resolvers
 local prefixes=resolvers.prefixes
@@ -23706,6 +23903,7 @@
 local dirname=file.dirname
 local joinpath=file.join
 local isfile=lfs.isfile
+local isdir=lfs.isdir
 prefixes.environment=function(str)
  return cleanpath(expansion(str))
 end
@@ -23766,6 +23964,30 @@
  local pth=getenv('HOME')
  return cleanpath(str and joinpath(pth,str) or pth)
 end
+do
+ local tmppth
+ prefixes.temp=function(str)
+  if not tmppth then
+   for _,s in ipairs { "TMP","TEMP","TMPDIR","TEMPDIR" } do
+    tmppth=getenv(s)
+    if tmppth~="" and isdir(tmppth) then
+     break
+    end
+   end
+   if not tmppth or tmppth=="" then
+    tmppth="."
+   end
+  end
+  return cleanpath(str and joinpath(tmppth,str) or tmppth)
+ end
+ prefixes.texruns=function(str)
+  local pth=getenv('TEXRUNS')
+  if pth=="" then
+   pth=tmppth
+  end
+  return cleanpath(str and joinpath(pth,str) or pth)
+ end
+end
 prefixes.env=prefixes.environment
 prefixes.rel=prefixes.relative
 prefixes.loc=prefixes.locate
@@ -23816,7 +24038,7 @@
 
 package.loaded["data-inp"] = package.loaded["data-inp"] or true
 
--- original size: 910, stripped down to: 818
+-- original size: 1050, stripped down to: 946
 
 if not modules then modules={} end modules ['data-inp']={
  version=1.001,
@@ -23832,12 +24054,15 @@
 local finders=allocate { helpers={},notfound=function() end }
 local openers=allocate { helpers={},notfound=function() end }
 local loaders=allocate { helpers={},notfound=function() return false,nil,0 end }
+local tracers=allocate { helpers={},notfound=function() end }
 registermethod("finders",finders,"uri")
 registermethod("openers",openers,"uri")
 registermethod("loaders",loaders,"uri")
+registermethod("tracers",tracers,"uri")
 resolvers.finders=finders
 resolvers.openers=openers
 resolvers.loaders=loaders
+resolvers.tracers=tracers
 
 
 end -- of closure
@@ -23846,7 +24071,7 @@
 
 package.loaded["data-out"] = package.loaded["data-out"] or true
 
--- original size: 551, stripped down to: 470
+-- original size: 682, stripped down to: 579
 
 if not modules then modules={} end modules ['data-out']={
  version=1.001,
@@ -23860,7 +24085,10 @@
 local registermethod=resolvers.registermethod
 local savers=allocate { helpers={} }
 resolvers.savers=savers
+local cleaners=allocate { helpers={} }
+resolvers.cleaners=cleaners
 registermethod("savers",savers,"uri")
+registermethod("cleaners",cleaners,"uri")
 
 
 end -- of closure
@@ -23998,7 +24226,7 @@
 
 package.loaded["data-con"] = package.loaded["data-con"] or true
 
--- original size: 5388, stripped down to: 3685
+-- original size: 5487, stripped down to: 3757
 
 if not modules then modules={} end modules ['data-con']={
  version=1.100,
@@ -24036,7 +24264,7 @@
  end,
  __storage__=true
 }
-function containers.define(category,subcategory,version,enabled)
+function containers.define(category,subcategory,version,enabled,reload)
  if category and subcategory then
   local c=allocated[category]
   if not c then
@@ -24050,6 +24278,7 @@
     subcategory=subcategory,
     storage={},
     enabled=enabled,
+    reload=reload,
     version=version or math.pi,
     trace=false,
    }
@@ -24072,7 +24301,8 @@
 end
 function containers.read(container,name)
  local storage=container.storage
- local stored=storage[name]
+ local reload=container.reload
+ local stored=not reload and storage[name]
  if not stored and container.enabled and caches and containers.usecache then
   stored=loaddatafromcache(container.readables,name,container.writable)
   if stored and stored.cache_version==container.version then
@@ -24126,7 +24356,7 @@
 
 package.loaded["data-use"] = package.loaded["data-use"] or true
 
--- original size: 5785, stripped down to: 2905
+-- original size: 5806, stripped down to: 2925
 
 if not modules then modules={} end modules ['data-use']={
  version=1.001,
@@ -24156,7 +24386,7 @@
    functionality=LUATEXFUNCTIONALITY,
   }
   io.savedata(luvname,table.serialize(luvdata,true))
-  lua.registerfinalizer(function()
+  lua.registerinitexfinalizer(function()
    if jit then
     logs.report("format banner","%s  lua: %s jit",banner,LUAVERSION)
    else
@@ -24163,7 +24393,7 @@
     logs.report("format banner","%s  lua: %s",banner,LUAVERSION)
    end
    logs.newline()
-  end)
+  end,"show banner")
  end
 end
 function statistics.checkfmtstatus(texname)
@@ -24214,7 +24444,7 @@
 
 package.loaded["data-zip"] = package.loaded["data-zip"] or true
 
--- original size: 10725, stripped down to: 7949
+-- original size: 10805, stripped down to: 7951
 
 if not modules then modules={} end modules ['data-zip']={
  version=1.001,
@@ -24257,10 +24487,10 @@
  local openstream=streams.open
  local readstring=streams.readstring
  local streamsize=streams.size
- local metatable={
+ local metatable={ 
   close=streams.close,
   read=function(stream,n)
-   readstring(stream,n=="*a" and streamsize(stream) or n)
+   readstring(stream,n=="*a" and streamsize(stream) or n) 
   end
  }
  filehandle=function(zfile,queryname)
@@ -25287,7 +25517,7 @@
 
 package.loaded["libs-ini"] = package.loaded["libs-ini"] or true
 
--- original size: 6459, stripped down to: 4006
+-- original size: 6524, stripped down to: 4064
 
 if not modules then modules={} end modules ['libs-ini']={
  version=1.001,
@@ -25329,10 +25559,10 @@
   for i=1,#list do
    local name=list[i]
    local found=findfile(name,"lib")
-   if not found then
+   if not found or found=="" then
     found=findfile(addsuffix(name,suffix),"lib")
    end
-   if found then
+   if found and found~="" then
     if trace then
      report("library %a resolved via %a path to %a",name,"tds lib",found)
     end
@@ -25345,9 +25575,9 @@
    for i=1,#list do
     local full=joinfile(list[i],base)
     local found=isfile(full) and full
-    if found then
+    if found and found~="" then
      if trace then
-      report("library %a resolved via %a path to %a",name,"system",found)
+      report("library %a resolved via %a path to %a",full,"system",found)
      end
      return found
     end
@@ -25402,7 +25632,7 @@
     for i=1,#libnames do
      local libname=libnames[i]
      local filename=foundlibraries[libname]
-     if filename then
+     if filename and filename~="" then
       libnames[i]=filename
      else
       report("unable to locate library %a",libname)
@@ -25842,8 +26072,8 @@
 
 -- used libraries    : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.lua util-env.lua luat-env.lua util-zip.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua libs-ini.lua luat-sta.lua luat-fmt.lua
 -- skipped libraries : -
--- original bytes    : 1025947
--- stripped bytes    : 405652
+-- original bytes    : 1034927
+-- stripped bytes    : 407861
 
 -- end library merge
 
@@ -27371,6 +27601,10 @@
 
 if ok == false then ok = 1 elseif ok == true or ok == nil then ok = 0 end
 
+if lua and lua.getexitcode then
+    ok = lua.getexitcode()
+end
+
 -- os.exit(ok,true) -- true forces a cleanup in 5.2+
 
 os.exit(ok)         -- true forces a cleanup in 5.2+ but reports a wrong number then



More information about the tex-live-commits mailing list.