diff options
48 files changed, 3511 insertions, 1175 deletions
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index 2bc943210..abd80b8b4 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = { license = "see context related readme files" } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end --~ return p --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~ local c1, c2 = string.byte(s, 1, 2) +--~ return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~ local c1, c2, c3 = string.byte(s, 1, 3) +--~ return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~ local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~ return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191") -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~ + lpeg.R("\194\223") * cont / f2 +--~ + lpeg.R("\224\239") * cont * cont / f3 +--~ + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191") -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + + end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = { table.join = table.concat local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs function table.strip(tab) local lst = { } @@ -721,6 +756,8 @@ end -- -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution + local function do_serialize(root,name,depth,level,indexed) if level > 0 then depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %s,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then handle(format("%s %s,",depth,v)) else handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%s,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%s,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%s,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%s,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then --~ handle(format("%s %s=%s,",depth,key(k),v)) if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify) end end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ... for i=1,#t do local v = t[i] if type(v) == "table" then @@ -1065,6 +1103,24 @@ end table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) + if not f then + f = { } + end + for k, v in next, t do + if type(v) == "table" then + flattened(v,f) + else + f[k] = v + end + end + return f +end + +table.flattened = flattened + -- the next three may disappear function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table elseif not t then t = { } end - setmetatable(t, { __index = function(_,key) return p[key] end }) + setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ? return t end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = { license = "see context related readme files" } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil function os.resultof(command) return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default) elseif name == "macosx" then if find(architecture,"i386") then platform = "osx-intel" + elseif find(architecture,"x86_64") then + platform = "osx-64" else platform = "osx-ppc" end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default) return platform end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +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 -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str) return str end +--~ print(file.collapse_path("/a")) --~ print(file.collapse_path("a/./b/..")) --~ print(file.collapse_path("a/aa/../b/bb")) --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how) end end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } if moretolerant then pattern_b_s:match(str) else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str) end end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_b_s:match(str) return hash else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str) end end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_c_s:match(str) return next(hash) and hash else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings) sc = table.clone(self[parent]) self[class] = sc end - aux.add_settings_to_array(sc, settings) + aux.settings_to_hash(settings,sc) end -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = { -- bound to a variable, like node.new, node.copy etc (contrary to for instance -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub + debugger = debugger or { } local counters = { } local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub -- one @@ -3363,11 +3453,11 @@ end --~ print("") --~ debugger.showstats(print,3) -trackers = trackers or { } +setters = setters or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) + local data, done = t.data, t.done if type(what) == "string" then what = aux.settings_to_array(what) -- inefficient but ok end @@ -3386,28 +3476,30 @@ local function set(what,value) end end -local function reset() - for d, f in next, data do +local function reset(t) + for d, f in next, t.data do for i=1,#f do f[i](false) end end end -local function enable(what) - set(what,true) +local function enable(t,what) + set(t,what,true) end -local function disable(what) +local function disable(t,what) + local data = t.data if not what or what == "" then - done = { } - reset() + t.done = { } + reset(t) else - set(what,false) + set(t,what,false) end end -function trackers.register(what,...) +function setters.register(t,what,...) + local data = t.data what = lower(what) local w = data[what] if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...) if typ == "function" then w[#w+1] = fnc elseif typ == "string" then - w[#w+1] = function(value) set(fnc,value,nesting) end + w[#w+1] = function(value) set(t,fnc,value,nesting) end end end end -function trackers.enable(what) - local e = trackers.enable - trackers.enable, done = enable, { } - enable(string.simpleesc(what)) - trackers.enable, done = e, { } +function setters.enable(t,what) + local e = t.enable + t.enable, t.done = enable, { } + enable(t,string.simpleesc(what)) + t.enable, t.done = e, { } end -function trackers.disable(what) - local e = trackers.disable - trackers.disable, done = disable, { } - disable(string.simpleesc(what)) - trackers.disable, done = e, { } +function setters.disable(t,what) + local e = t.disable + t.disable, t.done = disable, { } + disable(t,string.simpleesc(what)) + t.disable, t.done = e, { } end -function trackers.reset() - done = { } - reset() +function setters.reset(t) + t.done = { } + reset(t) end -function trackers.list() -- pattern - local list = table.sortedkeys(data) +function setters.list(t) -- pattern + local list = table.sortedkeys(t.data) local user, system = { }, { } for l=1,#list do local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern return user, system end +function setters.show(t) + commands.writestatus("","") + for k,v in ipairs(setters.list(t)) do + commands.writestatus(t.name,v) + end + commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) + local t + t = { + data = { }, + name = name, + enable = function(...) setters.enable (t,...) end, + disable = function(...) setters.disable (t,...) end, + register = function(...) setters.register(t,...) end, + list = function(...) setters.list (t,...) end, + show = function(...) setters.show (t,...) end, + } + setters.data[name] = t + return t +end + +trackers = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) + commands.writestatus("directives","enabling: %s",concat({...}," ")) + e(...) +end + +function directives.disable(...) + commands.writestatus("directives","disabling: %s",concat({...}," ")) + d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~ if type(what) == "string" then +--~ what = aux.settings_to_array(what) -- inefficient but ok +--~ end +--~ for i=1,#what do +--~ local w = what[i] +--~ for d, f in next, data do +--~ if done[d] then +--~ -- prevent recursion due to wildcards +--~ elseif find(d,w) then +--~ done[d] = true +--~ for i=1,#f do +--~ f[i](value) +--~ end +--~ end +--~ end +--~ end +--~ end +--~ local function reset() +--~ for d, f in next, data do +--~ for i=1,#f do +--~ f[i](false) +--~ end +--~ end +--~ end +--~ local function enable(what) +--~ set(what,true) +--~ end +--~ local function disable(what) +--~ if not what or what == "" then +--~ done = { } +--~ reset() +--~ else +--~ set(what,false) +--~ end +--~ end +--~ function trackers.register(what,...) +--~ what = lower(what) +--~ local w = data[what] +--~ if not w then +--~ w = { } +--~ data[what] = w +--~ end +--~ for _, fnc in next, { ... } do +--~ local typ = type(fnc) +--~ if typ == "function" then +--~ w[#w+1] = fnc +--~ elseif typ == "string" then +--~ w[#w+1] = function(value) set(fnc,value,nesting) end +--~ end +--~ end +--~ end +--~ function trackers.enable(what) +--~ local e = trackers.enable +--~ trackers.enable, done = enable, { } +--~ enable(string.simpleesc(what)) +--~ trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~ local e = trackers.disable +--~ trackers.disable, done = disable, { } +--~ disable(string.simpleesc(what)) +--~ trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~ done = { } +--~ reset() +--~ end +--~ function trackers.list() -- pattern +--~ local list = table.sortedkeys(data) +--~ local user, system = { }, { } +--~ for l=1,#list do +--~ local what = list[l] +--~ if find(what,"^%*") then +--~ system[#system+1] = what +--~ else +--~ user[#user+1] = what +--~ end +--~ end +--~ return user, system +--~ end + end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report) end + end -- of closure do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -4703,9 +4931,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -4925,7 +5157,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -5664,8 +5904,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 344ff42c5..22abf74b1 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -992,24 +992,29 @@ local loaded = false function scripts.context.metapost() local filename = environment.files[1] or "" ---~ local tempname = "mtx-context-metapost.tex" ---~ local tempdata = string.format(template,"metafun",filename) ---~ io.savedata(tempname,tempdata) ---~ environment.files[1] = tempname ---~ environment.setargument("result",file.removesuffix(filename)) ---~ environment.setargument("once",true) ---~ scripts.context.run() if not loaded then dofile(resolvers.find_file("mlib-run.lua")) loaded = true commands = commands or { } commands.writestatus = logs.report end - local formatname = environment.arguments("format") or "metafun" + local formatname = environment.argument("format") or "metafun" if formatname == "" or type(format) == "boolean" then formatname = "metafun" end - if environment.arguments("svg") then + if environment.argument("pdf") then + local basename = file.removesuffix(filename) + local resultname = environment.argument("result") or basename + local jobname = "mtx-context-metapost" + local tempname = file.addsuffix(jobname,"tex") + io.savedata(tempname,string.format(template,"metafun",filename)) + environment.files[1] = tempname + environment.setargument("result",resultname) + environment.setargument("once",true) + scripts.context.run() + scripts.context.purge_job(jobname,true) + scripts.context.purge_job(resultname,true) + elseif environment.argument("svg") then metapost.directrun(formatname,filename,"svg") else metapost.directrun(formatname,filename,"mps") diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 0cd9a3270..67c48d0a8 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -20,23 +20,46 @@ function scripts.fonts.reload(verbose) end function scripts.fonts.names(name) + local simpleversion = 1.001 + local simplelist = { "ttf", "otf", "ttc", "dfont" } name = name or "luatex-fonts-names.lua" + fonts.names.filters.list = simplelist + fonts.names.version = simpleversion -- this number is the same as in font-dum.lua + logs.report("fontnames","generating font database for 'luatex-fonts' version %s",fonts.names.version) fonts.names.identify(true) local data = fonts.names.data if data then - data.fallback_mapping = nil + local simplemappings = { } + local simplified = { + mappings = simplemappings, + version = simpleversion, + } + local specifications = data.specifications + for _, format in ipairs(simplelist) do + for tag, index in pairs(data.mappings[format]) do + local s = specifications[index] + simplemappings[tag] = { s.rawname, s.filename, s.subfont } + end + end logs.report("fontnames","saving names in '%s'",name) - io.savedata(name,table.serialize(data,true)) + io.savedata(name,table.serialize(simplified,true)) + local data = io.loaddata(resolvers.find_file("font-dum.lua","tex")) + local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)") + if tonumber(dummy) ~= simpleversion then + logs.report("fontnames","warning: version number %s in 'font-dum' does not match database version number %s",dummy or "?",simpleversion) + end elseif lfs.isfile(name) then os.remove(name) end end -local function showfeatures(v,n,f,s,t) - logs.simple("fontname: %s",v) - logs.simple("fullname: %s",n) - logs.simple("filename: %s",f) - local features = fonts.get_features(f,t) +local function showfeatures(tag,specification) + logs.simple("mapping : %s",tag) + logs.simple("fontname: %s",specification.fontname) + logs.simple("fullname: %s",specification.fullname) + logs.simple("filename: %s",specification.filename) + -- maybe more + local features = fonts.get_features(specification.filename,specification.format) if features then for what, v in table.sortedpairs(features) do local data = features[what] @@ -61,6 +84,10 @@ local function showfeatures(v,n,f,s,t) end end end + else + logs.simple() + logs.simple("no features") + logs.simple() end logs.reportline() end @@ -74,7 +101,7 @@ local function make_pattern(pattern) -- will become helper in string if pattern == "" then pattern = ".*" else - pattern = "^" .. pattern .. "$" +--~ pattern = "^" .. pattern .. "$" end return pattern end @@ -87,53 +114,120 @@ local function reloadbase(reload) end end -function scripts.fonts.list_by_pattern(pattern,reload,all,info) - reloadbase(reload) - local t = fonts.names.list(make_pattern(pattern)) +local function subfont(sf) + if sf then + return string.format("index: % 2s", sf) + else + return "" + end +end +local function fontweight(fw) + if fw then + return string.format("conflict: %s", fw) + else + return "" + end +end + +local function list_specifications(t) if t then local s, w = table.sortedkeys(t), { 0, 0, 0 } for k,v in ipairs(s) do local entry = t[v] - local n = #v if n > w[1] then w[1] = n end - local n = #entry[2] if n > w[2] then w[2] = n end - local n = #entry[3] if n > w[3] then w[3] = n end + s[k] = { + entry.familyname or "<nofamily>", + entry.weight or "<noweight>", + entry.style or "<nostyle>", + entry.width or "<nowidth>", + entry.fontname, + entry.filename, + subfont(entry.subfont), + fontweight(entry.fontweight), + } end - local template = "%-" .. w[1] .. "s %-" .. w[2] .. "s %-" .. w[3] .. "s %s" + table.formatcolumns(s) for k,v in ipairs(s) do - local entry = t[v] - local tag, fontname, filename, sub = v, entry[2], entry[3], entry[4] - if sub then sub = "(sub)" else sub = "" end - if info then - showfeatures(tag,fontname,filename,sub,t) - else - print(string.format(template,tag,fontname,filename,sub)) + texio.write_nl(v) + end + end +end + +local function list_matches(t) + if t then + local s, w = table.sortedkeys(t), { 0, 0, 0 } + if info then + for k,v in ipairs(s) do + showfeatures(v,t[v]) + end + else + for k,v in ipairs(s) do + local entry = t[v] + s[k] = { + v, + entry.fontname, + entry.filename, + subfont(entry.subfont) + } + end + table.formatcolumns(s) + for k,v in ipairs(s) do + texio.write_nl(v) end end end end -function scripts.fonts.list_by_specification(specification,reload,all,info) +function scripts.fonts.list() + + local all = environment.argument("all") + local info = environment.argument("info") + local reload = environment.argument("reload") + local pattern = environment.argument("pattern") + local filter = environment.argument("filter") + local given = environment.files[1] + reloadbase(reload) - local t = fonts.names.collectspec(specification) - if t then - local w, tags = { 0, 0, 0 }, { } - for k,entry in ipairs(t) do - local s = entry[5] .. "-" .. (entry[6] or "noweight") .. "-" .. (entry[7] or "nostyle") .. "-" .. (entry[8] or "nowidth") - local n = #s if n > w[1] then w[1] = n end - local n = #entry[2] if n > w[2] then w[2] = n end - local n = #entry[3] if n > w[3] then w[3] = n end - tags[k] = s + + if environment.argument("name") then + if pattern then + --~ mtxrun --script font --list --name --pattern=*somename* + list_matches(fonts.names.list(make_pattern(pattern),reload,all)) + elseif filter then + logs.report("fontnames","not supported: --list --name --filter",name) + elseif given then + --~ mtxrun --script font --list --name somename + list_matches(fonts.names.list(given,reload,all)) + else + logs.report("fontnames","not supported: --list --name <no specification>",name) end - local template = "%-" .. w[1] .."s %-" .. w[2] .. "s %-" .. w[3] .. "s %s" - for k,entry in ipairs(t) do - local tag, fontname, filename, sub, name, weight, style = tags[k], entry[2], entry[3], entry[4], entry[5], entry[6], entry[7] - if sub then sub = "(sub)" else sub = "" end - print(string.format(template,tag,fontname,filename,sub)) + elseif environment.argument("spec") then + if pattern then + --~ mtxrun --script font --list --spec --pattern=*somename* + logs.report("fontnames","not supported: --list --spec --pattern",name) + elseif filter then + --~ mtxrun --script font --list --spec --filter="fontname=somename" + list_specifications(fonts.names.getlookups(filter),nil,reload) + elseif given then + --~ mtxrun --script font --list --spec somename + list_specifications(fonts.names.collectspec(given,reload,all)) + else + logs.report("fontnames","not supported: --list --spec <no specification>",name) end + elseif pattern then + --~ mtxrun --script font --list --pattern=*somename* + list_matches(fonts.names.list(make_pattern(pattern),reload,all)) + elseif given then + --~ mtxrun --script font --list somename + list_matches(fonts.names.list(given,reload,all)) + else + logs.report("fontnames","not supported: --list <no specification>",name) end + end -function scripts.fonts.save(name,sub) +function scripts.fonts.save() + local name = environment.files[1] or "" + local sub = environment.files[2] or "" local function save(savename,fontblob) if fontblob then savename = savename:lower() .. ".lua" @@ -171,37 +265,49 @@ function scripts.fonts.save(name,sub) end end -logs.extendbanner("Font Tools 0.20",true) +logs.extendbanner("Font Tools 0.21",true) messages.help = [[ --reload generate new font database ---list [--info] list installed fonts (show info) --save save open type font in raw table --names generate 'luatex-fonts-names.lua' (not for context!) +--list list installed fonts (show info) + +--name filter by name +--spec filter by spec --pattern=str filter files using pattern +--filter=list key-value pairs --all provide alternatives +--info give more details +--track=list enable trackers + +examples: + +mtxrun --script font --list somename (== --pattern=*somename*) + +mtxrun --script font --list --name somename +mtxrun --script font --list --name --pattern=*somename* + +mtxrun --script font --list --spec somename +mtxrun --script font --list --spec somename-bold-italic +mtxrun --script font --list --spec --pattern=*somename* +mtxrun --script font --list --spec --filter="fontname=somename" +mtxrun --script font --list --spec --filter="familyname=somename,weight=bold,style=italic,width=condensed" ]] +local track = environment.argument("track") + +if track then trackers.enable(track) end + if environment.argument("reload") then scripts.fonts.reload(true) elseif environment.argument("names") then scripts.fonts.names() -elseif environment.argument("list") then - local all = environment.argument("all") - local info = environment.argument("info") - local reload = environment.argument("reload") - if environment.argument("pattern") then - scripts.fonts.list_by_pattern(environment.argument("pattern"),reload,all,info) - elseif environment.files[1] then - scripts.fonts.list_by_specification(environment.files[1],reload,all,info) - else - scripts.fonts.list_by_pattern("",reload,all,info) -- wildcard - end elseif environment.argument("save") then - local name = environment.files[1] or "" - local sub = environment.files[2] or "" - scripts.fonts.save(name,sub) + scripts.fonts.save() +elseif environment.argument("list") then + scripts.fonts.list() else logs.help(messages.help) end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 130ad493c..0d3f08025 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %.99g,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%.99g,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%.99g,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%.99g,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%.99g,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent) local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent} local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')") local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'") local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val if expressions[t] then s = s and s ~= "" and cleaner:match(s) if s and s ~= "" then - return "expr." .. t .. "(e," .. s ..")" + return "expr." .. t .. "(ll," .. s ..")" else - return "expr." .. t .. "(e)" + return "expr." .. t .. "(ll)" end else return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg end expressions.tag = function(e,n) -- only tg - local found = false - n = tonumber(n) or 0 - if n == 0 then - found = (type(e) == "table") and e -- seems to fail - elseif n < 0 then - local d, k = e.__p__.dt, e.ni - for i=k-1,1,-1 do - local di = d[i] - if type(di) == "table" then - if n == -1 then - found = di - break - else - n = n + 1 + if not e then + return "" + else + local found = false + n = tonumber(n) or 0 + if n == 0 then + found = (type(e) == "table") and e -- seems to fail + elseif n < 0 then + local d, k = e.__p__.dt, e.ni + for i=k-1,1,-1 do + local di = d[i] + if type(di) == "table" then + if n == -1 then + found = di + break + else + n = n + 1 + end end end - end - else - local d, k = e.__p__.dt, e.ni - for i=k+1,#d,1 do - local di = d[i] - if type(di) == "table" then - if n == 1 then - found = di - break - else - n = n - 1 + else + local d, k = e.__p__.dt, e.ni + for i=k+1,#d,1 do + local di = d[i] + if type(di) == "table" then + if n == 1 then + found = di + break + else + n = n - 1 + end end end end + return (found and found.tg) or "" end - return (found and found.tg) or "" end --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata) --~ local settings = xmldata.settings --~ settings.parent_root = xmldata -- to be tested --~ local xi = xmlconvert(data,settings) - local xi = xml.inheritedconvert(element,xmldata) + local xi = xml.inheritedconvert(data,xmldata) if not xi then epdt[ek.ni] = "" -- xml.empty(d,k) else @@ -7046,7 +7055,6 @@ end local name, banner = 'report', 'context' local function report(category,fmt,...) ---~ print(fmt,...) if fmt then write_nl(format("%s | %s: %s",name,category,format(fmt,...))) elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -7649,9 +7659,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -7871,7 +7885,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -8610,8 +8632,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua index 2bc943210..abd80b8b4 100644 --- a/scripts/context/stubs/mswin/luatools.lua +++ b/scripts/context/stubs/mswin/luatools.lua @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = { license = "see context related readme files" } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end --~ return p --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~ local c1, c2 = string.byte(s, 1, 2) +--~ return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~ local c1, c2, c3 = string.byte(s, 1, 3) +--~ return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~ local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~ return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191") -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~ + lpeg.R("\194\223") * cont / f2 +--~ + lpeg.R("\224\239") * cont * cont / f3 +--~ + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191") -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + + end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = { table.join = table.concat local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs function table.strip(tab) local lst = { } @@ -721,6 +756,8 @@ end -- -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution + local function do_serialize(root,name,depth,level,indexed) if level > 0 then depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %s,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then handle(format("%s %s,",depth,v)) else handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%s,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%s,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%s,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%s,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then --~ handle(format("%s %s=%s,",depth,key(k),v)) if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify) end end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ... for i=1,#t do local v = t[i] if type(v) == "table" then @@ -1065,6 +1103,24 @@ end table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) + if not f then + f = { } + end + for k, v in next, t do + if type(v) == "table" then + flattened(v,f) + else + f[k] = v + end + end + return f +end + +table.flattened = flattened + -- the next three may disappear function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table elseif not t then t = { } end - setmetatable(t, { __index = function(_,key) return p[key] end }) + setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ? return t end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = { license = "see context related readme files" } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil function os.resultof(command) return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default) elseif name == "macosx" then if find(architecture,"i386") then platform = "osx-intel" + elseif find(architecture,"x86_64") then + platform = "osx-64" else platform = "osx-ppc" end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default) return platform end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +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 -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str) return str end +--~ print(file.collapse_path("/a")) --~ print(file.collapse_path("a/./b/..")) --~ print(file.collapse_path("a/aa/../b/bb")) --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how) end end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } if moretolerant then pattern_b_s:match(str) else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str) end end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_b_s:match(str) return hash else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str) end end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_c_s:match(str) return next(hash) and hash else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings) sc = table.clone(self[parent]) self[class] = sc end - aux.add_settings_to_array(sc, settings) + aux.settings_to_hash(settings,sc) end -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = { -- bound to a variable, like node.new, node.copy etc (contrary to for instance -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub + debugger = debugger or { } local counters = { } local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub -- one @@ -3363,11 +3453,11 @@ end --~ print("") --~ debugger.showstats(print,3) -trackers = trackers or { } +setters = setters or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) + local data, done = t.data, t.done if type(what) == "string" then what = aux.settings_to_array(what) -- inefficient but ok end @@ -3386,28 +3476,30 @@ local function set(what,value) end end -local function reset() - for d, f in next, data do +local function reset(t) + for d, f in next, t.data do for i=1,#f do f[i](false) end end end -local function enable(what) - set(what,true) +local function enable(t,what) + set(t,what,true) end -local function disable(what) +local function disable(t,what) + local data = t.data if not what or what == "" then - done = { } - reset() + t.done = { } + reset(t) else - set(what,false) + set(t,what,false) end end -function trackers.register(what,...) +function setters.register(t,what,...) + local data = t.data what = lower(what) local w = data[what] if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...) if typ == "function" then w[#w+1] = fnc elseif typ == "string" then - w[#w+1] = function(value) set(fnc,value,nesting) end + w[#w+1] = function(value) set(t,fnc,value,nesting) end end end end -function trackers.enable(what) - local e = trackers.enable - trackers.enable, done = enable, { } - enable(string.simpleesc(what)) - trackers.enable, done = e, { } +function setters.enable(t,what) + local e = t.enable + t.enable, t.done = enable, { } + enable(t,string.simpleesc(what)) + t.enable, t.done = e, { } end -function trackers.disable(what) - local e = trackers.disable - trackers.disable, done = disable, { } - disable(string.simpleesc(what)) - trackers.disable, done = e, { } +function setters.disable(t,what) + local e = t.disable + t.disable, t.done = disable, { } + disable(t,string.simpleesc(what)) + t.disable, t.done = e, { } end -function trackers.reset() - done = { } - reset() +function setters.reset(t) + t.done = { } + reset(t) end -function trackers.list() -- pattern - local list = table.sortedkeys(data) +function setters.list(t) -- pattern + local list = table.sortedkeys(t.data) local user, system = { }, { } for l=1,#list do local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern return user, system end +function setters.show(t) + commands.writestatus("","") + for k,v in ipairs(setters.list(t)) do + commands.writestatus(t.name,v) + end + commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) + local t + t = { + data = { }, + name = name, + enable = function(...) setters.enable (t,...) end, + disable = function(...) setters.disable (t,...) end, + register = function(...) setters.register(t,...) end, + list = function(...) setters.list (t,...) end, + show = function(...) setters.show (t,...) end, + } + setters.data[name] = t + return t +end + +trackers = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) + commands.writestatus("directives","enabling: %s",concat({...}," ")) + e(...) +end + +function directives.disable(...) + commands.writestatus("directives","disabling: %s",concat({...}," ")) + d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~ if type(what) == "string" then +--~ what = aux.settings_to_array(what) -- inefficient but ok +--~ end +--~ for i=1,#what do +--~ local w = what[i] +--~ for d, f in next, data do +--~ if done[d] then +--~ -- prevent recursion due to wildcards +--~ elseif find(d,w) then +--~ done[d] = true +--~ for i=1,#f do +--~ f[i](value) +--~ end +--~ end +--~ end +--~ end +--~ end +--~ local function reset() +--~ for d, f in next, data do +--~ for i=1,#f do +--~ f[i](false) +--~ end +--~ end +--~ end +--~ local function enable(what) +--~ set(what,true) +--~ end +--~ local function disable(what) +--~ if not what or what == "" then +--~ done = { } +--~ reset() +--~ else +--~ set(what,false) +--~ end +--~ end +--~ function trackers.register(what,...) +--~ what = lower(what) +--~ local w = data[what] +--~ if not w then +--~ w = { } +--~ data[what] = w +--~ end +--~ for _, fnc in next, { ... } do +--~ local typ = type(fnc) +--~ if typ == "function" then +--~ w[#w+1] = fnc +--~ elseif typ == "string" then +--~ w[#w+1] = function(value) set(fnc,value,nesting) end +--~ end +--~ end +--~ end +--~ function trackers.enable(what) +--~ local e = trackers.enable +--~ trackers.enable, done = enable, { } +--~ enable(string.simpleesc(what)) +--~ trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~ local e = trackers.disable +--~ trackers.disable, done = disable, { } +--~ disable(string.simpleesc(what)) +--~ trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~ done = { } +--~ reset() +--~ end +--~ function trackers.list() -- pattern +--~ local list = table.sortedkeys(data) +--~ local user, system = { }, { } +--~ for l=1,#list do +--~ local what = list[l] +--~ if find(what,"^%*") then +--~ system[#system+1] = what +--~ else +--~ user[#user+1] = what +--~ end +--~ end +--~ return user, system +--~ end + end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report) end + end -- of closure do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -4703,9 +4931,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -4925,7 +5157,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -5664,8 +5904,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 130ad493c..0d3f08025 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %.99g,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%.99g,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%.99g,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%.99g,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%.99g,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent) local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent} local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')") local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'") local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val if expressions[t] then s = s and s ~= "" and cleaner:match(s) if s and s ~= "" then - return "expr." .. t .. "(e," .. s ..")" + return "expr." .. t .. "(ll," .. s ..")" else - return "expr." .. t .. "(e)" + return "expr." .. t .. "(ll)" end else return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg end expressions.tag = function(e,n) -- only tg - local found = false - n = tonumber(n) or 0 - if n == 0 then - found = (type(e) == "table") and e -- seems to fail - elseif n < 0 then - local d, k = e.__p__.dt, e.ni - for i=k-1,1,-1 do - local di = d[i] - if type(di) == "table" then - if n == -1 then - found = di - break - else - n = n + 1 + if not e then + return "" + else + local found = false + n = tonumber(n) or 0 + if n == 0 then + found = (type(e) == "table") and e -- seems to fail + elseif n < 0 then + local d, k = e.__p__.dt, e.ni + for i=k-1,1,-1 do + local di = d[i] + if type(di) == "table" then + if n == -1 then + found = di + break + else + n = n + 1 + end end end - end - else - local d, k = e.__p__.dt, e.ni - for i=k+1,#d,1 do - local di = d[i] - if type(di) == "table" then - if n == 1 then - found = di - break - else - n = n - 1 + else + local d, k = e.__p__.dt, e.ni + for i=k+1,#d,1 do + local di = d[i] + if type(di) == "table" then + if n == 1 then + found = di + break + else + n = n - 1 + end end end end + return (found and found.tg) or "" end - return (found and found.tg) or "" end --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata) --~ local settings = xmldata.settings --~ settings.parent_root = xmldata -- to be tested --~ local xi = xmlconvert(data,settings) - local xi = xml.inheritedconvert(element,xmldata) + local xi = xml.inheritedconvert(data,xmldata) if not xi then epdt[ek.ni] = "" -- xml.empty(d,k) else @@ -7046,7 +7055,6 @@ end local name, banner = 'report', 'context' local function report(category,fmt,...) ---~ print(fmt,...) if fmt then write_nl(format("%s | %s: %s",name,category,format(fmt,...))) elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -7649,9 +7659,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -7871,7 +7885,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -8610,8 +8632,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools index 2bc943210..abd80b8b4 100755 --- a/scripts/context/stubs/unix/luatools +++ b/scripts/context/stubs/unix/luatools @@ -308,7 +308,7 @@ if not modules then modules = { } end modules ['l-lpeg'] = { license = "see context related readme files" } -local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc --~ l-lpeg.lua : @@ -415,6 +415,41 @@ end --~ return p --~ end +--~ from roberto's site: +--~ +--~ -- decode a two-byte UTF-8 sequence +--~ local function f2 (s) +--~ local c1, c2 = string.byte(s, 1, 2) +--~ return c1 * 64 + c2 - 12416 +--~ end +--~ +--~ -- decode a three-byte UTF-8 sequence +--~ local function f3 (s) +--~ local c1, c2, c3 = string.byte(s, 1, 3) +--~ return (c1 * 64 + c2) * 64 + c3 - 925824 +--~ end +--~ +--~ -- decode a four-byte UTF-8 sequence +--~ local function f4 (s) +--~ local c1, c2, c3, c4 = string.byte(s, 1, 4) +--~ return ((c1 * 64 + c2) * 64 + c3) * 64 + c4 - 63447168 +--~ end +--~ +--~ local cont = lpeg.R("\128\191") -- continuation byte +--~ +--~ local utf8 = lpeg.R("\0\127") / string.byte +--~ + lpeg.R("\194\223") * cont / f2 +--~ + lpeg.R("\224\239") * cont * cont / f3 +--~ + lpeg.R("\240\244") * cont * cont * cont / f4 +--~ +--~ local decode_pattern = lpeg.Ct(utf8^0) * -1 + + +local cont = R("\128\191") -- continuation byte + +lpeg.utf8 = R("\0\127") + R("\194\223") * cont + R("\224\239") * cont * cont + R("\240\244") * cont * cont * cont + + end -- of closure @@ -431,9 +466,9 @@ if not modules then modules = { } end modules ['l-table'] = { table.join = table.concat local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove -local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump +local format, find, gsub, lower, dump, match = string.format, string.find, string.gsub, string.lower, string.dump, string.match local getmetatable, setmetatable = getmetatable, setmetatable -local type, next, tostring, ipairs = type, next, tostring, ipairs +local type, next, tostring, tonumber, ipairs, pairs = type, next, tostring, tonumber, ipairs, pairs function table.strip(tab) local lst = { } @@ -721,6 +756,8 @@ end -- -- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) ) +-- problem: there no good number_to_string converter with the best resolution + local function do_serialize(root,name,depth,level,indexed) if level > 0 then depth = depth .. " " @@ -743,6 +780,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -765,10 +803,10 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %s,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then handle(format("%s %s,",depth,v)) else handle(format("%s %q,",depth,v)) @@ -805,29 +843,29 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%s,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%s,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%s,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%s,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then - if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then + if reduce and tonumber(v) then --~ handle(format("%s %s=%s,",depth,key(k),v)) if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then @@ -1036,7 +1074,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify) end end -local function flatten(t,f,complete) +local function flatten(t,f,complete) -- is this used? meybe a variant with next, ... for i=1,#t do local v = t[i] if type(v) == "table" then @@ -1065,6 +1103,24 @@ end table.flatten_one_level = table.unnest +-- a better one: + +local function flattened(t,f) + if not f then + f = { } + end + for k, v in next, t do + if type(v) == "table" then + flattened(v,f) + else + f[k] = v + end + end + return f +end + +table.flattened = flattened + -- the next three may disappear function table.remove_value(t,value) -- todo: n @@ -1200,7 +1256,7 @@ function table.clone(t,p) -- t is optional or nil or table elseif not t then t = { } end - setmetatable(t, { __index = function(_,key) return p[key] end }) + setmetatable(t, { __index = function(_,key) return p[key] end }) -- why not __index = p ? return t end @@ -1615,7 +1671,8 @@ if not modules then modules = { } end modules ['l-os'] = { license = "see context related readme files" } -local find = string.find +local find, format = string.find, string.format +local random, ceil = math.random, math.ceil function os.resultof(command) return io.popen(command,"r"):read("*all") @@ -1712,6 +1769,8 @@ function os.currentplatform(name,default) elseif name == "macosx" then if find(architecture,"i386") then platform = "osx-intel" + elseif find(architecture,"x86_64") then + platform = "osx-64" else platform = "osx-ppc" end @@ -1738,6 +1797,29 @@ function os.currentplatform(name,default) return platform end +-- beware, we set the randomseed +-- + +-- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the +-- version number as well as two reserved bits. All other bits are set using a random or pseudorandom +-- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal +-- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. +-- +-- as we don't call this function too often there is not so much risk on repetition + + +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 -- of closure @@ -1778,8 +1860,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -1857,6 +1943,7 @@ function file.collapse_path(str) return str end +--~ print(file.collapse_path("/a")) --~ print(file.collapse_path("a/./b/..")) --~ print(file.collapse_path("a/aa/../b/bb")) --~ print(file.collapse_path("a/../..")) @@ -3028,9 +3115,9 @@ function aux.make_settings_to_hash_pattern(set,how) end end -function aux.settings_to_hash(str) +function aux.settings_to_hash(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } if moretolerant then pattern_b_s:match(str) else @@ -3042,9 +3129,9 @@ function aux.settings_to_hash(str) end end -function aux.settings_to_hash_tolerant(str) +function aux.settings_to_hash_tolerant(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_b_s:match(str) return hash else @@ -3052,9 +3139,9 @@ function aux.settings_to_hash_tolerant(str) end end -function aux.settings_to_hash_strict(str) +function aux.settings_to_hash_strict(str,existing) if str and str ~= "" then - hash = { } + hash = existing or { } pattern_c_s:match(str) return next(hash) and hash else @@ -3142,7 +3229,7 @@ function aux.getparameters(self,class,parentclass,settings) sc = table.clone(self[parent]) self[class] = sc end - aux.add_settings_to_array(sc, settings) + aux.settings_to_hash(settings,sc) end -- temporary here @@ -3230,12 +3317,15 @@ if not modules then modules = { } end modules ['trac-tra'] = { -- bound to a variable, like node.new, node.copy etc (contrary to for instance -- node.has_attribute which is bound to a has_attribute local variable in mkiv) +local getinfo = debug.getinfo +local type, next = type, next +local concat = table.concat +local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub + debugger = debugger or { } local counters = { } local names = { } -local getinfo = debug.getinfo -local format, find, lower, gmatch, gsub = string.format, string.find, string.lower, string.gmatch, string.gsub -- one @@ -3363,11 +3453,11 @@ end --~ print("") --~ debugger.showstats(print,3) -trackers = trackers or { } +setters = setters or { } +setters.data = setters.data or { } -local data, done = { }, { } - -local function set(what,value) +local function set(t,what,value) + local data, done = t.data, t.done if type(what) == "string" then what = aux.settings_to_array(what) -- inefficient but ok end @@ -3386,28 +3476,30 @@ local function set(what,value) end end -local function reset() - for d, f in next, data do +local function reset(t) + for d, f in next, t.data do for i=1,#f do f[i](false) end end end -local function enable(what) - set(what,true) +local function enable(t,what) + set(t,what,true) end -local function disable(what) +local function disable(t,what) + local data = t.data if not what or what == "" then - done = { } - reset() + t.done = { } + reset(t) else - set(what,false) + set(t,what,false) end end -function trackers.register(what,...) +function setters.register(t,what,...) + local data = t.data what = lower(what) local w = data[what] if not w then @@ -3419,32 +3511,32 @@ function trackers.register(what,...) if typ == "function" then w[#w+1] = fnc elseif typ == "string" then - w[#w+1] = function(value) set(fnc,value,nesting) end + w[#w+1] = function(value) set(t,fnc,value,nesting) end end end end -function trackers.enable(what) - local e = trackers.enable - trackers.enable, done = enable, { } - enable(string.simpleesc(what)) - trackers.enable, done = e, { } +function setters.enable(t,what) + local e = t.enable + t.enable, t.done = enable, { } + enable(t,string.simpleesc(what)) + t.enable, t.done = e, { } end -function trackers.disable(what) - local e = trackers.disable - trackers.disable, done = disable, { } - disable(string.simpleesc(what)) - trackers.disable, done = e, { } +function setters.disable(t,what) + local e = t.disable + t.disable, t.done = disable, { } + disable(t,string.simpleesc(what)) + t.disable, t.done = e, { } end -function trackers.reset() - done = { } - reset() +function setters.reset(t) + t.done = { } + reset(t) end -function trackers.list() -- pattern - local list = table.sortedkeys(data) +function setters.list(t) -- pattern + local list = table.sortedkeys(t.data) local user, system = { }, { } for l=1,#list do local what = list[l] @@ -3457,6 +3549,139 @@ function trackers.list() -- pattern return user, system end +function setters.show(t) + commands.writestatus("","") + for k,v in ipairs(setters.list(t)) do + commands.writestatus(t.name,v) + end + commands.writestatus("","") +end + +-- we could have used a bit of oo and the trackers:enable syntax but +-- there is already a lot of code around using the singluar tracker + +function setters.new(name) + local t + t = { + data = { }, + name = name, + enable = function(...) setters.enable (t,...) end, + disable = function(...) setters.disable (t,...) end, + register = function(...) setters.register(t,...) end, + list = function(...) setters.list (t,...) end, + show = function(...) setters.show (t,...) end, + } + setters.data[name] = t + return t +end + +trackers = setters.new("trackers") +directives = setters.new("directives") + +-- nice trick: we overload two of the directives related functions with variants that +-- do tracing (itself using a tracker) .. proof of concept + +local trace_directives = false local trace_directives = false trackers.register("system.directives", function(v) trace_directives = v end) + +local e = directives.enable +local d = directives.disable + +function directives.enable(...) + commands.writestatus("directives","enabling: %s",concat({...}," ")) + e(...) +end + +function directives.disable(...) + commands.writestatus("directives","disabling: %s",concat({...}," ")) + d(...) +end + +--~ -- old code: +-- +--~ trackers = trackers or { } +--~ local data, done = { }, { } +--~ local function set(what,value) +--~ if type(what) == "string" then +--~ what = aux.settings_to_array(what) -- inefficient but ok +--~ end +--~ for i=1,#what do +--~ local w = what[i] +--~ for d, f in next, data do +--~ if done[d] then +--~ -- prevent recursion due to wildcards +--~ elseif find(d,w) then +--~ done[d] = true +--~ for i=1,#f do +--~ f[i](value) +--~ end +--~ end +--~ end +--~ end +--~ end +--~ local function reset() +--~ for d, f in next, data do +--~ for i=1,#f do +--~ f[i](false) +--~ end +--~ end +--~ end +--~ local function enable(what) +--~ set(what,true) +--~ end +--~ local function disable(what) +--~ if not what or what == "" then +--~ done = { } +--~ reset() +--~ else +--~ set(what,false) +--~ end +--~ end +--~ function trackers.register(what,...) +--~ what = lower(what) +--~ local w = data[what] +--~ if not w then +--~ w = { } +--~ data[what] = w +--~ end +--~ for _, fnc in next, { ... } do +--~ local typ = type(fnc) +--~ if typ == "function" then +--~ w[#w+1] = fnc +--~ elseif typ == "string" then +--~ w[#w+1] = function(value) set(fnc,value,nesting) end +--~ end +--~ end +--~ end +--~ function trackers.enable(what) +--~ local e = trackers.enable +--~ trackers.enable, done = enable, { } +--~ enable(string.simpleesc(what)) +--~ trackers.enable, done = e, { } +--~ end +--~ function trackers.disable(what) +--~ local e = trackers.disable +--~ trackers.disable, done = disable, { } +--~ disable(string.simpleesc(what)) +--~ trackers.disable, done = e, { } +--~ end +--~ function trackers.reset() +--~ done = { } +--~ reset() +--~ end +--~ function trackers.list() -- pattern +--~ local list = table.sortedkeys(data) +--~ local user, system = { }, { } +--~ for l=1,#list do +--~ local what = list[l] +--~ if find(what,"^%*") then +--~ system[#system+1] = what +--~ else +--~ user[#user+1] = what +--~ end +--~ end +--~ return user, system +--~ end + end -- of closure @@ -3908,6 +4133,7 @@ function statistics.timed(action,report) end + end -- of closure do -- create closure to overcome 200 locals limit @@ -4241,6 +4467,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -4629,7 +4857,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -4638,7 +4866,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -4703,9 +4931,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -4734,7 +4962,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -4746,11 +4974,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -4815,13 +5043,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -4829,12 +5061,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -4858,12 +5090,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -4925,7 +5157,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -5184,6 +5416,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -5206,6 +5439,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -5213,6 +5452,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -5467,7 +5707,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -5664,8 +5904,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5896,7 +6136,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -6048,9 +6288,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -6397,6 +6637,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 130ad493c..0d3f08025 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -789,6 +789,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s{",depth)) end end + -- we could check for k (index) being number (cardinal) if root and next(root) then local first, last = nil, 0 -- #root cannot be trusted here if compact then @@ -811,7 +812,7 @@ local function do_serialize(root,name,depth,level,indexed) if hexify then handle(format("%s 0x%04X,",depth,v)) else - handle(format("%s %.99g,",depth,v)) + handle(format("%s %s,",depth,v)) -- %.99g end elseif t == "string" then if reduce and tonumber(v) then @@ -851,25 +852,25 @@ local function do_serialize(root,name,depth,level,indexed) --~ if hexify then --~ handle(format("%s %s=0x%04X,",depth,key(k),v)) --~ else - --~ handle(format("%s %s=%.99g,",depth,key(k),v)) + --~ handle(format("%s %s=%s,",depth,key(k),v)) -- %.99g --~ end if type(k) == "number" then -- or find(k,"^%d+$") then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) else - handle(format("%s [%s]=%.99g,",depth,k,v)) + handle(format("%s [%s]=%s,",depth,k,v)) -- %.99g end elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then if hexify then handle(format("%s %s=0x%04X,",depth,k,v)) else - handle(format("%s %s=%.99g,",depth,k,v)) + handle(format("%s %s=%s,",depth,k,v)) -- %.99g end else if hexify then handle(format("%s [%q]=0x%04X,",depth,k,v)) else - handle(format("%s [%q]=%.99g,",depth,k,v)) + handle(format("%s [%q]=%s,",depth,k,v)) -- %.99g end end elseif t == "string" then @@ -1868,8 +1869,12 @@ function file.dirname(name,default) return match(name,"^(.+)[/\\].-$") or (default or "") end +--~ function file.basename(name) +--~ return match(name,"^.+[/\\](.-)$") or name +--~ end + function file.basename(name) - return match(name,"^.+[/\\](.-)$") or name + return match(name,"^.*[/\\](.-)$") or name end function file.nameonly(name) @@ -4872,7 +4877,7 @@ local noparent = 1 - (lparent+rparent) local nested = lpeg.P{lparent * (noparent + lpeg.V(1))^0 * rparent} local value = lpeg.P(lparent * lpeg.C((noparent + nested)^0) * rparent) -- lpeg.P{"("*C(((1-S("()"))+V(1))^0)*")"} -local lp_child = Cc("expr.child(e,'") * R("az","AZ","--","__")^1 * Cc("')") +local lp_child = Cc("expr.child(ll,'") * R("az","AZ","--","__")^1 * Cc("')") local lp_string = Cc("'") * R("az","AZ","--","__")^1 * Cc("'") local lp_content = (P("'") * (1-P("'"))^0 * P("'") + P('"') * (1-P('"'))^0 * P('"')) @@ -4882,9 +4887,9 @@ local lp_special = (C(P("name")+P("text")+P("tag")+P("count")+P("child"))) * val if expressions[t] then s = s and s ~= "" and cleaner:match(s) if s and s ~= "" then - return "expr." .. t .. "(e," .. s ..")" + return "expr." .. t .. "(ll," .. s ..")" else - return "expr." .. t .. "(e)" + return "expr." .. t .. "(ll)" end else return "expr.error(" .. t .. ")" @@ -5434,38 +5439,42 @@ expressions.name = function(e,n) -- ns + tg end expressions.tag = function(e,n) -- only tg - local found = false - n = tonumber(n) or 0 - if n == 0 then - found = (type(e) == "table") and e -- seems to fail - elseif n < 0 then - local d, k = e.__p__.dt, e.ni - for i=k-1,1,-1 do - local di = d[i] - if type(di) == "table" then - if n == -1 then - found = di - break - else - n = n + 1 + if not e then + return "" + else + local found = false + n = tonumber(n) or 0 + if n == 0 then + found = (type(e) == "table") and e -- seems to fail + elseif n < 0 then + local d, k = e.__p__.dt, e.ni + for i=k-1,1,-1 do + local di = d[i] + if type(di) == "table" then + if n == -1 then + found = di + break + else + n = n + 1 + end end end - end - else - local d, k = e.__p__.dt, e.ni - for i=k+1,#d,1 do - local di = d[i] - if type(di) == "table" then - if n == 1 then - found = di - break - else - n = n - 1 + else + local d, k = e.__p__.dt, e.ni + for i=k+1,#d,1 do + local di = d[i] + if type(di) == "table" then + if n == 1 then + found = di + break + else + n = n - 1 + end end end end + return (found and found.tg) or "" end - return (found and found.tg) or "" end --[[ldx-- @@ -5992,7 +6001,7 @@ local function include(xmldata,pattern,attribute,recursive,loaddata) --~ local settings = xmldata.settings --~ settings.parent_root = xmldata -- to be tested --~ local xi = xmlconvert(data,settings) - local xi = xml.inheritedconvert(element,xmldata) + local xi = xml.inheritedconvert(data,xmldata) if not xi then epdt[ek.ni] = "" -- xml.empty(d,k) else @@ -7046,7 +7055,6 @@ end local name, banner = 'report', 'context' local function report(category,fmt,...) ---~ print(fmt,...) if fmt then write_nl(format("%s | %s: %s",name,category,format(fmt,...))) elseif category then @@ -7187,6 +7195,8 @@ local format, gsub, find, lower, upper, match, gmatch = string.format, string.gs local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys local next, type = next, type +local collapse_path = file.collapse_path + local trace_locating, trace_detail, trace_verbose = false, false, false trackers.register("resolvers.verbose", function(v) trace_verbose = v end) @@ -7575,7 +7585,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat end if ok then local function validate(s) - s = file.collapse_path(s) + s = collapse_path(s) return s ~= "" and not find(s,dummy_path_expr) and s end for k=1,#pathlist do @@ -7584,7 +7594,7 @@ local function expanded_path_from_list(pathlist) -- maybe not a list, just a pat else for k=1,#pathlist do for p in gmatch(pathlist[k],"([^,]+)") do - p = file.collapse_path(p) + p = collapse_path(p) if p ~= "" then newlist[#newlist+1] = p end end end @@ -7649,9 +7659,9 @@ local function identify_own() local ownpath = resolvers.getownpath() or lfs.currentdir() local ie = instance.environment if ownpath then - if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end - if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end - if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end + if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = collapse_path(ownpath) end + if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = collapse_path(ownpath .. "/..") end + if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = collapse_path(ownpath .. "/../..") end else logs.report("fileio","error: unable to locate ownpath") os.exit() @@ -7680,7 +7690,7 @@ function resolvers.identify_cnf() local function locate(filename,list) for i=1,#t do local ti = t[i] - local texmfcnf = file.collapse_path(file.join(ti,filename)) + local texmfcnf = collapse_path(file.join(ti,filename)) if lfs.isfile(texmfcnf) then list[#list+1] = texmfcnf end @@ -7692,11 +7702,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -7761,13 +7771,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -7775,12 +7789,12 @@ function resolvers.load_cnf() else instance.rootpath = instance.cnffiles[1] for k,fname in ipairs(instance.cnffiles) do - instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.cnffiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) if instance.diskcache and not instance.renewcache then resolvers.loadoldconfig(instance.cnffiles) if instance.loaderror then @@ -7804,12 +7818,12 @@ function resolvers.load_lua() else instance.rootpath = instance.luafiles[1] for k,fname in ipairs(instance.luafiles) do - instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/')) + instance.luafiles[k] = collapse_path(gsub(fname,"\\",'/')) end for i=1,3 do instance.rootpath = file.dirname(instance.rootpath) end - instance.rootpath = file.collapse_path(instance.rootpath) + instance.rootpath = collapse_path(instance.rootpath) resolvers.loadnewconfig() collapse_cnf_data() end @@ -7871,7 +7885,7 @@ function resolvers.locatelists() if trace_verbose then logs.report("fileio","locating list of %s",path) end - resolvers.locatedatabase(file.collapse_path(path)) + resolvers.locatedatabase(collapse_path(path)) end end @@ -8130,6 +8144,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -8152,6 +8167,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -8159,6 +8180,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -8413,7 +8435,7 @@ function resolvers.clean_path_list(str) local t = resolvers.expanded_path_list(str) if t then for i=1,#t do - t[i] = file.collapse_path(resolvers.clean_path(t[i])) + t[i] = collapse_path(resolvers.clean_path(t[i])) end end return t @@ -8610,8 +8632,8 @@ end local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc) local result = collected or { } local stamp = nil - filename = file.collapse_path(filename) -- elsewhere - filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere + filename = collapse_path(filename) -- elsewhere + filename = collapse_path(gsub(filename,"\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -8842,7 +8864,7 @@ local function collect_instance_files(filename,collected) -- todo : plugin (scan end end for k=1,#result do - result[k] = file.collapse_path(result[k]) + result[k] = collapse_path(result[k]) end if instance.remember then instance.found[stamp] = result @@ -8994,9 +9016,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() @@ -9343,6 +9365,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/tex/context/base/colo-hex.mkii b/tex/context/base/colo-hex.mkii index 7cef6e8a2..db67f1841 100644 --- a/tex/context/base/colo-hex.mkii +++ b/tex/context/base/colo-hex.mkii @@ -11,8 +11,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\ifx\dodododefinecolor\undefined \else - \endinput +\ifdefined \hexcolorprefix + \expandafter \endinput \fi \writestatus{loading}{ConTeXt Color Macros / Hexadecimal} diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv index 5f3cdf372..cde9f5820 100644 --- a/tex/context/base/colo-ini.mkiv +++ b/tex/context/base/colo-ini.mkiv @@ -143,7 +143,7 @@ \unexpanded\def\color [#1]{\groupedcommand{\doactivatecolor{#1}}{}} \unexpanded\def\startcolor [#1]{\begingroup\doactivatecolor{#1}} \unexpanded\def\stopcolor {\endgroup} -\unexpanded\def\graycolor [#1]{\groupedcommand{\setcolormodel{gray}\getvalue{#1}}{}} +\unexpanded\def\graycolor [#1]{\groupedcommand{\dosetcolormodel{gray}\getvalue{#1}}{}} \unexpanded\def\colored [#1]{\groupedcommand{\definecolor[@colored@][#1]\doactivatecolor{@colored@}}{}} \unexpanded\def\fastcolored [#1]#2{\begingroup\dodefinefastcolor[@colored@][#1]\doactivatecolor{@colored@}#2\endgroup} \def\predefinecolor [#1]{\flushatshipout{\hbox{\color[#1]{}}}} @@ -693,7 +693,10 @@ \def\setcolormodel#1% {\showcolormessage\m!colors1{#1}% - \currentcolormodel\ctxlua{tex.print(colors.setmodel('#1',\ifweightGRAY true\else false\fi))}% + \dosetcolormodel{#1}} + +\def\dosetcolormodel#1% no message + {\currentcolormodel\ctxlua{tex.print(colors.setmodel('#1',\ifweightGRAY true\else false\fi))}% \dosetattribute{colormodel}{\the\currentcolormodel}} \setcolormodel{all} diff --git a/tex/context/base/colo-x11.tex b/tex/context/base/colo-x11.tex new file mode 100644 index 000000000..45d3aac62 --- /dev/null +++ b/tex/context/base/colo-x11.tex @@ -0,0 +1,677 @@ +%D \module +%D [ file=colo-x11, +%D version=2009.11.13, +%D title=\CONTEXT\ Color Macros, +%D subtitle=X11, +%D author=Alan Braslau] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +%D Standard X11 rgb colors (from \type {/usr/share/X11/rgb.txt}): + +\doifnotmode{mkiv} { + \input colo-hex.mkii +} + +\definecolor [snow] [h=fffafa] +\definecolor [ghostwhite] [h=f8f8ff] +\definecolor [whitesmoke] [s=0.96] +\definecolor [gainsboro] [s=0.86] +\definecolor [floralwhite] [h=fffaf0] +\definecolor [oldlace] [h=fdf5e6] +\definecolor [linen] [h=faf0e6] +\definecolor [antiquewhite] [h=faebd7] +\definecolor [papayawhip] [h=ffefd5] +\definecolor [blanchedalmond] [h=ffebcd] +\definecolor [bisque] [h=ffe4c4] +\definecolor [peachpuff] [h=ffdab9] +\definecolor [navajowhite] [h=ffdead] +\definecolor [moccasin] [h=ffe4b5] +\definecolor [cornsilk] [h=fff8dc] +\definecolor [ivory] [h=fffff0] +\definecolor [lemonchiffon] [h=fffacd] +\definecolor [seashell] [h=fff5ee] +\definecolor [honeydew] [h=f0fff0] +\definecolor [mintcream] [h=f5fffa] +\definecolor [azure] [h=f0ffff] +\definecolor [aliceblue] [h=f0f8ff] +\definecolor [lavender] [h=e6e6fa] +\definecolor [lavenderblush] [h=fff0f5] +\definecolor [mistyrose] [h=ffe4e1] +\definecolor [white] [s=1] +\definecolor [black] [s=0] +\definecolor [darkslategray] [h=2f4f4f] +\definecolor [darkslategrey] [darkslategray] +\definecolor [dimgray] [s=0.41] +\definecolor [dimgrey] [dimgray] +\definecolor [slategray] [h=708090] +\definecolor [slategrey] [slategray] +\definecolor [lightslategray] [h=778899] +\definecolor [lightslategrey] [lightslategray] +\definecolor [gray] [s=0.75] +\definecolor [grey] [gray] +\definecolor [lightgrey] [s=0.83] +\definecolor [lightgray] [lightgrey] +\definecolor [midnightblue] [h=191970] +\definecolor [navy] [h=000080] +\definecolor [navyblue] [navy] +\definecolor [cornflowerblue] [h=6495ed] +\definecolor [darkslateblue] [h=483d8b] +\definecolor [slateblue] [h=6a5acd] +\definecolor [mediumslateblue] [h=7b68ee] +\definecolor [lightslateblue] [h=8470ff] +\definecolor [mediumblue] [h=0000cd] +\definecolor [royalblue] [h=4169e1] +\definecolor [blue] [h=0000ff] +\definecolor [dodgerblue] [h=1e90ff] +\definecolor [deepskyblue] [h=00bfff] +\definecolor [skyblue] [h=87ceeb] +\definecolor [lightskyblue] [h=87cefa] +\definecolor [steelblue] [h=4682b4] +\definecolor [lightsteelblue] [h=b0c4de] +\definecolor [lightblue] [h=add8e6] +\definecolor [powderblue] [h=b0e0e6] +\definecolor [paleturquoise] [h=afeeee] +\definecolor [darkturquoise] [h=00ced1] +\definecolor [mediumturquoise] [h=48d1cc] +\definecolor [turquoise] [h=40e0d0] +\definecolor [cyan] [h=00ffff] +\definecolor [lightcyan] [h=e0ffff] +\definecolor [cadetblue] [h=5f9ea0] +\definecolor [mediumaquamarine] [h=66cdaa] +\definecolor [aquamarine] [h=7fffd4] +\definecolor [darkgreen] [h=006400] +\definecolor [darkolivegreen] [h=556b2f] +\definecolor [darkseagreen] [h=8fbc8f] +\definecolor [seagreen] [h=2e8b57] +\definecolor [mediumseagreen] [h=3cb371] +\definecolor [lightseagreen] [h=20b2aa] +\definecolor [palegreen] [h=98fb98] +\definecolor [springgreen] [h=00ff7f] +\definecolor [lawngreen] [h=7cfc00] +\definecolor [green] [h=00ff00] +\definecolor [chartreuse] [h=7fff00] +\definecolor [mediumspringgreen] [h=00fa9a] +\definecolor [greenyellow] [h=adff2f] +\definecolor [limegreen] [h=32cd32] +\definecolor [yellowgreen] [h=9acd32] +\definecolor [forestgreen] [h=228b22] +\definecolor [olivedrab] [h=6b8e23] +\definecolor [darkkhaki] [h=bdb76b] +\definecolor [khaki] [h=f0e68c] +\definecolor [palegoldenrod] [h=eee8aa] +\definecolor [lightgoldenrodyellow] [h=fafad2] +\definecolor [lightyellow] [h=ffffe0] +\definecolor [yellow] [h=ffff00] +\definecolor [gold] [h=ffd700] +\definecolor [lightgoldenrod] [h=eedd82] +\definecolor [goldenrod] [h=daa520] +\definecolor [darkgoldenrod] [h=b8860b] +\definecolor [rosybrown] [h=bc8f8f] +\definecolor [indianred] [h=cd5c5c] +\definecolor [saddlebrown] [h=8b4513] +\definecolor [sienna] [h=a0522d] +\definecolor [peru] [h=cd853f] +\definecolor [burlywood] [h=deb887] +\definecolor [beige] [h=f5f5dc] +\definecolor [wheat] [h=f5deb3] +\definecolor [sandybrown] [h=f4a460] +\definecolor [tan] [h=d2b48c] +\definecolor [chocolate] [h=d2691e] +\definecolor [firebrick] [h=b22222] +\definecolor [brown] [h=a52a2a] +\definecolor [darksalmon] [h=e9967a] +\definecolor [salmon] [h=fa8072] +\definecolor [lightsalmon] [h=ffa07a] +\definecolor [orange] [h=ffa500] +\definecolor [darkorange] [h=ff8c00] +\definecolor [coral] [h=ff7f50] +\definecolor [lightcoral] [h=f08080] +\definecolor [tomato] [h=ff6347] +\definecolor [orangered] [h=ff4500] +\definecolor [red] [h=ff0000] +\definecolor [hotpink] [h=ff69b4] +\definecolor [deeppink] [h=ff1493] +\definecolor [pink] [h=ffc0cb] +\definecolor [lightpink] [h=ffb6c1] +\definecolor [palevioletred] [h=db7093] +\definecolor [maroon] [h=b03060] +\definecolor [mediumvioletred] [h=c71585] +\definecolor [violetred] [h=d02090] +\definecolor [magenta] [h=ff00ff] +\definecolor [violet] [h=ee82ee] +\definecolor [plum] [h=dda0dd] +\definecolor [orchid] [h=da70d6] +\definecolor [mediumorchid] [h=ba55d3] +\definecolor [darkorchid] [h=9932cc] +\definecolor [darkviolet] [h=9400d3] +\definecolor [blueviolet] [h=8a2be2] +\definecolor [purple] [h=a020f0] +\definecolor [mediumpurple] [h=9370db] +\definecolor [thistle] [h=d8bfd8] +\definecolor [snow1] [h=fffafa] +\definecolor [snow2] [h=eee9e9] +\definecolor [snow3] [h=cdc9c9] +\definecolor [snow4] [h=8b8989] +\definecolor [seashell1] [h=fff5ee] +\definecolor [seashell2] [h=eee5de] +\definecolor [seashell3] [h=cdc5bf] +\definecolor [seashell4] [h=8b8682] +\definecolor [antiquewhite1] [h=ffefdb] +\definecolor [antiquewhite2] [h=eedfcc] +\definecolor [antiquewhite3] [h=cdc0b0] +\definecolor [antiquewhite4] [h=8b8378] +\definecolor [bisque1] [h=ffe4c4] +\definecolor [bisque2] [h=eed5b7] +\definecolor [bisque3] [h=cdb79e] +\definecolor [bisque4] [h=8b7d6b] +\definecolor [peachpuff1] [h=ffdab9] +\definecolor [peachpuff2] [h=eecbad] +\definecolor [peachpuff3] [h=cdaf95] +\definecolor [peachpuff4] [h=8b7765] +\definecolor [navajowhite1] [h=ffdead] +\definecolor [navajowhite2] [h=eecfa1] +\definecolor [navajowhite3] [h=cdb38b] +\definecolor [navajowhite4] [h=8b795e] +\definecolor [lemonchiffon1] [h=fffacd] +\definecolor [lemonchiffon2] [h=eee9bf] +\definecolor [lemonchiffon3] [h=cdc9a5] +\definecolor [lemonchiffon4] [h=8b8970] +\definecolor [cornsilk1] [h=fff8dc] +\definecolor [cornsilk2] [h=eee8cd] +\definecolor [cornsilk3] [h=cdc8b1] +\definecolor [cornsilk4] [h=8b8878] +\definecolor [ivory1] [h=fffff0] +\definecolor [ivory2] [h=eeeee0] +\definecolor [ivory3] [h=cdcdc1] +\definecolor [ivory4] [h=8b8b83] +\definecolor [honeydew1] [h=f0fff0] +\definecolor [honeydew2] [h=e0eee0] +\definecolor [honeydew3] [h=c1cdc1] +\definecolor [honeydew4] [h=838b83] +\definecolor [lavenderblush1] [h=fff0f5] +\definecolor [lavenderblush2] [h=eee0e5] +\definecolor [lavenderblush3] [h=cdc1c5] +\definecolor [lavenderblush4] [h=8b8386] +\definecolor [mistyrose1] [h=ffe4e1] +\definecolor [mistyrose2] [h=eed5d2] +\definecolor [mistyrose3] [h=cdb7b5] +\definecolor [mistyrose4] [h=8b7d7b] +\definecolor [azure1] [h=f0ffff] +\definecolor [azure2] [h=e0eeee] +\definecolor [azure3] [h=c1cdcd] +\definecolor [azure4] [h=838b8b] +\definecolor [slateblue1] [h=836fff] +\definecolor [slateblue2] [h=7a67ee] +\definecolor [slateblue3] [h=6959cd] +\definecolor [slateblue4] [h=473c8b] +\definecolor [royalblue1] [h=4876ff] +\definecolor [royalblue2] [h=436eee] +\definecolor [royalblue3] [h=3a5fcd] +\definecolor [royalblue4] [h=27408b] +\definecolor [blue1] [h=0000ff] +\definecolor [blue2] [h=0000ee] +\definecolor [blue3] [h=0000cd] +\definecolor [blue4] [h=00008b] +\definecolor [dodgerblue1] [h=1e90ff] +\definecolor [dodgerblue2] [h=1c86ee] +\definecolor [dodgerblue3] [h=1874cd] +\definecolor [dodgerblue4] [h=104e8b] +\definecolor [steelblue1] [h=63b8ff] +\definecolor [steelblue2] [h=5cacee] +\definecolor [steelblue3] [h=4f94cd] +\definecolor [steelblue4] [h=36648b] +\definecolor [deepskyblue1] [h=00bfff] +\definecolor [deepskyblue2] [h=00b2ee] +\definecolor [deepskyblue3] [h=009acd] +\definecolor [deepskyblue4] [h=00688b] +\definecolor [skyblue1] [h=87ceff] +\definecolor [skyblue2] [h=7ec0ee] +\definecolor [skyblue3] [h=6ca6cd] +\definecolor [skyblue4] [h=4a708b] +\definecolor [lightskyblue1] [h=b0e2ff] +\definecolor [lightskyblue2] [h=a4d3ee] +\definecolor [lightskyblue3] [h=8db6cd] +\definecolor [lightskyblue4] [h=607b8b] +\definecolor [slategray1] [h=c6e2ff] +\definecolor [slategray2] [h=b9d3ee] +\definecolor [slategray3] [h=9fb6cd] +\definecolor [slategray4] [h=6c7b8b] +\definecolor [lightsteelblue1] [h=cae1ff] +\definecolor [lightsteelblue2] [h=bcd2ee] +\definecolor [lightsteelblue3] [h=a2b5cd] +\definecolor [lightsteelblue4] [h=6e7b8b] +\definecolor [lightblue1] [h=bfefff] +\definecolor [lightblue2] [h=b2dfee] +\definecolor [lightblue3] [h=9ac0cd] +\definecolor [lightblue4] [h=68838b] +\definecolor [lightcyan1] [h=e0ffff] +\definecolor [lightcyan2] [h=d1eeee] +\definecolor [lightcyan3] [h=b4cdcd] +\definecolor [lightcyan4] [h=7a8b8b] +\definecolor [paleturquoise1] [h=bbffff] +\definecolor [paleturquoise2] [h=aeeeee] +\definecolor [paleturquoise3] [h=96cdcd] +\definecolor [paleturquoise4] [h=668b8b] +\definecolor [cadetblue1] [h=98f5ff] +\definecolor [cadetblue2] [h=8ee5ee] +\definecolor [cadetblue3] [h=7ac5cd] +\definecolor [cadetblue4] [h=53868b] +\definecolor [turquoise1] [h=00f5ff] +\definecolor [turquoise2] [h=00e5ee] +\definecolor [turquoise3] [h=00c5cd] +\definecolor [turquoise4] [h=00868b] +\definecolor [cyan1] [h=00ffff] +\definecolor [cyan2] [h=00eeee] +\definecolor [cyan3] [h=00cdcd] +\definecolor [cyan4] [h=008b8b] +\definecolor [darkslategray1] [h=97ffff] +\definecolor [darkslategray2] [h=8deeee] +\definecolor [darkslategray3] [h=79cdcd] +\definecolor [darkslategray4] [h=528b8b] +\definecolor [aquamarine1] [h=7fffd4] +\definecolor [aquamarine2] [h=76eec6] +\definecolor [aquamarine3] [h=66cdaa] +\definecolor [aquamarine4] [h=458b74] +\definecolor [darkseagreen1] [h=c1ffc1] +\definecolor [darkseagreen2] [h=b4eeb4] +\definecolor [darkseagreen3] [h=9bcd9b] +\definecolor [darkseagreen4] [h=698b69] +\definecolor [seagreen1] [h=54ff9f] +\definecolor [seagreen2] [h=4eee94] +\definecolor [seagreen3] [h=43cd80] +\definecolor [seagreen4] [h=2e8b57] +\definecolor [palegreen1] [h=9aff9a] +\definecolor [palegreen2] [h=90ee90] +\definecolor [palegreen3] [h=7ccd7c] +\definecolor [palegreen4] [h=548b54] +\definecolor [springgreen1] [h=00ff7f] +\definecolor [springgreen2] [h=00ee76] +\definecolor [springgreen3] [h=00cd66] +\definecolor [springgreen4] [h=008b45] +\definecolor [green1] [h=00ff00] +\definecolor [green2] [h=00ee00] +\definecolor [green3] [h=00cd00] +\definecolor [green4] [h=008b00] +\definecolor [chartreuse1] [h=7fff00] +\definecolor [chartreuse2] [h=76ee00] +\definecolor [chartreuse3] [h=66cd00] +\definecolor [chartreuse4] [h=458b00] +\definecolor [olivedrab1] [h=c0ff3e] +\definecolor [olivedrab2] [h=b3ee3a] +\definecolor [olivedrab3] [h=9acd32] +\definecolor [olivedrab4] [h=698b22] +\definecolor [darkolivegreen1] [h=caff70] +\definecolor [darkolivegreen2] [h=bcee68] +\definecolor [darkolivegreen3] [h=a2cd5a] +\definecolor [darkolivegreen4] [h=6e8b3d] +\definecolor [khaki1] [h=fff68f] +\definecolor [khaki2] [h=eee685] +\definecolor [khaki3] [h=cdc673] +\definecolor [khaki4] [h=8b864e] +\definecolor [lightgoldenrod1] [h=ffec8b] +\definecolor [lightgoldenrod2] [h=eedc82] +\definecolor [lightgoldenrod3] [h=cdbe70] +\definecolor [lightgoldenrod4] [h=8b814c] +\definecolor [lightyellow1] [h=ffffe0] +\definecolor [lightyellow2] [h=eeeed1] +\definecolor [lightyellow3] [h=cdcdb4] +\definecolor [lightyellow4] [h=8b8b7a] +\definecolor [yellow1] [h=ffff00] +\definecolor [yellow2] [h=eeee00] +\definecolor [yellow3] [h=cdcd00] +\definecolor [yellow4] [h=8b8b00] +\definecolor [gold1] [h=ffd700] +\definecolor [gold2] [h=eec900] +\definecolor [gold3] [h=cdad00] +\definecolor [gold4] [h=8b7500] +\definecolor [goldenrod1] [h=ffc125] +\definecolor [goldenrod2] [h=eeb422] +\definecolor [goldenrod3] [h=cd9b1d] +\definecolor [goldenrod4] [h=8b6914] +\definecolor [darkgoldenrod1] [h=ffb90f] +\definecolor [darkgoldenrod2] [h=eead0e] +\definecolor [darkgoldenrod3] [h=cd950c] +\definecolor [darkgoldenrod4] [h=8b6508] +\definecolor [rosybrown1] [h=ffc1c1] +\definecolor [rosybrown2] [h=eeb4b4] +\definecolor [rosybrown3] [h=cd9b9b] +\definecolor [rosybrown4] [h=8b6969] +\definecolor [indianred1] [h=ff6a6a] +\definecolor [indianred2] [h=ee6363] +\definecolor [indianred3] [h=cd5555] +\definecolor [indianred4] [h=8b3a3a] +\definecolor [sienna1] [h=ff8247] +\definecolor [sienna2] [h=ee7942] +\definecolor [sienna3] [h=cd6839] +\definecolor [sienna4] [h=8b4726] +\definecolor [burlywood1] [h=ffd39b] +\definecolor [burlywood2] [h=eec591] +\definecolor [burlywood3] [h=cdaa7d] +\definecolor [burlywood4] [h=8b7355] +\definecolor [wheat1] [h=ffe7ba] +\definecolor [wheat2] [h=eed8ae] +\definecolor [wheat3] [h=cdba96] +\definecolor [wheat4] [h=8b7e66] +\definecolor [tan1] [h=ffa54f] +\definecolor [tan2] [h=ee9a49] +\definecolor [tan3] [h=cd853f] +\definecolor [tan4] [h=8b5a2b] +\definecolor [chocolate1] [h=ff7f24] +\definecolor [chocolate2] [h=ee7621] +\definecolor [chocolate3] [h=cd661d] +\definecolor [chocolate4] [h=8b4513] +\definecolor [firebrick1] [h=ff3030] +\definecolor [firebrick2] [h=ee2c2c] +\definecolor [firebrick3] [h=cd2626] +\definecolor [firebrick4] [h=8b1a1a] +\definecolor [brown1] [h=ff4040] +\definecolor [brown2] [h=ee3b3b] +\definecolor [brown3] [h=cd3333] +\definecolor [brown4] [h=8b2323] +\definecolor [salmon1] [h=ff8c69] +\definecolor [salmon2] [h=ee8262] +\definecolor [salmon3] [h=cd7054] +\definecolor [salmon4] [h=8b4c39] +\definecolor [lightsalmon1] [h=ffa07a] +\definecolor [lightsalmon2] [h=ee9572] +\definecolor [lightsalmon3] [h=cd8162] +\definecolor [lightsalmon4] [h=8b5742] +\definecolor [orange1] [h=ffa500] +\definecolor [orange2] [h=ee9a00] +\definecolor [orange3] [h=cd8500] +\definecolor [orange4] [h=8b5a00] +\definecolor [darkorange1] [h=ff7f00] +\definecolor [darkorange2] [h=ee7600] +\definecolor [darkorange3] [h=cd6600] +\definecolor [darkorange4] [h=8b4500] +\definecolor [coral1] [h=ff7256] +\definecolor [coral2] [h=ee6a50] +\definecolor [coral3] [h=cd5b45] +\definecolor [coral4] [h=8b3e2f] +\definecolor [tomato1] [h=ff6347] +\definecolor [tomato2] [h=ee5c42] +\definecolor [tomato3] [h=cd4f39] +\definecolor [tomato4] [h=8b3626] +\definecolor [orangered1] [h=ff4500] +\definecolor [orangered2] [h=ee4000] +\definecolor [orangered3] [h=cd3700] +\definecolor [orangered4] [h=8b2500] +\definecolor [red1] [h=ff0000] +\definecolor [red2] [h=ee0000] +\definecolor [red3] [h=cd0000] +\definecolor [red4] [h=8b0000] +\definecolor [debianred] [h=d70751] +\definecolor [deeppink1] [h=ff1493] +\definecolor [deeppink2] [h=ee1289] +\definecolor [deeppink3] [h=cd1076] +\definecolor [deeppink4] [h=8b0a50] +\definecolor [hotpink1] [h=ff6eb4] +\definecolor [hotpink2] [h=ee6aa7] +\definecolor [hotpink3] [h=cd6090] +\definecolor [hotpink4] [h=8b3a62] +\definecolor [pink1] [h=ffb5c5] +\definecolor [pink2] [h=eea9b8] +\definecolor [pink3] [h=cd919e] +\definecolor [pink4] [h=8b636c] +\definecolor [lightpink1] [h=ffaeb9] +\definecolor [lightpink2] [h=eea2ad] +\definecolor [lightpink3] [h=cd8c95] +\definecolor [lightpink4] [h=8b5f65] +\definecolor [palevioletred1] [h=ff82ab] +\definecolor [palevioletred2] [h=ee799f] +\definecolor [palevioletred3] [h=cd6889] +\definecolor [palevioletred4] [h=8b475d] +\definecolor [maroon1] [h=ff34b3] +\definecolor [maroon2] [h=ee30a7] +\definecolor [maroon3] [h=cd2990] +\definecolor [maroon4] [h=8b1c62] +\definecolor [violetred1] [h=ff3e96] +\definecolor [violetred2] [h=ee3a8c] +\definecolor [violetred3] [h=cd3278] +\definecolor [violetred4] [h=8b2252] +\definecolor [magenta1] [h=ff00ff] +\definecolor [magenta2] [h=ee00ee] +\definecolor [magenta3] [h=cd00cd] +\definecolor [magenta4] [h=8b008b] +\definecolor [orchid1] [h=ff83fa] +\definecolor [orchid2] [h=ee7ae9] +\definecolor [orchid3] [h=cd69c9] +\definecolor [orchid4] [h=8b4789] +\definecolor [plum1] [h=ffbbff] +\definecolor [plum2] [h=eeaeee] +\definecolor [plum3] [h=cd96cd] +\definecolor [plum4] [h=8b668b] +\definecolor [mediumorchid1] [h=e066ff] +\definecolor [mediumorchid2] [h=d15fee] +\definecolor [mediumorchid3] [h=b452cd] +\definecolor [mediumorchid4] [h=7a378b] +\definecolor [darkorchid1] [h=bf3eff] +\definecolor [darkorchid2] [h=b23aee] +\definecolor [darkorchid3] [h=9a32cd] +\definecolor [darkorchid4] [h=68228b] +\definecolor [purple1] [h=9b30ff] +\definecolor [purple2] [h=912cee] +\definecolor [purple3] [h=7d26cd] +\definecolor [purple4] [h=551a8b] +\definecolor [mediumpurple1] [h=ab82ff] +\definecolor [mediumpurple2] [h=9f79ee] +\definecolor [mediumpurple3] [h=8968cd] +\definecolor [mediumpurple4] [h=5d478b] +\definecolor [thistle1] [h=ffe1ff] +\definecolor [thistle2] [h=eed2ee] +\definecolor [thistle3] [h=cdb5cd] +\definecolor [thistle4] [h=8b7b8b] +\definecolor [gray0] [s=0.00] +\definecolor [grey0] [gray0] +\definecolor [gray1] [s=0.01] +\definecolor [grey1] [gray1] +\definecolor [gray2] [s=0.02] +\definecolor [grey2] [gray2] +\definecolor [gray3] [s=0.03] +\definecolor [grey3] [gray3] +\definecolor [gray4] [s=0.04] +\definecolor [grey4] [gray4] +\definecolor [gray5] [s=0.05] +\definecolor [grey5] [gray5] +\definecolor [gray6] [s=0.06] +\definecolor [grey6] [gray6] +\definecolor [gray7] [s=0.07] +\definecolor [grey7] [gray7] +\definecolor [gray8] [s=0.08] +\definecolor [grey8] [gray8] +\definecolor [gray9] [s=0.09] +\definecolor [grey9] [gray9] +\definecolor [gray10] [s=0.10] +\definecolor [grey10] [gray10] +\definecolor [gray11] [s=0.11] +\definecolor [grey11] [gray11] +\definecolor [gray12] [s=0.12] +\definecolor [grey12] [gray12] +\definecolor [gray13] [s=0.13] +\definecolor [grey13] [gray13] +\definecolor [gray14] [s=0.14] +\definecolor [grey14] [gray14] +\definecolor [gray15] [s=0.15] +\definecolor [grey15] [gray15] +\definecolor [gray16] [s=0.16] +\definecolor [grey16] [gray16] +\definecolor [gray17] [s=0.17] +\definecolor [grey17] [gray17] +\definecolor [gray18] [s=0.18] +\definecolor [grey18] [gray18] +\definecolor [gray19] [s=0.19] +\definecolor [grey19] [gray19] +\definecolor [gray20] [s=0.20] +\definecolor [grey20] [gray20] +\definecolor [gray21] [s=0.21] +\definecolor [grey21] [gray21] +\definecolor [gray22] [s=0.22] +\definecolor [grey22] [gray22] +\definecolor [gray23] [s=0.23] +\definecolor [grey23] [gray23] +\definecolor [gray24] [s=0.24] +\definecolor [grey24] [gray24] +\definecolor [gray25] [s=0.25] +\definecolor [grey25] [gray25] +\definecolor [gray26] [s=0.26] +\definecolor [grey26] [gray26] +\definecolor [gray27] [s=0.27] +\definecolor [grey27] [gray27] +\definecolor [gray28] [s=0.28] +\definecolor [grey28] [gray28] +\definecolor [gray29] [s=0.29] +\definecolor [grey29] [gray29] +\definecolor [gray30] [s=0.30] +\definecolor [grey30] [gray30] +\definecolor [gray31] [s=0.31] +\definecolor [grey31] [gray31] +\definecolor [gray32] [s=0.32] +\definecolor [grey32] [gray32] +\definecolor [gray33] [s=0.33] +\definecolor [grey33] [gray33] +\definecolor [gray34] [s=0.34] +\definecolor [grey34] [gray34] +\definecolor [gray35] [s=0.35] +\definecolor [grey35] [gray35] +\definecolor [gray36] [s=0.36] +\definecolor [grey36] [gray36] +\definecolor [gray37] [s=0.37] +\definecolor [grey37] [gray37] +\definecolor [gray38] [s=0.38] +\definecolor [grey38] [gray38] +\definecolor [gray39] [s=0.39] +\definecolor [grey39] [gray39] +\definecolor [gray40] [s=0.40] +\definecolor [grey40] [gray40] +\definecolor [gray41] [s=0.41] +\definecolor [grey41] [gray41] +\definecolor [gray42] [s=0.42] +\definecolor [grey42] [gray42] +\definecolor [gray43] [s=0.43] +\definecolor [grey43] [gray43] +\definecolor [gray44] [s=0.44] +\definecolor [grey44] [gray44] +\definecolor [gray45] [s=0.45] +\definecolor [grey45] [gray45] +\definecolor [gray46] [s=0.46] +\definecolor [grey46] [gray46] +\definecolor [gray47] [s=0.47] +\definecolor [grey47] [gray47] +\definecolor [gray48] [s=0.48] +\definecolor [grey48] [gray48] +\definecolor [gray49] [s=0.49] +\definecolor [grey49] [gray49] +\definecolor [gray50] [s=0.50] +\definecolor [grey50] [gray50] +\definecolor [gray51] [s=0.51] +\definecolor [grey51] [gray51] +\definecolor [gray52] [s=0.52] +\definecolor [grey52] [gray52] +\definecolor [gray53] [s=0.53] +\definecolor [grey53] [gray53] +\definecolor [gray54] [s=0.54] +\definecolor [grey54] [gray54] +\definecolor [gray55] [s=0.55] +\definecolor [grey55] [gray55] +\definecolor [gray56] [s=0.56] +\definecolor [grey56] [gray56] +\definecolor [gray57] [s=0.57] +\definecolor [grey57] [gray57] +\definecolor [gray58] [s=0.58] +\definecolor [grey58] [gray58] +\definecolor [gray59] [s=0.59] +\definecolor [grey59] [gray59] +\definecolor [gray60] [s=0.60] +\definecolor [grey60] [gray60] +\definecolor [gray61] [s=0.61] +\definecolor [grey61] [gray61] +\definecolor [gray62] [s=0.62] +\definecolor [grey62] [gray62] +\definecolor [gray63] [s=0.63] +\definecolor [grey63] [gray63] +\definecolor [gray64] [s=0.64] +\definecolor [grey64] [gray64] +\definecolor [gray65] [s=0.65] +\definecolor [grey65] [gray65] +\definecolor [gray66] [s=0.66] +\definecolor [grey66] [gray66] +\definecolor [gray67] [s=0.67] +\definecolor [grey67] [gray67] +\definecolor [gray68] [s=0.68] +\definecolor [grey68] [gray68] +\definecolor [gray69] [s=0.69] +\definecolor [grey69] [gray69] +\definecolor [gray70] [s=0.70] +\definecolor [grey70] [gray70] +\definecolor [gray71] [s=0.71] +\definecolor [grey71] [gray71] +\definecolor [gray72] [s=0.72] +\definecolor [grey72] [gray72] +\definecolor [gray73] [s=0.73] +\definecolor [grey73] [gray73] +\definecolor [gray74] [s=0.74] +\definecolor [grey74] [gray74] +\definecolor [gray75] [s=0.75] +\definecolor [grey75] [gray75] +\definecolor [gray76] [s=0.76] +\definecolor [grey76] [gray76] +\definecolor [gray77] [s=0.77] +\definecolor [grey77] [gray77] +\definecolor [gray78] [s=0.78] +\definecolor [grey78] [gray78] +\definecolor [gray79] [s=0.79] +\definecolor [grey79] [gray79] +\definecolor [gray80] [s=0.80] +\definecolor [grey80] [gray80] +\definecolor [gray81] [s=0.81] +\definecolor [grey81] [gray81] +\definecolor [gray82] [s=0.82] +\definecolor [grey82] [gray82] +\definecolor [gray83] [s=0.83] +\definecolor [grey83] [gray83] +\definecolor [gray84] [s=0.84] +\definecolor [grey84] [gray84] +\definecolor [gray85] [s=0.85] +\definecolor [grey85] [gray85] +\definecolor [gray86] [s=0.86] +\definecolor [grey86] [gray86] +\definecolor [gray87] [s=0.87] +\definecolor [grey87] [gray87] +\definecolor [gray88] [s=0.88] +\definecolor [grey88] [gray88] +\definecolor [gray89] [s=0.89] +\definecolor [grey89] [gray89] +\definecolor [gray90] [s=0.90] +\definecolor [grey90] [gray90] +\definecolor [gray91] [s=0.91] +\definecolor [grey91] [gray91] +\definecolor [gray92] [s=0.92] +\definecolor [grey92] [gray92] +\definecolor [gray93] [s=0.93] +\definecolor [grey93] [gray93] +\definecolor [gray94] [s=0.94] +\definecolor [grey94] [gray94] +\definecolor [gray95] [s=0.95] +\definecolor [grey95] [gray95] +\definecolor [gray96] [s=0.96] +\definecolor [grey96] [gray96] +\definecolor [gray97] [s=0.97] +\definecolor [grey97] [gray97] +\definecolor [gray98] [s=0.98] +\definecolor [grey98] [gray98] +\definecolor [gray99] [s=0.99] +\definecolor [grey99] [gray99] +\definecolor [gray100] [s=1.00] +\definecolor [grey100] [gray100] +\definecolor [darkgrey] [s=0.66] +\definecolor [darkgray] [darkgrey] +\definecolor [darkblue] [h=00008b] +\definecolor [darkcyan] [h=008b8b] +\definecolor [darkmagenta] [h=8b008b] +\definecolor [darkred] [h=8b0000] +\definecolor [lightgreen] [h=90ee90] + +\endinput diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 35b716ed4..93a1c17c2 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -25,6 +25,8 @@ % % \setbreakpoints[compound] +\ctxlua{logs.report=function(s,...) commands.writestatus("!"..s,...) end} + \unprotect % % % % % % needs testing but saves runtime diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex index 1eecb06fe..b6b633877 100644 --- a/tex/context/base/cont-new.tex +++ b/tex/context/base/cont-new.tex @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2009.11.13 12:45} +\newcontextversion{2009.11.18 21:51} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex index 95b945f26..76233c43d 100644 --- a/tex/context/base/context.tex +++ b/tex/context/base/context.tex @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2009.11.13 12:45} +\edef\contextversion{2009.11.18 21:51} %D For those who want to use this: diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv index d3d24acd7..bc1b6b2bf 100644 --- a/tex/context/base/core-def.mkiv +++ b/tex/context/base/core-def.mkiv @@ -61,6 +61,8 @@ \appendtoks \the\everybackendshipout \to \everyshipout \prependtoks \the\everylastbackendshipout \to \everylastshipout +\prependtoks \lefttoright \to \everybeforeoutput + % temporary here: \ifdefined\in \let\normalmathin \in \unexpanded\def\in {\mathortext\normalmathin \dospecialin } \else \let\in \dospecialin \fi diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua index 7181f5a17..9964af421 100644 --- a/tex/context/base/data-res.lua +++ b/tex/context/base/data-res.lua @@ -544,11 +544,11 @@ function resolvers.identify_cnf() end local function load_cnf_file(fname) + -- why don't we just read the file from the cache + -- we need to switch to the lua file fname = resolvers.clean_path(fname) local lname = file.replacesuffix(fname,'lua') - local f = io.open(lname) - if f then -- this will go - f:close() + if lfs.isfile(lname) then local dname = file.dirname(fname) if not instance.configuration[dname] then resolvers.load_data(dname,'configuration',lname and file.basename(lname)) @@ -613,13 +613,17 @@ local function collapse_cnf_data() -- potential optimization: pass start index ( end end -function resolvers.load_cnf() - local function loadoldconfigdata() - for _, fname in ipairs(instance.cnffiles) do - load_cnf_file(fname) - end +local function loadoldconfigdata() + for _, fname in ipairs(instance.cnffiles) do + load_cnf_file(fname) end +end + +function resolvers.load_cnf() -- instance.cnffiles contain complete names now ! + -- we still use a funny mix of cnf and new but soon + -- we will switch to lua exclusively as we only use + -- the file to collect the tree roots if #instance.cnffiles == 0 then if trace_verbose then logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)") @@ -982,6 +986,7 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl date = os.date("%Y-%m-%d"), time = os.date("%H:%M:%S"), content = files, + uuid = os.uuid(), } local ok = io.savedata(luaname,resolvers.serialize(data)) if ok then @@ -1004,6 +1009,12 @@ function resolvers.save_data(dataname, makename) -- untested without cache overl end end +local data_state = { } + +function resolvers.data_state() + return data_state or { } +end + function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload filename = ((not filename or (filename == "")) and dataname) or filename filename = (makename and makename(dataname,filename)) or file.join(pathname,filename) @@ -1011,6 +1022,7 @@ function resolvers.load_data(pathname,dataname,filename,makename) -- untested wi if blob then local data = blob() if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then + data_state[#data_state+1] = data.uuid if trace_verbose then logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename) end @@ -1846,9 +1858,9 @@ function resolvers.load(option) statistics.starttiming(instance) resolvers.resetconfig() resolvers.identify_cnf() - resolvers.load_lua() + resolvers.load_lua() -- will become the new method resolvers.expand_variables() - resolvers.load_cnf() + resolvers.load_cnf() -- will be skipped when we have a lua file resolvers.expand_variables() if option ~= "nofiles" then resolvers.load_hash() diff --git a/tex/context/base/data-tmp.lua b/tex/context/base/data-tmp.lua index 802af6e4e..ba338b5a4 100644 --- a/tex/context/base/data-tmp.lua +++ b/tex/context/base/data-tmp.lua @@ -157,6 +157,7 @@ function caches.savedata(filepath,filename,data,raw) if raw then reduce, simplify = false, false end + data.cache_uuid = os.uuid() if caches.direct then file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex else diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua index 72b36600c..2ba73be26 100644 --- a/tex/context/base/font-afm.lua +++ b/tex/context/base/font-afm.lua @@ -720,7 +720,8 @@ function tfm.read_from_afm(specification) if filename then tfmtable.encodingbytes = 2 tfmtable.filename = resolvers.findbinfile(filename,"") or filename - tfmtable.fullname = afmdata.metadata.fontname or afmdata.metadata.fullname + tfmtable.fontname = afmdata.metadata.fontname or afmdata.metadata.fullname + tfmtable.fullname = afmdata.metadata.fullname or afmdata.metadata.fontname tfmtable.format = 'type1' tfmtable.name = afmdata.luatex.filename or tfmtable.fullname end diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index c18fbe0ff..3845ae5b9 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -405,9 +405,9 @@ local dimenfactors = number.dimenfactors function fonts.dimenfactor(unit,tfmdata) if unit == "ex" then - return tfmdata.parameters.x_height + return (tfmdata and tfmdata.parameters.x_height) or 655360 elseif unit == "em" then - return tfmdata.parameters.em_height + return (tfmdata and tfmdata.parameters.em_height) or 655360 else return dimenfactors[unit] or unit end diff --git a/tex/context/base/font-dum.lua b/tex/context/base/font-dum.lua index c585c18b5..d6fee5598 100644 --- a/tex/context/base/font-dum.lua +++ b/tex/context/base/font-dum.lua @@ -39,10 +39,15 @@ function fonts.logger.save() end -- names +-- +-- Watch out, the version number is the same as the one used in +-- the mtx-fonts.lua function scripts.fonts.names as we use a +-- simplified font database in the plain solution and by using +-- a different number we're less dependent on context. fonts.names = fonts.names or { } -fonts.names.version = 1.014 +fonts.names.version = 1.001 -- not the same as in context fonts.names.basename = "luatex-fonts-names.lua" fonts.names.new_to_old = { } fonts.names.old_to_new = { } @@ -57,16 +62,6 @@ function fonts.names.resolve(name,sub) local foundname = resolvers.find_file(basename,format) or "" if foundname ~= "" then data = dofile(foundname) - if data then - local d = { } - for k, v in pairs(data.mapping) do - local t = v[1] - if t == "ttf" or t == "otf" or t == "ttc" or t == "dfont" then - d[k] = v - end - end - data.mapping = d - end break end end @@ -77,9 +72,12 @@ function fonts.names.resolve(name,sub) local condensed = string.gsub(string.lower(name),"[^%a%d]","") local found = data.mapping and data.mapping[condensed] if found then - local filename, is_sub = found[3], found[4] - if is_sub then is_sub = found[2] end - return filename, is_sub + local fontname, filename, subfont = found[1], found[2], found[3] + if subfont then + return filename, fontname + else + return filename, false + end else return name, false -- fallback to filename end diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv index 3ce821a39..e36485319 100644 --- a/tex/context/base/font-ini.mkiv +++ b/tex/context/base/font-ini.mkiv @@ -4010,6 +4010,28 @@ \def\showchardata#1{\ctxlua{fonts.show_char_data("#1")}} \def\showfontdata {\ctxlua{fonts.show_font_parameters()}} +%D some low level helpers +%D +%D \starttyping +%D \def\TestLookup#1% +%D {pattern: #1, found: \dolookupnoffound +%D \blank +%D \dolookupfontbyspec{#1} +%D \dorecurse {\dolookupnoffound} {% +%D \recurselevel:~\dolookupgetkeyofindex{fontname}{\recurselevel}\quad +%D }% +%D \blank} +%D +%D \TestLookup{familyname=helveticaneue} +%D \TestLookup{familyname=helveticaneue,weight=bold} +%D \TestLookup{familyname=helveticaneue,weight=bold,style=italic} +%D \stoptyping + +\def\dolookupfontbyspec #1{\ctxlua{fonts.names.lookup("#1")}} +\def\dolookupnoffound {\ctxlua{tex.write(fonts.names.noflookups())}} +\def\dolookupgetkeyofindex#1#2{\ctxlua{tex.write(fonts.names.getlookupkey("#1",#2))}} +\def\dolookupgetkey #1{\ctxlua{tex.write(fonts.names.getlookupkey("#1"))}} + \protect \endinput % \startluacode diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua index dc60cf2a2..40160e49d 100644 --- a/tex/context/base/font-mis.lua +++ b/tex/context/base/font-mis.lua @@ -35,7 +35,7 @@ end function fonts.get_features(name,t,script,language) local t = lower(t or (name and file.extname(name)) or "") - if t == "otf" or t == "ttf" or t == "ttc" then + if t == "otf" or t == "ttf" or t == "ttc" or t == "dfont" then local filename = resolvers.find_file(name,t) or "" if filename ~= "" then local data = fonts.otf.loadcached(filename) diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index b5f7cb431..7929dfb02 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -1497,8 +1497,9 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th tfm.units = metadata.units_per_em or 1000 -- we need a runtime lookup because of running from cdrom or zip, brrr tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename - tfm.fullname = metadata.fontname or metadata.fullname - tfm.psname = tfm.fullname + tfm.fullname = metadata.fullname + tfm.fontname = metadata.fontname + tfm.psname = tfm.fontname or tfm.fullname tfm.encodingbytes = 2 tfm.cidinfo = data.cidinfo tfm.cidinfo.registry = tfm.cidinfo.registry or "" @@ -1622,7 +1623,8 @@ function tfm.read_from_open_type(specification) if filename then tfmtable.encodingbytes = 2 tfmtable.filename = resolvers.findbinfile(filename,"") or filename - tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname + tfmtable.fontname = tfmtable.fontname or otfdata.metadata.fontname + tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fullname or tfmtable.fontname local order = otfdata and otfdata.metadata.order2 if order == 0 then tfmtable.format = 'opentype' @@ -1631,7 +1633,7 @@ function tfm.read_from_open_type(specification) else tfmtable.format = specification.format end - tfmtable.name = tfmtable.filename or tfmtable.fullname + tfmtable.name = tfmtable.filename or tfmtable.fullname or tfmtable.fontname end fonts.logger.save(tfmtable,file.extname(specification.filename),specification) end diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index 77d67d4b5..fb04b367e 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -117,7 +117,7 @@ results in different tables.</p> -- remark: the 'not implemented yet' variants will be done when we have fonts that use them -- remark: we need to check what to do with discretionaries -local concat = table.concat +local concat, insert, remove = table.concat, table.insert, table.remove local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip local type, next, tonumber, tostring = type, next, tonumber, tostring @@ -139,6 +139,7 @@ local trace_details = false trackers.register("otf.details", function local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end) local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end) local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end) +local trace_directions = false trackers.register("otf.directions", function(v) trace_directions = v end) trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) @@ -743,7 +744,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to if exit then local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) + logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) end done = true break @@ -1395,7 +1396,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache, if exit then local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) + logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) end done = true break @@ -1832,6 +1833,9 @@ local resolved = { } -- we only resolve a font,script,language pair once -- todo: pass all these 'locals' in a table +-- maybe some day i'll make an alternative that works on 'sub direction runs' which might be +-- more efficient for arabic but it has quite some consequences + function fonts.methods.node.otf.features(head,font,attr) if trace_steps then checkstep(head) @@ -1875,6 +1879,7 @@ function fonts.methods.node.otf.features(head,font,attr) local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false -- sequences always > 1 so no need for optimization for s=1,#sequences do + local pardir, txtdir = 0, { } local success = false local sequence = sequences[s] local r = ra[s] -- cache @@ -1974,7 +1979,7 @@ function fonts.methods.node.otf.features(head,font,attr) local ns = #subtables local thecache = featuredata[typ] or { } start = head -- local ? - rlmode = 0 + rlmode = 0 -- to be checked ? if ns == 1 then local lookupname = subtables[1] local lookupcache = thecache[lookupname] @@ -2016,24 +2021,57 @@ function fonts.methods.node.otf.features(head,font,attr) -- start = start.next -- end elseif id == whatsit then +--~ if subtype == 7 then +--~ local dir = start.dir +--~ if dir == "+TRT" then +--~ rlmode = -1 +--~ elseif dir == "+TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ elseif subtype == 6 then +--~ local dir = start.dir +--~ if dir == "TRT" then +--~ rlmode = -1 +--~ elseif dir == "TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ end local subtype = start.subtype if subtype == 7 then local dir = start.dir - if dir == "+TRT" then + if dir == "+TRT" or dir == "+TLT" then + insert(txtdir,dir) + elseif dir == "-TRT" or dir == "-TLT" then + remove(txtdir) + end + local d = txtdir[#txtdir] + if d == "+TRT" then rlmode = -1 - elseif dir == "+TLT" then + elseif d == "+TLT" then rlmode = 1 else - rlmode = 0 + rlmode = pardir + end + if trace_directions then + logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end elseif subtype == 6 then local dir = start.dir if dir == "TRT" then - rlmode = -1 + pardir = -1 elseif dir == "TLT" then - rlmode = 1 + pardir = 1 else - rlmode = 0 + pardir = 0 + end + rlmode = pardir + --~ txtdir = { } + if trace_directions then + logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end end start = start.next @@ -2041,7 +2079,6 @@ function fonts.methods.node.otf.features(head,font,attr) start = start.next end end - end else while start do @@ -2088,25 +2125,59 @@ function fonts.methods.node.otf.features(head,font,attr) -- end elseif id == whatsit then local subtype = start.subtype - if subtype == 7 then - local dir = start.dir - if dir == "+TRT" then - rlmode = -1 - elseif dir == "+TLT" then - rlmode = 1 - else - rlmode = 0 +--~ if subtype == 7 then +--~ local dir = start.dir +--~ if dir == "+TRT" then +--~ rlmode = -1 +--~ elseif dir == "+TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ elseif subtype == 6 then +--~ local dir = start.dir +--~ if dir == "TRT" then +--~ rlmode = -1 +--~ elseif dir == "TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ end + local subtype = start.subtype + if subtype == 7 then + local dir = start.dir + if dir == "+TRT" or dir == "+TLT" then + insert(txtdir,dir) + elseif dir == "-TRT" or dir == "-TLT" then + remove(txtdir) + end + local d = txtdir[#txtdir] + if d == "+TRT" then + rlmode = -1 + elseif d == "+TLT" then + rlmode = 1 + else + rlmode = pardir + end + if trace_directions then + logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) + end + elseif subtype == 6 then + local dir = start.dir + if dir == "TRT" then + pardir = -1 + elseif dir == "TLT" then + pardir = 1 + else + pardir = 0 + end + rlmode = pardir + --~ txtdir = { } + if trace_directions then + logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end - elseif subtype == 6 then - local dir = start.dir - if dir == "TRT" then - rlmode = -1 - elseif dir == "TLT" then - rlmode = 1 - else - rlmode = 0 end - end start = start.next else start = start.next diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua index f2b86a48a..96b5fe870 100644 --- a/tex/context/base/font-pat.lua +++ b/tex/context/base/font-pat.lua @@ -95,17 +95,18 @@ end patches["palatino.*arabic"] = patch -local function patch(data,filename) +local function patch_domh(data,filename,threshold) local m = data.math if m then local d = m.DisplayOperatorMinHeight or 0 - if d < 2800 then + if d < threshold then if trace_loading then - logs.report("load otf","patching DisplayOperatorMinHeight(%s -> 2800)",d) + logs.report("load otf","patching DisplayOperatorMinHeight(%s -> %s)",d,threshold) end - m.DisplayOperatorMinHeight = 2800 + m.DisplayOperatorMinHeight = threshold end end end -patches["cambria"] = patch +patches["cambria"] = function(data,filename) patch_domh(data,filename,2800) end +patches["asana"] = function(data,filename) patch_domh(data,filename,1350) end diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua index f184fe2e5..0b74cc73c 100644 --- a/tex/context/base/font-syn.lua +++ b/tex/context/base/font-syn.lua @@ -6,8 +6,11 @@ if not modules then modules = { } end modules ['font-syn'] = { license = "see context related readme files" } -local next = next +-- todo: subs in lookups requests + +local next, tonumber = next, tonumber local gsub, lower, match, find, lower, upper = string.gsub, string.lower, string.match, string.find, string.lower, string.upper +local find, gmatch = string.find, string.gmatch local concat, sort, format = table.concat, table.sort, string.format local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end) @@ -30,7 +33,7 @@ fonts.names.data = fonts.names.data or { } local names = fonts.names local filters = fonts.names.filters -names.version = 1.014 -- when adapting this, also changed font-dum.lua +names.version = 1.100 names.basename = "names" names.saved = false names.loaded = false @@ -40,6 +43,91 @@ names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_A names.cache = containers.define("fonts","data",names.version,true) --[[ldx-- +<p>A few helpers.</p> +--ldx]]-- + +local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg + +local weights = Cs ( -- not extra + P("demibold") + + P("semibold") + + P("mediumbold") + + P("ultrabold") + + P("extrabold") + + P("ultralight") + + P("bold") + + P("demi") + + P("semi") + + P("light") + + P("medium") + + P("heavy") + + P("ultra") + + P("black") + + P("bol") + + P("regular") / "normal" +) + +local styles = Cs ( + P("reverseoblique") / "reverseitalic" + + P("regular") / "normal" + + P("italic") + + P("oblique") / "italic" + + P("slanted") + + P("roman") / "normal" + + P("ital") / "italic" + + P("ita") / "italic" +) + +local widths = Cs( + P("condensed") + + P("thin") + + P("expanded") + + P("cond") / "condensed" + + P("normal") + + P("book") / "normal" +) + +local any = P(1) + +local analysed_table + +local analyser = Cs ( + ( + weights / function(s) analysed_table[1] = s return "" end + + styles / function(s) analysed_table[2] = s return "" end + + widths / function(s) analysed_table[3] = s return "" end + + any + )^0 +) + +local splitter = lpeg.splitat("-") + +function names.splitspec(askedname) + local name, weight, style, width = splitter:match(askedname) + weight = weight and weights:match(weight) or weight + style = style and styles :match(style) or style + width = width and widths :match(width) or width + if trace_names then + logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s' and width '%s'",askedname,name or '',weight or '',style or '',width or '') + end + if not weight or not weight or not width then + weight, style, width = weight or "normal", style or "normal", width or "normal" + if trace_names then + logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s'",askedname,name,weight,style,width) + end + end + return name or askedname, weight, style, width +end + +local function analysespec(somename) + if somename then + analysed_table = { } + local name = analyser:match(somename) + return name, analysed_table[1], analysed_table[2],analysed_table[3] + end +end + +--[[ldx-- <p>It would make sense to implement the filters in the related modules, but to keep the overview, we define them here.</p> --ldx]]-- @@ -104,16 +192,6 @@ filters.list = { "otf", "ttf", "ttc", "dfont", "afm", } -filters.fixes = { -- can be lpeg - { "bolita$", "bolditalic", }, - { "ital$", "italic", }, - { "cond$", "condensed", }, - { "book$", "", }, - { "reg$", "regular", }, - { "ita$", "italic", }, - { "bol$", "bold", }, -} - names.xml_configuration_file = "fonts.conf" -- a bit weird format, bonus feature names.environment_path_variable = "OSFONTDIR" -- the official way, in minimals etc @@ -149,7 +227,7 @@ function names.getpaths(trace) end end if name ~= "" and lfs.isfile(name) then - if trace then + if trace_names then logs.report("fontnames","loading fontconfig file: %s",name) end local xmldata = xml.load(name) @@ -162,17 +240,17 @@ function names.getpaths(trace) end end if lfs.isfile(incname) then - if trace then + if trace_names then logs.report("fontnames","merging included fontconfig file: %s",incname) end return io.loaddata(incname) - elseif trace then + elseif trace_names then logs.report("fontnames","ignoring included fontconfig file: %s",incname) end end) -- end of untested mess local fontdirs = xml.collect_texts(xmldata,"dir",true) - if trace then + if trace_names then logs.report("fontnames","%s dirs found in fontconfig",#fontdirs) end collect(fontdirs) @@ -185,77 +263,299 @@ function names.getpaths(trace) return result end -function names.cleanname(name) +local function cleanname(name) return (gsub(lower(name),"[^%a%d]","")) end -function names.identify(verbose) -- lsr is for kpse - names.data = { - version = names.version, - mapping = { }, - -- sorted = { }, - fallback_mapping = { }, - -- fallback_sorted = { }, +names.cleanname = cleanname + +local function check_names(result) + local names = result.names + if names then + for i=1,#names do + local name = names[i] + if name.lang == "English (US)" then + return name.names + end + end + end +end + +local function walk_tree(pathlist,suffix,identify) + if pathlist then + for _, path in ipairs(pathlist) do + path = resolvers.clean_path(path .. "/") + path = gsub(path,"/+","/") + local pattern = path .. "**." .. suffix -- ** forces recurse + logs.report("fontnames", "globbing path %s",pattern) + local t = dir.glob(pattern) + for _, completename in pairs(t) do -- ipairs + identify(completename,file.basename(completename),suffix,completename) + end + end + end +end + +local function check_name(data,result,filename,suffix,subfont) + -- shortcuts + local specifications = data.specifications + local families = data.families + -- prepare + local names = check_names(result) + -- fetch + local familyname = (names and names.preffamilyname) or result.familyname + local fullname = (names and names.fullname) or result.fullname + local fontname = result.fontname + local subfamily = (names and names.subfamily) + local modifiers = (names and names.prefmodifiers) + local weight = (names and names.weight) or result.weight + local italicangle = tonumber(result.italicangle) + local subfont = subfont or nil + local rawname = fullname or fontname or familyname + -- normalize + familyname = familyname and cleanname(familyname) + fullname = fullname and cleanname(fullname) + fontname = fontname and cleanname(fontname) + subfamily = subfamily and cleanname(subfamily) + modifiers = modifiers and cleanname(modifiers) + weight = weight and cleanname(weight) + italicangle = (italicangle == 0) and nil + -- analyse + local a_name, a_weight, a_style, a_width = analysespec(fullname or fontname or familyname) + -- check + local width = a_width + local style = modifiers and gsub(modifiers,"[^%a]","") + if not style and italicangle then + style = "italic" + end + if not weight or weight == "" then + weight = a_weight + end + if not style or style == "" then + style = a_style + end + if not familyname then + familyname = a_name + end + fontname = fontname or fullname or familyname or basename + fullname = fullname or fontname + familyname = familyname or fontname + -- register + local index = #specifications + 1 + specifications[index] = { + filename = filename, + format = lower(suffix), + subfont = subfont, + rawname = rawname, + familyname = familyname, + fullname = fullname, + fontname = fontname, + subfamily = subfamily, + modifiers = modifiers, + weight = weight, + style = style, + width = width, } - local done, mapping, fallback_mapping, nofread, nofok = { }, names.data.mapping, names.data.fallback_mapping, 0, 0 - local cleanname = names.cleanname - local function check(result, filename, suffix, is_sub) -- unlocal this one - local fontname = result.fullname - if fontname then - local n = cleanname(result.fullname) - if not mapping[n] then - mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 - end - end - if result.fontname then - fontname = result.fontname or fontname - local n = cleanname(result.fontname) - if not mapping[n] then - mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 - end - end - if result.familyname and result.weight and result.italicangle == 0 then - local madename = result.familyname .. " " .. result.weight - fontname = madename or fontname - local n = cleanname(fontname) - if not mapping[n] and not fallback_mapping[n] then - fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 - end - end - if result.names then - for k, v in ipairs(result.names) do - local lang, names = v.lang, v.names - if lang == "English (US)" then - local family, subfamily, fullnamet = names.family, names.subfamily, names.fullname - local preffamilyname, prefmodifiers, weight = names.preffamilyname, names.prefmodifiers, names.weight - if preffamilyname then - if subfamily then - local n = cleanname(preffamilyname .. " " .. subfamily) - if not mapping[n] and not fallback_mapping[n] then - fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 - end - end - -- okay? - local n = cleanname(preffamilyname) - if not mapping[n] and not fallback_mapping[n] then - fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1 + local family = families[familyname] + if not family then + families[familyname] = { index } + else + family[#family+1] = index + end +end + +local function cleanupkeywords() + local data = names.data + local specifications = names.data.specifications + if specifications then + local weights, styles, widths, variants = { }, { }, { }, { } + for i=1,#specifications do + local s = specifications[i] + -- fix (sofar styles are taken from the name, and widths from the specification) + local b_variant, b_weight, b_style, b_width = analysespec(s.weight) + local c_variant, c_weight, c_style, c_width = analysespec(s.style) + local d_variant, d_weight, d_style, d_width = analysespec(s.width) + local e_variant, e_weight, e_style, e_width = analysespec(s.fullname or "") + local weight = b_weight or c_weight or d_weight or e_weight or "normal" + local style = b_style or c_style or d_style or e_style or "normal" + local width = b_width or c_width or d_width or e_width or "normal" + local variant = b_variant or c_variant or d_variant or e_variant or "normal" + if weight then weights [weight ] = (weights [weight ] or 0) + 1 end + if style then styles [style ] = (styles [style ] or 0) + 1 end + if width then widths [width ] = (widths [width ] or 0) + 1 end + if variant then variants[variant] = (variants[variant] or 0) + 1 end + if weight ~= s.weight then + s.fontweight = s.weight + end + s.weight, s.style, s.width, s.variant = weight, style, width, variant + end + local stats = data.statistics + stats.used_weights, stats.used_styles, stats.used_widths, stats.used_variants = weights, styles, widths, variants + end +end + +local function collectstatistics() + local data = names.data + local specifications = data.specifications + if specifications then + local weights, styles, widths = { }, { }, { } + for i=1,#specifications do + local s = specifications[i] + local weight, style, width = s.weight, s.style, s.width + if weight then weights[weight] = (weights[weight] or 0) + 1 end + if style then styles [style ] = (styles [style ] or 0) + 1 end + if width then widths [width ] = (widths [width ] or 0) + 1 end + end + local stats = data.statistics + stats.weights, stats.styles, stats.widths, stats.fonts = weights, styles, widths, #specifications + end +end + +local function collecthashes() + local data = names.data + local mappings = data.mappings + local fallbacks = data.fallbacks + local specifications = data.specifications + local nofmappings, noffallbacks = 0, 0 + if specifications then + for index=1,#specifications do + local s = specifications[index] + local format, fullname, fontname, familyname, weight, subfamily = s.format, s.fullname, s.fontname, s.familyname, s.weight, s.subfamily + local mf, ff = mappings[format], fallbacks[format] + if fullname and not mf[fullname] then + mf[fullname], nofmappings = index, nofmappings + 1 + end + if fontname and not mf[fontname] then + mf[fontname], nofmappings = index, nofmappings + 1 + end + if familyname and weight then + local madename = familyname .. weight + if not mf[madename] and not ff[madename] then + ff[madename], noffallbacks = index, noffallbacks + 1 + end + end + if familyname and subfamily then + local extraname = familyname .. subfamily + if not mf[extraname] and not ff[extraname] then + ff[extraname], noffallbacks = index, noffallbacks + 1 + end + end + if familyname and subfamily then + if not mf[familyname] and not ff[familyname] then + ff[familyname], noffallbacks = index, noffallbacks + 1 + end + end + end + end + return nofmappings, noffallbacks +end + +local function checkduplicate(mapping) -- fails on "Romantik" but that's a border case anyway + local data = names.data + local mapping = data[mapping] + local specifications, loaded = data.specifications, { } + if specifications and mapping then + for _, m in next, mapping do + for k, v in next, m do + local s = specifications[v] + local hash = format("%s-%s-%s-%s",s.familyname,s.weight or "*",s.style or "*",s.width or "*") + local h = loaded[hash] + if h then + local ok = true + local fn = s.filename + for i=1,#h do + local hn = s.filename + if h[i] == fn then + ok = false + break end end + if ok then + h[#h+1] = fn + end + else + loaded[hash] = { s.filename } end end end end - local trace = verbose or trace_names - local skip_paths = filters.paths - local skip_names = filters.names + for k, v in table.sortedpairs(loaded) do + if #v > 1 then + logs.report("fontnames", "double lookup: %s => %s",k,concat(v," | ")) + end + end +end + +local function checkduplicates() + checkduplicate("mappings") + checkduplicate("fallbacks") +end + +local sorter = function(a,b) + return #a < #b and a < b +end + +local function sorthashes() + local data, list = names.data, filters.list + local mappings, fallbacks, sorted_mappings, sorted_fallbacks = data.mappings, data.fallbacks, { }, { } + data.sorted_mappings, data.sorted_fallbacks = sorted_mappings, sorted_fallbacks + for i=1,#list do + local l = list[i] + sorted_mappings[l], sorted_fallbacks[l] = table.keys(mappings[l]), table.keys(fallbacks[l]) + sort(sorted_mappings[l],sorter) + sort(sorted_fallbacks[l],sorter) + end + data.sorted_families = table.keys(data.families) + sort(data.sorted_families,sorter) +end + +local function unpackreferences() + local data = names.data + local specifications = data.specifications + if specifications then + for k, v in next, data.families do + for i=1,#v do + v[i] = specifications[v[i]] + end + end + end + local mappings = data.mappings + if mappings then + for _, m in next, mappings do + for k, v in next, m do + m[k] = specifications[v] + end + end + end + local fallbacks = data.fallbacks + if fallbacks then + for _, f in next, fallbacks do + for k, v in next, f do + f[k] = specifications[v] + end + end + end +end + +local function analysefiles() + local data = names.data + local done, totalnofread, totalnofskipped = { }, 0, 0 + local skip_paths, skip_names = filters.paths, filters.names local function identify(completename,name,suffix,storedname) - if not done[name] and io.exists(completename) then + local basename = file.basename(completename) + local basepath = file.dirname(completename) + if done[name] then + -- already done (avoid otf afm clash) + elseif not io.exists(completename) then + -- weird error + elseif not file.is_qualified_path(completename) and resolvers.find_file(completename,suffix) == "" then + -- not locateble by backend anyway + else nofread = nofread + 1 if #skip_paths > 0 then - local path = file.dirname(completename) for i=1,#skip_paths do - if find(path,skip_paths[i]) then - if trace then + if find(basepath,skip_paths[i]) then + if trace_names then logs.report("fontnames","rejecting path of %s font %s",suffix,completename) logs.push() end @@ -264,11 +564,10 @@ function names.identify(verbose) -- lsr is for kpse end end if #skip_names > 0 then - local base = file.basename(completename) for i=1,#skip_paths do - if find(base,skip_names[i]) then + if find(basename,skip_names[i]) then done[name] = true - if trace then + if trace_names then logs.report("fontnames","rejecting name of %s font %s",suffix,completename) logs.push() end @@ -281,15 +580,21 @@ function names.identify(verbose) -- lsr is for kpse logs.push() end local result, message = filters[lower(suffix)](completename) - if trace then + if trace_names then logs.pop() end if result then if not result[1] then - check(result,storedname,suffix,false) -- was name + local ok = check_name(data,result,storedname,suffix) + if not ok then + nofskipped = nofskipped + 1 + end else for r=1,#result do - check(result[r],storedname,suffix,true) -- was name + local ok = check_name(data,result[r],storedname,suffix,r-1) -- subfonts start at zero + if not ok then + nofskipped = nofskipped + 1 + end end end if message and message ~= "" then @@ -301,33 +606,19 @@ function names.identify(verbose) -- lsr is for kpse done[name] = true end end - local totalread, totalok = 0, 0 local function traverse(what, method) for n, suffix in ipairs(filters.list) do - nofread, nofok = 0, 0 local t = os.gettimeofday() -- use elapser + nofread, nofskipped = 0, 0 suffix = lower(suffix) logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix) method(suffix) suffix = upper(suffix) logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix) method(suffix) - logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofok,os.gettimeofday()-t) - totalread, totalok = totalread + nofread, totalok + nofok - end - end - local function walk_tree(pathlist,suffix) - if pathlist then - for _, path in ipairs(pathlist) do - path = resolvers.clean_path(path .. "/") - path = gsub(path,"/+","/") - local pattern = path .. "**." .. suffix -- ** forces recurse - logs.report("fontnames", "globbing path %s",pattern) - local t = dir.glob(pattern) - for _, completename in pairs(t) do -- ipairs - identify(completename,file.basename(completename),suffix,completename) - end - end + totalnofread, totalnofskipped = totalnofread + nofread, totalnofskipped + nofskipped + local elapsed = os.gettimeofday() - t + logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofread-nofskipped,elapsed) end end traverse("tree", function(suffix) -- TEXTREE only @@ -343,43 +634,42 @@ function names.identify(verbose) -- lsr is for kpse -- using the vars is to clumsy so we just stick to a full scan instead traverse("lsr", function(suffix) -- all trees local pathlist = resolvers.split_path(resolvers.show_path("ls-R") or "") - walk_tree(pathlist,suffix) + walk_tree(pathlist,suffix,identify) end) else traverse("system", function(suffix) -- OSFONTDIR cum suis - walk_tree(names.getpaths(trace),suffix) + walk_tree(names.getpaths(trace),suffix,identify) end) end - local t = { } - for _, f in ipairs(filters.fixes) do - local expression, replacement = f[1], f[2] - for k,v in next, mapping do - local fix, pos = gsub(k,expression,replacement) - if pos > 0 and not mapping[fix] then - t[fix] = v - end - end - end - local n = 0 - for k,v in next, t do - mapping[k] = v - n = n + 1 - end - local rejected = 0 - for k, v in next, mapping do - local kind, filename = v[1], v[3] - if not file.is_qualified_path(filename) and resolvers.find_file(filename,kind) == "" then - mapping[k] = nil - rejected = rejected + 1 - end - end - if n > 0 then - logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,n,rejected,totalok+n-rejected) + data.statistics.readfiles, data.statistics.skippedfiles = totalnofread, totalnofskipped +end + +local function resetdata() + local mappings, fallbacks = { }, { } + for _, k in next, filters.list do + mappings[k], fallbacks[k] = { }, { } end - names.analyse(mapping) - names.analyse(fallback_mapping) - names.checkduplicates(mapping) - names.checkduplicates(fallback_mapping) + names.data = { + version = names.version, + mappings = mappings, + fallbacks = fallbacks, + specifications = { }, + families = { }, + statistics = { }, + data_state = resolvers.data_state(), + } +end + +function names.identify() + resetdata() + analysefiles() + collectstatistics() + cleanupkeywords() + collecthashes() + checkduplicates() + -- sorthashes() -- will be resorted when saved + + --~ logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,added,rejected,totalok+added-rejected) end function names.is_permitted(name) @@ -392,120 +682,6 @@ function names.read_data(name) return containers.read(names.cache(),name) end -local sorter = function(a,b) return #a < #b and a < b end - -function names.sorted(t) - local s = table.keys(t or { }) or { } - sort(s,sorted) - return s -end - ---~ local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc ---~ ---~ local weight = C(P("demibold") + P("semibold") + P("mediumbold") + P("ultrabold") + P("bold") + P("demi") + P("semi") + P("light") + P("medium") + P("heavy") + P("ultra") + P("black")) ---~ local style = C(P("regular") + P("italic") + P("oblique") + P("slanted") + P("roman") + P("ital")) ---~ local width = C(P("condensed") + P("normal") + P("expanded") + P("cond")) ---~ local special = P("roman") ---~ local reserved = style + weight + width ---~ local any = (1-reserved) ---~ local name = C((special + any)^1) ---~ local crap = any^0 ---~ local dummy = Cc(false) ---~ local normal = Cc("normal") ---~ local analyser = name * (weight + normal) * crap * (style + normal) * crap * (width + normal) * crap ---~ ---~ function names.analyse(mapping) ---~ for k, v in next, mapping do ---~ -- fails on "Romantik" but that's a border case anyway ---~ local name, weight, style, width = analyser:match(k) ---~ v[5], v[6], v[7], v[8] = name or k, weight or "normal", style or "normal", width or "normal" ---~ end ---~ end - -local P, C, Cc, Cs, Carg = lpeg.P, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Carg - -local weight = C(P("demibold") + P("semibold") + P("mediumbold") + P("ultrabold") + P("bold") + P("demi") + P("semi") + P("light") + P("medium") + P("heavy") + P("ultra") + P("black")) -local style = C(P("regular") + P("italic") + P("oblique") + P("slanted") + P("roman") + P("ital")) -local width = C(P("condensed") + P("normal") + P("expanded") + P("cond")) -local strip = P("book") + P("roman") -local any = P(1) - -local t - -local analyser = Cs ( - ( - strip / "" + - weight / function(s) t[6] = s return "" end + - style / function(s) t[7] = s return "" end + - width / function(s) t[8] = s return "" end + - any - )^0 -) - -local stripper = Cs ( - ( - strip / "" + - any - )^0 -) - -function names.analyse(mapping) -- fails on "Romantik" but that's a border case anyway - for k, v in next, mapping do - t = v - t[5] = analyser:match(k) -- somehow Carg fails - v[5], v[6], v[7], v[8] = t[5] or k, t[6] or "normal", t[7] or "normal", t[8] or "normal" - end -end - -local splitter = lpeg.splitat("-") - -function names.splitspec(askedname) - local name, weight, style, width = splitter:match(stripper:match(askedname) or askedname) - if trace_names then - logs.report("fonts","requested name '%s' split in name '%s', weight '%s', style '%s' and width '%s'",askedname,name or '',weight or '',style or '',width or '') - end - if not weight or not weight or not width then - weight, style, width = weight or "normal", style or "normal", width or "normal" - if trace_names then - logs.report("fonts","request '%s' normalized to '%s-%s-%s-%s'",askedname,name,weight,style,width) - end - end - return name or askedname, weight, style, width -end - -function names.checkduplicates(mapping) -- fails on "Romantik" but that's a border case anyway - local loaded = { } - for k, v in next, mapping do - local hash = format("%s-%s-%s-%s",v[5],v[6],v[7],v[8]) - local h = loaded[hash] - if h then - local ok = true - local fn = v[3] - for i=1,#h do - local hn = mapping[h[i]][3] - if hn == fn then - ok = false - break - end - end - if ok then - h[#h+1] = k - end - else - loaded[hash] = { h } - end - end - for k, v in table.sortedpairs(loaded) do - if #v > 1 then - for i=1,#v do - local vi = v[i] - v[i] = format("%s = %s",vi,mapping[vi][3]) - end - logs.report("fonts", "double lookup: %s => %s",k,concat(v," | ")) - end - end -end - function names.load(reload,verbose) if not names.loaded then if reload then @@ -516,51 +692,85 @@ function names.load(reload,verbose) logs.report("font table", "unable to access database cache") end names.saved = true - else - names.data = names.read_data(names.basename) - if not names.saved then - if table.is_empty(names.data) or table.is_empty(names.data.mapping) then - names.load(true) - end - names.saved = true + end + local data = names.read_data(names.basename) + names.data = data + if not names.saved then + if not next(data) or not next(data.specifications) then + names.load(true) end + names.saved = true end - local data = names.data - -- names.analyse(data.mapping) - -- names.analyse(data.fallback_mapping) - if data then - data.sorted = names.sorted(data.mapping) - data.fallback_sorted = names.sorted(data.fallback_mapping) - else + if not data then logs.report("font table", "accessing the data table failed") + else + unpackreferences() + sorthashes() end names.loaded = true end end -function names.list(pattern,reload) +local function list_them(mapping,sorted,pattern,t,all) + if mapping[pattern] then + t[pattern] = mapping[pattern] + else + for k=1,#sorted do + local v = sorted[k] + if find(v,pattern) then + t[v] = mapping[v] + if not all then + return + end + end + end + end +end + +function names.list(pattern,reload,all) -- here? names.load(reload) if names.loaded then local t = { } - local function list_them(mapping,sorted) - if mapping[pattern] then - t[pattern] = mapping[pattern] - else - for k,v in ipairs(sorted) do - if find(v,pattern) then - t[v] = mapping[v] - end + local data = names.data + if data then + local list = filters.list + local mappings, sorted_mappings = data.mappings, data.sorted_mappings + local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks + for i=1,#list do + local format = list[i] + list_them(mappings[format],sorted_mappings[format],pattern,t,all) + if next(t) and not all then + return t + end + list_them(fallbacks[format],sorted_fallbacks[format],pattern,t,all) + if next(t) and not all then + return t end end end + return t + end +end + +local reloaded = false + +local function is_reloaded() + if not reloaded then local data = names.data - if data then - list_them(data.mapping,data.sorted) - list_them(data.fallback_mapping,data.fallback_sorted) + if names.autoreload then + local c_status = table.serialize(resolvers.data_state()) + local f_status = table.serialize(data.data_state) + if c_status == f_status then + logs.report("fonts","font database matches configuration and file hashes") + return + else + logs.report("fonts","font database does not match configuration and file hashes") + end end - return t - else - return nil + names.loaded = false + reloaded = true + io.flush() + names.load(true) end end @@ -570,231 +780,326 @@ here is for testing purposes only (it deals with names prefixed by an encoding name).</p> --ldx]]-- -local function found_indeed(mapping,sorted,name) - local mn = mapping[name] - if mn then - return mn[2], mn[3], mn[4] +-- if names.be_clever then -- this will become obsolete +-- local encoding, tag = match(name,"^(.-)[%-%:](.+)$") +-- local mt = mapping[tag] +-- if tag and fonts.enc.is_known(encoding) and mt then +-- return mt[1], encoding .. "-" .. mt[3], mt[4] +-- end +-- end + +-- simple search + +local function found(mapping,sorted,name,sub) + local found = mapping[name] + -- obsolete: old encoding test + if not found then + for k,v in next, mapping do + if find(k,name) then + found = v + break + end + end + if not found then + local condensed = gsub(name,"[^%a%d]","") + found = mapping[condensed] + if not found then + for k=1,#sorted do + local v = sorted[k] + if find(v,condensed) then + found = mapping[v] + break + end + end + end + end + end + return found +end + +local function foundname(name,sub) + local data = names.data + local mappings, sorted_mappings = data.mappings, data.sorted_mappings + local fallbacks, sorted_fallbacks = data.fallbacks, data.sorted_fallbacks + local list = filters.list + for i=1,#list do + local l = list[i] + local okay = found(mappings[l],sorted_mappings[l],name,sub) or found(fallbacks[l],sorted_fallbacks[l],name,sub) + if okay then + return okay + end + end +end + +function names.resolve(askedname,sub) + if askedname and askedname ~= "" and names.enabled then + askedname = cleanname(askedname) + names.load() + local found = foundname(askedname,sub) + if not found and is_reloaded() then + found = foundname(askedname,sub) + end + if found then + return found.filename, found.subfont and found.rawname + end + end +end + +-- specified search + +local function s_collect_weight_style_width(found,done,all,weight,style,width,family) + if family then + for i=1,#family do + local f = family[i] + if f and weight == f.weight and style == f.style and width == f.width then + found[#found+1], done[f] = f, true + if not all then return end + end + end end - if names.be_clever then -- this will become obsolete - local encoding, tag = match(name,"^(.-)[%-%:](.+)$") - local mt = mapping[tag] - if tag and fonts.enc.is_known(encoding) and mt then - return mt[1], encoding .. "-" .. mt[3], mt[4] +end +local function m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and weight == f.weight and style == f.style and width == f.width and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end + +local function s_collect_weight_style(found,done,all,weight,style,family) + if family then + for i=1,#family do local f = family[i] + if f and weight == f.weight and style == f.style then + found[#found+1], done[f] = f, true + if not all then return end + end end end - -- name, type, file - for k,v in next, mapping do - if find(k,name) then - return v[2], v[3], v[4] +end +local function m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and weight == f.weight and style == f.style and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end end end - local condensed = gsub(name,"[^%a%d]","") - local mc = mapping[condensed] - if mc then - return mc[2], mc[3], mc[4] +end + +local function s_collect_style_width(found,done,all,style,width,family) + if family then + for i=1,#family do local f = family[i] + if f and style == f.style and width == f.width then + found[#found+1], done[f] = f, true + if not all then return end + end + end end - for k=1,#sorted do - local v = sorted[k] - if find(v,condensed) then - v = mapping[v] - return v[2], v[3], v[4] +end +local function m_collect_style_width(found,done,all,style,width,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and style == f.style and width == f.width and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end end end - return nil, nil, nil end -local function found(name) - if name and name ~= "" and names.data then - name = names.cleanname(name) - local data = names.data - local fontname, filename, is_sub = found_indeed(data.mapping, data.sorted, name) - if not fontname or not filename then - fontname, filename, is_sub = found_indeed(data.fallback_mapping, data.fallback_sorted, name) +local function s_collect_weight(found,done,all,weight,family) + if family then + for i=1,#family do local f = family[i] + if f and weight == f.weight then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end +local function m_collect_weight(found,done,all,weight,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and weight == f.weight and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end end - return fontname, filename, is_sub - else - return nil, nil, nil end end -local function collect(stage,mapping,sorted,found,done,name,weight,style,width,all) - if not mapping or not sorted then - return +local function s_collect_style(found,done,all,style,family) + if family then + for i=1,#family do local f = family[i] + if f and style == f.style then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end +local function m_collect_style(found,done,all,style,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and style == f.style and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end + end end -strictname = "^".. name - local f = mapping[name] - if weight ~= "" then - if style ~= "" then - if width ~= "" then +end + +local function s_collect_width(found,done,all,width,family) + if family then + for i=1,#family do local f = family[i] + if f and width == f.width then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end +local function m_collect_width(found,done,all,width,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and width == f.width and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end + +local function s_collect(found,done,all,family) + if family then + for i=1,#family do local f = family[i] + if f then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end +local function m_collect(found,done,all,families,sorted,strictname) + for i=1,#sorted do + local k = sorted[i] + local family = families[k] + for i=1,#family do + local f = family[i] + if not done[f] and find(f.fontname,strictname) then + found[#found+1], done[f] = f, true + if not all then return end + end + end + end +end + +local function collect(stage,found,done,name,weight,style,width,all) + local data = names.data + local families, sorted = data.families, data.sorted_families + strictname = "^".. name -- to be checked + local family = families[name] + if trace_names then + logs.report("fonts","resolving name '%s', weight '%s', style '%s', width '%s'",name or "?",tostring(weight),tostring(style),tostring(width)) + end + if weight and weight ~= "" then + if style and style ~= "" then + if width and width ~= "" then if trace_names then logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s', width '%s'",stage,name,weight,style,width) end - if f and width ~= f[8] and style == f[7] and weight == f[6] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[6] == weight and v[7] == style and v[8] == width and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_weight_style_width(found,done,all,weight,style,width,family) + m_collect_weight_style_width(found,done,all,weight,style,width,families,sorted,strictname) else if trace_names then logs.report("fonts","resolving stage %s, name '%s', weight '%s', style '%s'",stage,name,weight,style) end - if f and style == f[7] and weight == f[6] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[6] == weight and v[7] == style and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_weight_style(found,done,all,weight,style,family) + m_collect_weight_style(found,done,all,weight,style,families,sorted,strictname) end else if trace_names then logs.report("fonts","resolving stage %s, name '%s', weight '%s'",stage,name,weight) end - if f and weight == f[6] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[6] == weight and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_weight(found,done,all,weight,family) + m_collect_weight(found,done,all,weight,families,sorted,strictname) end - elseif style ~= "" then - if width ~= "" then + elseif style and style ~= "" then + if width and width ~= "" then if trace_names then logs.report("fonts","resolving stage %s, name '%s', style '%s', width '%s'",stage,name,style,width) end - if f and style == f[7] and width == f[8] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[7] == style and v[8] == width and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_style_width(found,done,all,style,width,family) + m_collect_style_width(found,done,all,style,width,families,sorted,strictname) else if trace_names then logs.report("fonts","resolving stage %s, name '%s', style '%s'",stage,name,style) end - if f and style == f[7] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[7] == style and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_style(found,done,all,style,family) + m_collect_style(found,done,all,style,families,sorted,strictname) end - elseif width ~= "" then + elseif width and width ~= "" then if trace_names then logs.report("fonts","resolving stage %s, name '%s', width '%s'",stage,name,width) end - if f and width == f[8] then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if v[8] == width and find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect_width(found,done,all,width,family) + m_collect_width(found,done,all,width,families,sorted,strictname) else if trace_names then logs.report("fonts","resolving stage %s, name '%s'",stage,name) end - if f then - found[#found+1], done[name] = f, true - if not all then return end - end - for i=1,#sorted do - local k = sorted[i] - if not done[k] then - local v = mapping[k] - if find(v[5],strictname) then - found[#found+1], done[k] = v, true - if not all then return end - end - end - end + s_collect(found,done,all,family) + m_collect(found,done,all,families,sorted,strictname) end end function heuristic(name,weight,style,width,all) -- todo: fallbacks local found, done = { }, { } - local data = names.data - local mapping, sorted, fbmapping, fbsorted = data.mapping, data.sorted, data.fallback_mapping, data.fallback_sorted weight, style = weight or "", style or "" - name = names.cleanname(name) - collect(1,mapping,sorted,found,done,name,weight,style,width,all) - if #found == 0 then - collect(2,fbmapping,fbsorted,found,done,name,weight,style,width,all) - end + name = cleanname(name) + collect(1,found,done,name,weight,style,width,all) + -- still needed ? if #found == 0 and width ~= "" then - width = "normal" - collect(3,mapping,sorted,found,done,name,weight,style,width,all) - if #found == 0 then - collect(4,fbmapping,fbsorted,found,done,name,weight,style,width,all) - end + width = "" + collect(2,found,done,name,weight,style,width,all) end if #found == 0 and weight ~= "" then -- not style - weight = "normal" - collect(5,mapping,sorted,found,done,name,weight,style,width,all) - if #found == 0 then - collect(6,fbmapping,fbsorted,found,done,name,weight,style,width,all) - end + weight = "" + collect(3,found,done,name,weight,style,width,all) end if #found == 0 and style ~= "" then -- not weight - style = "normal" - collect(7,mapping,sorted,found,done,name,weight,style,width,all) - if #found == 0 then - collect(8,fbmapping,fbsorted,found,done,name,weight,style,width,all) - end + style = "" + collect(4,found,done,name,weight,style,width,all) end + -- local nf = #found if trace_names then if nf then local t = { } for i=1,nf do - t[#t+1] = format("'%s'",found[i][2]) + t[#t+1] = format("'%s'",found[i].fontname) end logs.report("fonts","name '%s' resolved to %s instances: %s",name,nf,concat(t," ")) else @@ -803,63 +1108,48 @@ function heuristic(name,weight,style,width,all) -- todo: fallbacks end if all then return nf > 0 and found - elseif nf > 0 then - local f = found[1] - return f[2], f[3], f[4] else - return nil, nil, nil + return found[1] end end -local reloaded = false - -function names.specification(askedname,weight,style,width) +function names.specification(askedname,weight,style,width,reload,all) if askedname and askedname ~= "" and names.enabled then askedname = lower(askedname) -- or cleanname - names.load() - local name, filename, is_sub = heuristic(askedname,weight,style,width) - if not filename and not reloaded and names.autoreload then - names.loaded = false - reloaded = true - io.flush() - names.load(true) - name, filename, is_sub = heuristic(askedname,weight,style,width) + names.load(reload) + local found = heuristic(askedname,weight,style,width,all) + if not found and is_reloaded() then + found = heuristic(askedname,weight,style,width,all) if not filename then - name, filename, is_sub = found(askedname) -- old method + found = foundname(askedname) -- old method end end - return name, filename, is_sub + return found end end -function names.collect(askedname,weight,style,width) +function names.collect(askedname,weight,style,width,reload,all) if askedname and askedname ~= "" and names.enabled then askedname = lower(askedname) -- or cleanname - names.load() + names.load(reload) local list = heuristic(askedname,weight,style,width,true) - if not list or #list == 0 and not reloaded and names.autoreload then - names.loaded = false - reloaded = true - io.flush() - names.load(true) + if not list or #list == 0 and is_reloaded() then list = heuristic(askedname,weight,style,width,true) end return list end end -function names.resolve(askedname, sub) - local name, filename, is_sub = names.specification(askedname) - return filename, (is_sub and name) or sub -end - -function names.collectspec(askedname) - return names.collect(names.splitspec(askedname)) +function names.collectspec(askedname,reload,all) + local name, weight, style, width = names.splitspec(askedname) + return names.collect(name,weight,style,width,reload,all) end function names.resolvespec(askedname,sub) - local name, filename, is_sub = names.specification(names.splitspec(askedname)) - return filename, (is_sub and name) or sub + local found = names.specification(names.splitspec(askedname)) + if found then + return found.filename, found.subfont and found.rawname + end end --[[ldx-- @@ -924,3 +1214,89 @@ function names.exists(name) names.autoreload = fna return found end + +-- for i=1,fonts.names.lookup(pattern) do +-- texio.write_nl(fonts.names.getkey("filename",i)) +-- end + +local lastlookups, lastpattern = { }, "" + +function names.lookup(pattern,name,reload) -- todo: find + if lastpattern ~= pattern then + names.load(reload) + local specifications = names.data.specifications + local families = names.data.families + local lookups = specifications + if name then + lookups = families[name] + elseif not find(pattern,"=") then + lookups = families[pattern] + end + if trace_names then + logs.report("fonts","starting with %s lookups for '%s'",#lookups,pattern) + end + if lookups then + for key, value in gmatch(pattern,"([^=,]+)=([^=,]+)") do + local t = { } + for i=1,#lookups do + local s = lookups[i] + if s[key] == value then + t[#t+1] = lookups[i] + end + end + if trace_names then + logs.report("fonts","%s matches for key '%s' with value '%s'",#t,key,value) + end + lookups = t + end + end + lastpattern = pattern + lastlookups = lookups or { } + end + return #lastlookups +end + +function names.getlookupkey(key,n) + local l = lastlookups[n or 1] + return (l and l[key]) or "" +end + +function names.noflookups() + return #lastlookups +end + +function names.getlookups(pattern,name,reload) + if pattern then + names.lookup(pattern,name,reload) + end + return lastlookups +end + +function table.formatcolumns(result) + if result and #result > 0 then + local widths = { } + local first = result[1] + local n = #first + for i=1,n do + widths[i] = 0 + end + for i=1,#result do + local r = result[i] + for j=1,n do + local w = #r[j] + if w > widths[j] then + widths[j] = w + end + end + end + for i=1,n do + widths[i] = "%-" .. widths[i] .. "s" + end + local template = concat(widths," ") + for i=1,#result do + local str = format(template,unpack(result[i])) + result[i] = string.strip(str) + end + end + return result +end diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua index 576829369..2794a947a 100644 --- a/tex/context/base/font-tfm.lua +++ b/tex/context/base/font-tfm.lua @@ -533,15 +533,15 @@ local private = fonts.private end -- needed for \high cum suis local tpx = tp.x_height -if hasmath then - if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay - if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal - if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped - if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal - if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined - if not tp[22] then tp[22] = 0 end -- mathaxisheight - if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard -end + if hasmath then + if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay + if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal + if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped + if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal + if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined + if not tp[22] then tp[22] = 0 end -- mathaxisheight + if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard + end t.tounicode = 1 t.cidinfo = tfmtable.cidinfo -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename @@ -549,20 +549,21 @@ end -- can have multiple subfonts if hasmath then if trace_defining then - logs.report("define font","math enabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") + logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") end else if trace_defining then - logs.report("define font","math disabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") + logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") end t.nomath, t.MathConstants = true, nil end - -- fullname is used in the subsetting if not t.psname then - t.psname = t.fullname -- else bad luck + -- name used in pdf file as well as for selecting subfont in ttc/dfont + t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname)) end if trace_defining then - logs.report("define font","used for subsetting: %s ",t.fullname or "nofullname") + logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname") + logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname") end return t, delta end diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua index 0fc40b38b..44447a7ad 100644 --- a/tex/context/base/grph-inc.lua +++ b/tex/context/base/grph-inc.lua @@ -667,7 +667,12 @@ function figures.includers.generic(data) end if figure then local n = figures.boxnumber - tex.box[n] = img.node(figure) -- img.write(figure) + tex.box[n] = node.hpack(img.node(figure)) + -- tex.box[n] = img.node(figure) -- img.write(figure) -- assigning img.node directly no longer valid +--~ local inode = img.node(figure) +--~ print(table.serialize(nodes.totable(inode))) +--~ tex.box[n] = inode +--~ print(table.serialize(nodes.totable(tex.box[n]))) tex.wd[n], tex.ht[n], tex.dp[n] = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet) ds.objectnumber = figure.objnum texsprint(ctxcatcodes,"\\relocateexternalfigure") diff --git a/tex/context/base/lang-ini.lua b/tex/context/base/lang-ini.lua index b7b908144..c251ab1a6 100644 --- a/tex/context/base/lang-ini.lua +++ b/tex/context/base/lang-ini.lua @@ -280,7 +280,7 @@ end languages.words = languages.words or {} languages.words.data = languages.words.data or {} -languages.words.enable = false +languages.words.enables = false languages.words.threshold = 4 languages.words.colors = { @@ -426,7 +426,7 @@ do local color = attributes.private('color') function languages.words.check(head) - if lw.enable and head.next then + if lw.enabled and head.next then local colors = lw.colors local alc = attributes.list[color] return lw.methods[lw.method](head, color, alc[colors.known], alc[colors.unknown]) @@ -435,6 +435,15 @@ do end end + function languages.words.enable() + tasks.enableaction("processors","languages.words.check") + languages.words.enabled = true + end + + function languages.words.disable() + languages.words.enabled = false + end + end -- for the moment we hook it into the attribute handler diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv index f88281a60..86870d635 100644 --- a/tex/context/base/lang-ini.mkiv +++ b/tex/context/base/lang-ini.mkiv @@ -567,8 +567,8 @@ \def\setupspellchecking[#1]% todo colors {\getparameters[\??wl][#1]% \doifelse\@@wlstate\v!start - {\ctxlua{languages.words.enable=true }} - {\ctxlua{languages.words.enable=false}}} + {\ctxlua{languages.words.enable()}} + {\ctxlua{languages.words.disable()}}} \setupspellchecking [\c!state=\v!stop] diff --git a/tex/context/base/m-pstric.tex b/tex/context/base/m-pstric.tex index ac018fe07..f4be08dbd 100644 --- a/tex/context/base/m-pstric.tex +++ b/tex/context/base/m-pstric.tex @@ -13,6 +13,9 @@ %M \usemodule[pstric] +\letvalue{@unused}\plussixteen +\letvalue{alloc@}\gobblefivearguments + \chardef\oldbarcode\the\catcode`\| \catcode`\|=12 \def\loadpstrickscolors#1% diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua index 0300bb07f..1a8979160 100644 --- a/tex/context/base/math-vfu.lua +++ b/tex/context/base/math-vfu.lua @@ -371,7 +371,7 @@ function fonts.vf.math.define(specification,set) if trace_virtual then logs.report("math virtual", "unicode point U+%05X has no index %04X in vector %s for font %s",unicode,index,vectorname,fontname) elseif not already_reported then - logs.report("math virtual", "the mapping is incomplete for '%s' at %s",name,size) + logs.report("math virtual", "the mapping is incomplete for '%s' at %s",name,number.topoints(size)) already_reported = true end rv[unicode] = true @@ -747,6 +747,23 @@ fonts.enc.math["tex-mi"] = { [0x0003E] = 0x3E, -- > [0x022C6] = 0x3F, -- star [0x02202] = 0x40, -- partial +-- + [0x0266D] = 0x5B, -- flat + [0x0266E] = 0x5C, -- natural + [0x0266F] = 0x5D, -- sharp + [0x02323] = 0x5E, -- smile + [0x02322] = 0x5F, -- frown + [0x02113] = 0x60, -- ell +-- + [0x1D6A4] = 0x7B, -- imath (TODO: also 0131) + [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237) + [0x02118] = 0x7D, -- wp + [0x020D7] = 0x7E, -- vec (TODO: not sure) +-- 0x7F, -- (no idea what that could be) +} + + +fonts.enc.math["tex-it"] = { -- [0x00041] = 0x41, -- A [0x1D6E2] = 0x41, -- Alpha -- [0x00042] = 0x42, -- B @@ -786,12 +803,6 @@ fonts.enc.math["tex-mi"] = { -- [0x00059] = 0x59, -- Y -- [0x0005A] = 0x5A, -- Z [0x1D6E7] = 0x5A, -- Zeta - [0x0266D] = 0x5B, -- flat - [0x0266E] = 0x5C, -- natural - [0x0266F] = 0x5D, -- sharp - [0x02323] = 0x5E, -- smile - [0x02322] = 0x5F, -- frown - [0x02113] = 0x60, -- ell -- [0x00061] = 0x61, -- a -- [0x00062] = 0x62, -- b -- [0x00063] = 0x63, -- c @@ -800,7 +811,7 @@ fonts.enc.math["tex-mi"] = { -- [0x00066] = 0x66, -- f -- [0x00067] = 0x67, -- g -- [0x00068] = 0x68, -- h - [0x0210E] = 0x68, -- plant constant + [0x0210E] = 0x68, -- plank constant -- [0x00069] = 0x69, -- i -- [0x0006A] = 0x6A, -- j -- [0x0006B] = 0x6B, -- k @@ -820,11 +831,6 @@ fonts.enc.math["tex-mi"] = { -- [0x00078] = 0x78, -- x -- [0x00079] = 0x79, -- y -- [0x0007A] = 0x7A, -- z - [0x1D6A4] = 0x7B, -- imath (TODO: also 0131) - [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237) - [0x02118] = 0x7D, -- wp - [0x020D7] = 0x7E, -- vec (TODO: not sure) --- 0x7F, -- (no idea what that could be) } fonts.enc.math["tex-ss"] = { } @@ -1314,7 +1320,7 @@ fonts.enc.math["tex-fraktur"] = { -- now that all other vectors are defined ... -fonts.vf.math.set_letters(fonts.enc.math, "tex-mi", 0x1D434, 0x1D44E) +fonts.vf.math.set_letters(fonts.enc.math, "tex-it", 0x1D434, 0x1D44E) fonts.vf.math.set_letters(fonts.enc.math, "tex-ss", 0x1D5A0, 0x1D5BA) fonts.vf.math.set_letters(fonts.enc.math, "tex-tt", 0x1D670, 0x1D68A) fonts.vf.math.set_letters(fonts.enc.math, "tex-bf", 0x1D400, 0x1D41A) @@ -1342,6 +1348,7 @@ mathematics.make_font ( "lmroman5-math", { { name = "lmroman5-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr5.tfm", vector = "tex-mr-missing" } , { name = "lmmi5.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi5.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy5.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam5.tfm", vector = "tex-ma" }, @@ -1363,6 +1370,7 @@ mathematics.make_font ( "lmroman6-math", { { name = "lmroman6-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr6.tfm", vector = "tex-mr-missing" } , { name = "lmmi6.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi6.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy6.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam5.tfm", vector = "tex-ma" }, @@ -1387,6 +1395,7 @@ mathematics.make_font ( "lmroman7-math", { { name = "lmroman7-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr7.tfm", vector = "tex-mr-missing" } , { name = "lmmi7.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi7.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy7.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam7.tfm", vector = "tex-ma" }, @@ -1409,6 +1418,7 @@ mathematics.make_font ( "lmroman8-math", { { name = "lmroman8-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr8.tfm", vector = "tex-mr-missing" } , { name = "lmmi8.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi8.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy8.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam7.tfm", vector = "tex-ma" }, @@ -1431,6 +1441,7 @@ mathematics.make_font ( "lmroman9-math", { { name = "lmroman9-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr9.tfm", vector = "tex-mr-missing" } , { name = "lmmi9.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi9.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy9.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1456,6 +1467,7 @@ mathematics.make_font ( "lmroman10-math", { { name = "lmroman10-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr10.tfm", vector = "tex-mr-missing" } , { name = "lmmi10.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi10.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1473,6 +1485,7 @@ mathematics.make_font ( "lmroman10-boldmath", { { name = "lmroman10-bold.otf", features = "virtualmath", main = true }, { name = "rm-lmr10.tfm", vector = "tex-mr-missing" } , { name = "lmmib10.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmib10.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmbsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , -- copied from roman: @@ -1495,6 +1508,7 @@ mathematics.make_font ( "lmroman12-math", { { name = "lmroman12-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr12.tfm", vector = "tex-mr-missing" } , { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi12.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1514,6 +1528,7 @@ mathematics.make_font ( "lmroman17-math", { { name = "lmroman17-regular.otf", features = "virtualmath", main = true }, { name = "rm-lmr12.tfm", vector = "tex-mr-missing" } , { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "lmmi12.tfm", vector = "tex-it", skewchar=0x7F }, { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "lmex10.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1533,6 +1548,7 @@ mathematics.make_font ( "px-math", { { name = "texgyrepagella-regular.otf", features = "virtualmath", main = true }, { name = "rpxr.tfm", vector = "tex-mr" } , { name = "rpxmi.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "pxmi1.tfm", vector = "tex-it", skewchar=0x7F }, { name = "pxsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "pxex.tfm", vector = "tex-ex", extension = true } , { name = "pxsya.tfm", vector = "tex-ma" }, @@ -1542,6 +1558,7 @@ mathematics.make_font ( "px-math", { mathematics.make_font ( "tx-math", { { name = "texgyretermes-regular.otf", features = "virtualmath", main = true }, { name = "rtxr.tfm", vector = "tex-mr" } , + { name = "rtxptmri.tfm", vector = "tex-it", skewchar=0x7F }, { name = "rtxmi.tfm", vector = "tex-mi", skewchar=0x7F }, { name = "txsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "txex.tfm", vector = "tex-ex", extension = true } , @@ -1552,6 +1569,7 @@ mathematics.make_font ( "tx-math", { mathematics.make_font ( "antykwa-math", { { name = "file:AntykwaTorunska-Regular", features = "virtualmath", main = true }, { name = "mi-anttri.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-anttri.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-anttrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-anttr.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1561,6 +1579,7 @@ mathematics.make_font ( "antykwa-math", { mathematics.make_font ( "antykwa-light-math", { { name = "file:AntykwaTorunskaLight-Regular", features = "virtualmath", main = true }, { name = "mi-anttli.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-anttli.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-anttlz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-anttl.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1570,6 +1589,7 @@ mathematics.make_font ( "antykwa-light-math", { mathematics.make_font ( "antykwa-cond-math", { { name = "file:AntykwaTorunskaCond-Regular", features = "virtualmath", main = true }, { name = "mi-anttcri.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-anttcri.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-anttcrz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-anttcr.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1579,6 +1599,7 @@ mathematics.make_font ( "antykwa-cond-math", { mathematics.make_font ( "antykwa-lightcond-math", { { name = "file:AntykwaTorunskaCondLight-Regular", features = "virtualmath", main = true }, { name = "mi-anttcli.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-anttcli.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-anttclz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-anttcl.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1588,6 +1609,7 @@ mathematics.make_font ( "antykwa-lightcond-math", { mathematics.make_font ( "iwona-math", { { name = "file:Iwona-Regular", features = "virtualmath", main = true }, { name = "mi-iwonari.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-iwonari.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-iwonarz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-iwonar.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1597,6 +1619,7 @@ mathematics.make_font ( "iwona-math", { mathematics.make_font ( "iwona-light-math", { { name = "file:IwonaLight-Regular", features = "virtualmath", main = true }, { name = "mi-iwonali.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-iwonali.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-iwonalz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-iwonal.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1606,6 +1629,7 @@ mathematics.make_font ( "iwona-light-math", { mathematics.make_font ( "iwona-medium-math", { { name = "file:IwonaMedium-Regular", features = "virtualmath", main = true }, { name = "mi-iwonami.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-iwonami.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-iwonamz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-iwonam.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1615,6 +1639,7 @@ mathematics.make_font ( "iwona-medium-math", { mathematics.make_font ( "iwona-heavy-math", { { name = "file:IwonaHeavy-Regular", features = "virtualmath", main = true }, { name = "mi-iwonahi.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mi-iwonahi.tfm", vector = "tex-it", skewchar=0x7F }, { name = "sy-iwonahz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } , { name = "ex-iwonah.tfm", vector = "tex-ex", extension = true } , { name = "msam10.tfm", vector = "tex-ma" }, @@ -1626,6 +1651,7 @@ mathematics.make_font ( "iwona-heavy-math", { mathematics.make_font ( "mathtimes-math", { { name = "file:texgyretermes-regular.otf", features = "virtualmath", main = true }, { name = "mtmiz.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "mtmiz.tfm", vector = "tex-it", skewchar=0x7F }, { name = "mtsyn.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "mtex.tfm", vector = "tex-ex", extension = true }, { name = "msam10.tfm", vector = "tex-ma" }, @@ -1635,6 +1661,7 @@ mathematics.make_font ( "mathtimes-math", { mathematics.make_font ( "lucida-math", { { name = "lbr.afm", features = "virtualmath", main = true }, { name = "hlcrim.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "hlcrim.tfm", vector = "tex-it", skewchar=0x7F }, { name = "hlcry.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "hlcrv.tfm", vector = "tex-ex", extension = true }, { name = "hlcra.tfm", vector = "tex-ma" }, @@ -1645,6 +1672,7 @@ mathematics.make_font ( "charter-math", { { name = "file:bchr8a", features = "virtualmath", main = true }, -- { name = "md-chr7m.tfm", vector = "tex-mr" }, { name = "md-chri7m.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "md-chri7m.tfm", vector = "tex-it", skewchar=0x7F }, { name = "md-chr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "md-chr7v.tfm", vector = "tex-ex", extension = true }, { name = "msam10.tfm", vector = "tex-ma" }, @@ -1655,6 +1683,7 @@ mathematics.make_font ( "garamond-math", { { name = "file:ugmr8y", features = "virtualmath", main = true }, -- { name = "md-gmr7m.tfm", vector = "tex-mr" }, { name = "md-gmri7m.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "md-gmri7m.tfm", vector = "tex-it", skewchar=0x7F }, { name = "md-gmr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "md-gmr7v.tfm", vector = "tex-ex", extension = true }, { name = "msam10.tfm", vector = "tex-ma" }, @@ -1665,6 +1694,7 @@ mathematics.make_font ( "utopia-math", { { name = "file:putr8y", features = "virtualmath", main = true }, -- { name = "md-utr7m.tfm", vector = "tex-mr" }, { name = "md-utri7m.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "md-utri7m.tfm", vector = "tex-it", skewchar=0x7F }, { name = "md-utr7y.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "md-utr7v.tfm", vector = "tex-ex", extension = true }, { name = "msam10.tfm", vector = "tex-ma" }, @@ -1675,6 +1705,7 @@ mathematics.make_font ( "hvmath-math", { { name = "file:texgyreheros-regular.otf", features = "virtualmath", main = true }, { name = "hvrm108r.tfm", vector="tex-mr" }, { name = "hvmi10.tfm", vector = "tex-mi", skewchar=0x7F }, + { name = "hvmi10.tfm", vector = "tex-it", skewchar=0x7F }, { name = "hvsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true }, { name = "hvex10.tfm", vector = "tex-ex", extension = true }, { name = "hvam10.tfm", vector = "tex-ma" }, diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua index 253243500..f0ee1ec29 100644 --- a/tex/context/base/mlib-pps.lua +++ b/tex/context/base/mlib-pps.lua @@ -424,7 +424,7 @@ metapost.last_box = metapost.last_box or 1100 metapost.textext_current = metapost.first_box metapost.multipass = false -function metapost.free_boxes() +function metapost.free_boxes() -- todo: mp direct list ipv box local tb = tex.box for i = metapost.first_box,metapost.last_box do local b = tb[i] diff --git a/tex/context/base/node-ref.lua b/tex/context/base/node-ref.lua index 02f6ca82d..008e44b6b 100644 --- a/tex/context/base/node-ref.lua +++ b/tex/context/base/node-ref.lua @@ -67,6 +67,8 @@ local function dimensions(parent,start,stop) end end +-- is pardir important at all? + local function inject_range(head,first,last,reference,make,stack,parent,pardir,txtdir) local width, height, depth = dimensions(parent,first,last) if pardir == "TRT" or txtdir == "+TRT" then diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua index f147981ed..49a1297eb 100644 --- a/tex/context/base/node-res.lua +++ b/tex/context/base/node-res.lua @@ -60,8 +60,10 @@ local glyph = nodes.register(new_node("glyph",0)) local textdir = nodes.register(new_node("whatsit",7)) local rule = nodes.register(new_node("rule")) local latelua = nodes.register(new_node("whatsit",35)) ---~ local user = nodes.register(new_node("user_defined")) -local user = nodes.register(new_node(44)) +local user_n = nodes.register(new_node("whatsit",44)) user_n.type = 100 +local user_l = nodes.register(new_node("whatsit",44)) user_l.type = 110 +local user_s = nodes.register(new_node("whatsit",44)) user_s.type = 115 +local user_t = nodes.register(new_node("whatsit",44)) user_t.type = 116 function nodes.glyph(fnt,chr) local n = copy_node(glyph) @@ -111,27 +113,41 @@ function nodes.latelua(code) return n end +local cache = { } + function nodes.usernumber(num) - local n = copy_node(user) - n.type = 100 - if num then n.value = num end - return n -end -function nodes.userstring(str) - local n = copy_node(user) - n.type = 115 - if str then n.value = str end - return n + local n = cache[num] + if n then + return copy_node(n) + else + local n = copy_node(user_n) + if num then n.value = num end + return n + end end + function nodes.userlist(list) - local n = copy_node(user) - n.type = 110 + local n = copy_node(user_l) if list then n.value = list end return n end + +local cache = { } -- we could use the same cache + +function nodes.userstring(str) + local n = cache[str] + if n then + return copy_node(n) + else + local n = copy_node(user_s) + n.type = 115 + if str then n.value = str end + return n + end +end + function nodes.usertokens(tokens) - local n = copy_node(user) - n.type = 116 + local n = copy_node(user_t) if tokens then n.value = tokens end return n end diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua index 60c6e77f3..3f1d572b7 100644 --- a/tex/context/base/node-rul.lua +++ b/tex/context/base/node-rul.lua @@ -11,7 +11,6 @@ if not modules then modules = { } end modules ['node-rul'] = { local trace_ruled = false trackers.register("nodes.ruled", function(v) trace_ruled = v end) local floor = math.floor -local topoints = number.topoints local n_tostring, n_tosequence = nodes.ids_tostring, nodes.tosequence local a_ruled = attributes.private('ruled') @@ -19,12 +18,14 @@ local a_color = attributes.private('color') local a_transparency = attributes.private('transparency') local a_colorspace = attributes.private('colormodel') -local glyph = node.id("glyph") -local disc = node.id("disc") -local glue = node.id("glue") -local kern = node.id("kern") -local hlist = node.id("hlist") -local vlist = node.id("vlist") +local glyph = node.id("glyph") +local disc = node.id("disc") +local glue = node.id("glue") +local kern = node.id("kern") +local hlist = node.id("hlist") +local vlist = node.id("vlist") +local rule = node.id("rule") +local whatsit = node.id("whatsit") local new_rule = nodes.rule local new_kern = nodes.kern @@ -44,6 +45,11 @@ local variables = interfaces.variables -- -- glyph rule unset whatsit glue margin_kern kern math disc +local checkdir = true + +-- we assume {glyphruns} and no funny extra kerning, ok, maybe we need +-- a dummy character as start and end; anyway we only collect glyphs + local function process_words(attribute,data,flush,head,parent) local n = head if n then @@ -55,7 +61,7 @@ local function process_words(attribute,data,flush,head,parent) local aa = has_attribute(n,attribute) if aa then if aa == a then - if not f then + if not f then -- ? f = n end l = n @@ -77,6 +83,8 @@ local function process_words(attribute,data,flush,head,parent) end elseif f and id == disc then l = n + elseif f and id == rule then + l = n elseif f and id == kern and n.subtype == 0 then l = n elseif id == hlist or id == vlist then @@ -88,6 +96,10 @@ local function process_words(attribute,data,flush,head,parent) if list then n.list = process_words(attribute,data,flush,list,n) end + elseif checkdir and id == whatsit and n.subtype == 7 then -- only changes in dir, we assume proper boundaries + if f and a then + l = n + end elseif f and not continue then head, done = flush(head,f,l,d,level,parent), true f, l, a = nil, nil, nil @@ -160,7 +172,7 @@ local function flush_ruled(head,f,l,d,level,parent) -- not that fast but accepta insert_after(head,r,k) end if trace_ruled then - logs.report("ruled", "level: %s, width: %s, nodes: %s, text: %s",level,topoints(w),n_tostring(f,l),n_tosequence(f,l,true)) + logs.report("ruled", "level: %s, width: %s, nodes: %s, text: %s",level,w,n_tostring(f,l),n_tosequence(f,l,true)) end end return head @@ -179,6 +191,8 @@ end -- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.process") -- tasks.disableaction("shipouts", "nodes.rules.process") -- only kick in when used +local trace_shifted = false trackers.register("nodes.shifted", function(v) trace_shifted = v end) + local a_shifted = attributes.private('shifted') nodes.shifts = nodes.shifts or { } @@ -209,6 +223,9 @@ local function flush_shifted(head,first,last,data,level,parent) -- not that fast end local raise = data.dy * dimenfactor(data.unit,fontdata[first.font]) list.shift, list.height, list.depth = raise, height, depth + if trace_shifted then + logs.report("shifted", "width: %s, nodes: %s, text: %s",width,n_tostring(first,last),n_tosequence(first,last,true)) + end return head end diff --git a/tex/context/base/node-rul.mkiv b/tex/context/base/node-rul.mkiv index 40d0014dc..ba2f0aed3 100644 --- a/tex/context/base/node-rul.mkiv +++ b/tex/context/base/node-rul.mkiv @@ -11,6 +11,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% todo: ex and and em traveling with attribute + \writestatus{loading}{ConTeXt Core Macros / Bars} %D The name of this file might change. @@ -255,13 +257,39 @@ \glet\dodoshifted\dodoshiftedindeed \dodoshifted} +% \def\dodoshiftedindeed#1% +% {\def\currentshift{#1}% +% \advance\csname\??ra:#1:c\endcsname\plusone +% \scratchcounter\csname\??ra:#1:c\endcsname +% \dosetattribute{shifted}{\numexpr1000*\scratchcounter +% +\csname\??ra#1\ifcsname\??ra#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname}% +% \setupalign[\shiftparameter\c!align]% +% \dosetshiftattributes\c!style\c!color} + +\def\dostartisolation{\char0 } +\def\dostopisolation {\char0 } +\def\doisolator {\char0 } + +\def\doisolatedgroupedalign#1#2% + {\groupedcommand + {\begingroup\dostartisolation\begingroup#1} + {#2\endgroup\dostopisolation\endgroup}} + +\def\dosetupisolatedalign#1% + {\doisolator + \setupalign[#1]\relax} + \def\dodoshiftedindeed#1% {\def\currentshift{#1}% \advance\csname\??ra:#1:c\endcsname\plusone \scratchcounter\csname\??ra:#1:c\endcsname \dosetattribute{shifted}{\numexpr1000*\scratchcounter +\csname\??ra#1\ifcsname\??ra#1:\number\scratchcounter\s!parent\endcsname:\number\scratchcounter\fi:a\endcsname}% - \dosetshiftattributes\c!style\c!color} + \dosetshiftattributes\c!style\c!color + \dosetupisolatedalign{\shiftparameter\c!align}} + +\def\doshifted#1% + {\doisolatedgroupedalign{\dodoshifted{#1}}{}} \unexpanded\def\startshift[#1]% {\begingroup @@ -287,6 +315,7 @@ \c!continue=\v!no, \c!dy=0, \c!unit=ex, + \c!align=, \c!style=, \c!color=] diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua index 004aa34fa..f243c9cd0 100644 --- a/tex/context/base/node-tra.lua +++ b/tex/context/base/node-tra.lua @@ -310,7 +310,7 @@ function nodes.show_list(head, message) if message then texio.write_nl(message) end - for n in traverse(head) do + for n in traverse_nodes(head) do texio.write_nl(tostring(n)) end end diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv index 8bae7e754..bd3a127e3 100644 --- a/tex/context/base/pack-rul.mkiv +++ b/tex/context/base/pack-rul.mkiv @@ -2286,7 +2286,7 @@ \egroup} \def\complexvl[#1]% - {\dovlwdhtdp\linewidth{#1}{#1}} + {\dovlwdhtdp{1}{#1}{#1}} \def\complexhl[#1]% {\hbox diff --git a/tex/context/base/spec-fdf.mkii b/tex/context/base/spec-fdf.mkii index 6f5a83bcb..509ea0596 100644 --- a/tex/context/base/spec-fdf.mkii +++ b/tex/context/base/spec-fdf.mkii @@ -191,6 +191,26 @@ \def\appendtoPDFdocumentextgstates#1% {\xdef\docuPDFextgstates{\docuPDFextgstates\space#1}} +%D Patterns (for tikz) + +\let\docuPDFpatterns\empty + +\def\checkPDFpatterns + {\ifx\docuPDFpatterns\empty \else + \ifnum\realpageno=\lastpage\relax + \doPDFdictionaryobject{FDF}{docupatterns}{\docuPDFpatterns}% + \fi + \doPDFgetobjectreference{FDF}{docupatterns}\PDFobjectreference + \doPDFpageresource{/Pattern \PDFobjectreference}% + \fi} + +\appendtoksonce + \checkPDFpatterns +\to \everyshipout + +\def\appendtoPDFdocumentpatterns#1% + {\xdef\docuPDFpatterns{\docuPDFpatterns\space#1}} + %D Another special mechanism (needed for color separation): \let\docuPDFcolorspaces\empty diff --git a/tex/context/base/strc-not.mkiv b/tex/context/base/strc-not.mkiv index 0d45ee59e..0246767b9 100644 --- a/tex/context/base/strc-not.mkiv +++ b/tex/context/base/strc-not.mkiv @@ -251,7 +251,6 @@ % \dochecknote % \to \everysetupnote - \def\setupnote {\dodoubleempty\dosetupnote} diff --git a/tex/context/base/tabl-tbl.mkiv b/tex/context/base/tabl-tbl.mkiv index bfff978ab..6942327fe 100644 --- a/tex/context/base/tabl-tbl.mkiv +++ b/tex/context/base/tabl-tbl.mkiv @@ -410,8 +410,8 @@ \def\gettabulatepreskip#1% {\doifnumberelse{#1} - {\edef\pretabskip{\the\dimenexpr#1\tabulateunit}\let\next\empty} - {\edef\pretabskip{\the\dimenexpr.5\tabulateunit}\def\next{#1}}% + {\edef\pretabskip{\the\dimexpr#1\tabulateunit}\let\next\empty} + {\edef\pretabskip{\the\dimexpr.5\tabulateunit}\def\next{#1}}% \@EA\settabulatepreamble\next} \def\gettabulateposskip#1% @@ -423,8 +423,8 @@ \def\gettabulatepreposskip#1% {\doifnumberelse{#1} - {\edef\pretabskip{\the\dimenexpr#1\tabulateunit}\let\next\empty} - {\edef\pretabskip{\the\dimenexpr.5\tabulateunit}\def\next{#1}}% + {\edef\pretabskip{\the\dimexpr#1\tabulateunit}\let\next\empty} + {\edef\pretabskip{\the\dimexpr.5\tabulateunit}\def\next{#1}}% \let\postabskip\pretabskip \let\gettabulateexit\settabulatepreamble \@EA\settabulatepreamble\next} diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua index dba099451..01bcaec0f 100644 --- a/tex/context/base/task-ini.lua +++ b/tex/context/base/task-ini.lua @@ -20,7 +20,8 @@ tasks.appendaction("processors", "characters", "chars.handle_breakpoints") tasks.appendaction("processors", "characters", "scripts.preprocess") tasks.appendaction("processors", "words", "kernel.hyphenation") -tasks.appendaction("processors", "words", "languages.words.check") +tasks.appendaction("processors", "words", "languages.words.check") -- * disabled + tasks.appendaction("processors", "fonts", "nodes.process_characters") tasks.appendaction("processors", "fonts", "nodes.inject_kerns") @@ -28,21 +29,18 @@ tasks.appendaction("processors", "fonts", "nodes.protect_glyphs", nil, "no tasks.appendaction("processors", "fonts", "kernel.ligaturing") tasks.appendaction("processors", "fonts", "kernel.kerning") -tasks.appendaction("processors", "lists", "lists.handle_spacing") -- * -tasks.appendaction("processors", "lists", "lists.handle_kerning") -- * +tasks.appendaction("processors", "lists", "lists.handle_spacing") -- * disabled +tasks.appendaction("processors", "lists", "lists.handle_kerning") -- * disabled tasks.appendaction("shipouts", "normalizers", "nodes.cleanup_page") tasks.appendaction("shipouts", "normalizers", "nodes.add_references") -- * tasks.appendaction("shipouts", "normalizers", "nodes.add_destinations") -- * -tasks.appendaction("shipouts", "normalizers", "nodes.rules.process") -- * -tasks.appendaction("shipouts", "normalizers", "nodes.shifts.process") -- * - -tasks.disableaction("shipouts", "nodes.rules.process") -- * only kick in when used -tasks.disableaction("shipouts", "nodes.shifts.process") -- * only kick in when used +tasks.appendaction("shipouts", "normalizers", "nodes.rules.process") -- * disabled +tasks.appendaction("shipouts", "normalizers", "nodes.shifts.process") -- * disabled tasks.appendaction("shipouts", "finishers", "shipouts.handle_color") tasks.appendaction("shipouts", "finishers", "shipouts.handle_transparency") -tasks.appendaction("shipouts", "finishers", "shipouts.handle_colorintent") +tasks.appendaction("shipouts", "finishers", "shipouts.handle_colorintent") -- * tasks.appendaction("shipouts", "finishers", "shipouts.handle_negative") -- * tasks.appendaction("shipouts", "finishers", "shipouts.handle_effect") -- * tasks.appendaction("shipouts", "finishers", "shipouts.handle_viewerlayer") -- * @@ -56,3 +54,11 @@ tasks.appendaction("math", "builders", "noads.mlist_to_hlist") -- quite experimental tasks.appendaction("finalizers", "lists", "nodes.repackage_graphicvadjust") -- * + +-- speedup: see * -- only kick in when used + +tasks.disableaction("processors", "languages.words.check") +tasks.disableaction("processors", "lists.handle_spacing") +tasks.disableaction("processors", "lists.handle_kerning") +tasks.disableaction("shipouts", "nodes.rules.process") +tasks.disableaction("shipouts", "nodes.shifts.process") diff --git a/tex/context/base/type-otf.mkiv b/tex/context/base/type-otf.mkiv index 983e197de..e7844fb0b 100644 --- a/tex/context/base/type-otf.mkiv +++ b/tex/context/base/type-otf.mkiv @@ -525,6 +525,24 @@ \loadmapfile[mdput.map] \stoptypescript +% asana math + +\starttypescript [math] [asana] + \definefontsynonym [AsanaMath] [name:asanamath] +\stoptypescript + +\starttypescript [math] [asana] [name] + \definefontsynonym [MathRoman] [AsanaMath] [features=math\mathsizesuffix] +\stoptypescript + +\starttypescript[asana] + \definetypeface [\typescriptone] [rm] [serif] [palatino] [default] + \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [rscale=1.075] + \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [rscale=1.075] + \definetypeface [\typescriptone] [mm] [math] [\typescriptone] [default] + \quittypescriptscanning +\stoptypescript + \stoptypescriptcollection \endinput diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua index 5ab0b07ed..87e066531 100644 --- a/tex/context/base/typo-krn.lua +++ b/tex/context/base/typo-krn.lua @@ -217,3 +217,8 @@ lists.handle_kerning = nodes.install_attribute_handler { namespace = kerns, processor = kerns.process, } + +function kerns.enable() + tasks.enableaction("processors","lists.handle_kerning") + kerns.enabled = true -- will go +end diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua index b6a1fbb5b..56ce36a05 100644 --- a/tex/context/base/typo-spa.lua +++ b/tex/context/base/typo-spa.lua @@ -25,7 +25,7 @@ local fontdata = fonts.ids spacings = spacings or { } spacings.mapping = spacings.mapping or { } -spacings.enabled = false +spacings.enabled = false -- will go spacings.attribute = attributes.private("spacing") storage.register("spacings/mapping", spacings.mapping, "spacings.mapping") @@ -148,3 +148,18 @@ lists.handle_spacing = nodes.install_attribute_handler { namespace = spacings, processor = spacings.process, } + +function spacings.enable() + tasks.enableaction("processors","lists.handle_spacing") + spacings.enabled = true -- will go +end + +--~ local data = { +--~ name = "spacing", +--~ namespace = spacings, +--~ processor = spacings.process, +--~ } +--~ nodes.process_attribute = process_attribute +--~ function lists.handle_spacing(head) +--~ return process_attribute(head,data) +--~ end diff --git a/tex/context/base/typo-spa.mkiv b/tex/context/base/typo-spa.mkiv index d1b855edd..9ff614be9 100644 --- a/tex/context/base/typo-spa.mkiv +++ b/tex/context/base/typo-spa.mkiv @@ -43,7 +43,8 @@ \fi} \def\setcharacterspacing - {\ctxlua{spacings.enabled=true}% +% {\ctxlua{spacings.enabled=true}% + {\ctxlua{spacings.enable()}% \gdef\setcharacterspacing[##1]{\dosetattribute{spacing}{\csname\??ch:##1\endcsname}}% \setcharacterspacing} diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua index 70368ebd9..82fe96610 100644 --- a/tex/generic/context/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts-merged.lua -- parent file : c:/data/develop/context/texmf/tex/generic/context/luatex-fonts.lua --- merge date : 11/13/09 12:51:09 +-- merge date : 11/18/09 21:55:28 do -- begin closure to overcome local limits and interference @@ -2345,8 +2345,10 @@ local glyph = nodes.register(new_node("glyph",0)) local textdir = nodes.register(new_node("whatsit",7)) local rule = nodes.register(new_node("rule")) local latelua = nodes.register(new_node("whatsit",35)) ---~ local user = nodes.register(new_node("user_defined")) -local user = nodes.register(new_node(44)) +local user_n = nodes.register(new_node("whatsit",44)) user_n.type = 100 +local user_l = nodes.register(new_node("whatsit",44)) user_l.type = 110 +local user_s = nodes.register(new_node("whatsit",44)) user_s.type = 115 +local user_t = nodes.register(new_node("whatsit",44)) user_t.type = 116 function nodes.glyph(fnt,chr) local n = copy_node(glyph) @@ -2396,27 +2398,41 @@ function nodes.latelua(code) return n end +local cache = { } + function nodes.usernumber(num) - local n = copy_node(user) - n.type = 100 - if num then n.value = num end - return n -end -function nodes.userstring(str) - local n = copy_node(user) - n.type = 115 - if str then n.value = str end - return n + local n = cache[num] + if n then + return copy_node(n) + else + local n = copy_node(user_n) + if num then n.value = num end + return n + end end + function nodes.userlist(list) - local n = copy_node(user) - n.type = 110 + local n = copy_node(user_l) if list then n.value = list end return n end + +local cache = { } -- we could use the same cache + +function nodes.userstring(str) + local n = cache[str] + if n then + return copy_node(n) + else + local n = copy_node(user_s) + n.type = 115 + if str then n.value = str end + return n + end +end + function nodes.usertokens(tokens) - local n = copy_node(user) - n.type = 116 + local n = copy_node(user_t) if tokens then n.value = tokens end return n end @@ -3794,15 +3810,15 @@ local private = fonts.private end -- needed for \high cum suis local tpx = tp.x_height -if hasmath then - if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay - if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal - if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped - if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal - if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined - if not tp[22] then tp[22] = 0 end -- mathaxisheight - if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard -end + if hasmath then + if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay + if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal + if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped + if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal + if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined + if not tp[22] then tp[22] = 0 end -- mathaxisheight + if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard + end t.tounicode = 1 t.cidinfo = tfmtable.cidinfo -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename @@ -3810,20 +3826,21 @@ end -- can have multiple subfonts if hasmath then if trace_defining then - logs.report("define font","math enabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") + logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") end else if trace_defining then - logs.report("define font","math disabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") + logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") end t.nomath, t.MathConstants = true, nil end - -- fullname is used in the subsetting if not t.psname then - t.psname = t.fullname -- else bad luck + -- name used in pdf file as well as for selecting subfont in ttc/dfont + t.psname = t.fontname or (t.fullname and fonts.names.cleanname(t.fullname)) end if trace_defining then - logs.report("define font","used for subsetting: %s ",t.fullname or "nofullname") + logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname") + logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname") end return t, delta end @@ -6705,8 +6722,9 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th tfm.units = metadata.units_per_em or 1000 -- we need a runtime lookup because of running from cdrom or zip, brrr tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename - tfm.fullname = metadata.fontname or metadata.fullname - tfm.psname = tfm.fullname + tfm.fullname = metadata.fullname + tfm.fontname = metadata.fontname + tfm.psname = tfm.fontname or tfm.fullname tfm.encodingbytes = 2 tfm.cidinfo = data.cidinfo tfm.cidinfo.registry = tfm.cidinfo.registry or "" @@ -6830,7 +6848,8 @@ function tfm.read_from_open_type(specification) if filename then tfmtable.encodingbytes = 2 tfmtable.filename = resolvers.findbinfile(filename,"") or filename - tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname + tfmtable.fontname = tfmtable.fontname or otfdata.metadata.fontname + tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fullname or tfmtable.fontname local order = otfdata and otfdata.metadata.order2 if order == 0 then tfmtable.format = 'opentype' @@ -6839,7 +6858,7 @@ function tfm.read_from_open_type(specification) else tfmtable.format = specification.format end - tfmtable.name = tfmtable.filename or tfmtable.fullname + tfmtable.name = tfmtable.filename or tfmtable.fullname or tfmtable.fontname end fonts.logger.save(tfmtable,file.extname(specification.filename),specification) end @@ -7491,7 +7510,7 @@ results in different tables.</p> -- remark: the 'not implemented yet' variants will be done when we have fonts that use them -- remark: we need to check what to do with discretionaries -local concat = table.concat +local concat, insert, remove = table.concat, table.insert, table.remove local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip local type, next, tonumber, tostring = type, next, tonumber, tostring @@ -7513,6 +7532,7 @@ local trace_details = false trackers.register("otf.details", function local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end) local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end) local trace_skips = false trackers.register("otf.skips", function(v) trace_skips = v end) +local trace_directions = false trackers.register("otf.directions", function(v) trace_directions = v end) trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) @@ -8117,7 +8137,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to if exit then local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) + logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) end done = true break @@ -8769,7 +8789,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache, if exit then local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound) + logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) end done = true break @@ -9206,6 +9226,9 @@ local resolved = { } -- we only resolve a font,script,language pair once -- todo: pass all these 'locals' in a table +-- maybe some day i'll make an alternative that works on 'sub direction runs' which might be +-- more efficient for arabic but it has quite some consequences + function fonts.methods.node.otf.features(head,font,attr) if trace_steps then checkstep(head) @@ -9249,6 +9272,7 @@ function fonts.methods.node.otf.features(head,font,attr) local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false -- sequences always > 1 so no need for optimization for s=1,#sequences do + local pardir, txtdir = 0, { } local success = false local sequence = sequences[s] local r = ra[s] -- cache @@ -9348,7 +9372,7 @@ function fonts.methods.node.otf.features(head,font,attr) local ns = #subtables local thecache = featuredata[typ] or { } start = head -- local ? - rlmode = 0 + rlmode = 0 -- to be checked ? if ns == 1 then local lookupname = subtables[1] local lookupcache = thecache[lookupname] @@ -9390,24 +9414,57 @@ function fonts.methods.node.otf.features(head,font,attr) -- start = start.next -- end elseif id == whatsit then +--~ if subtype == 7 then +--~ local dir = start.dir +--~ if dir == "+TRT" then +--~ rlmode = -1 +--~ elseif dir == "+TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ elseif subtype == 6 then +--~ local dir = start.dir +--~ if dir == "TRT" then +--~ rlmode = -1 +--~ elseif dir == "TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ end local subtype = start.subtype if subtype == 7 then local dir = start.dir - if dir == "+TRT" then + if dir == "+TRT" or dir == "+TLT" then + insert(txtdir,dir) + elseif dir == "-TRT" or dir == "-TLT" then + remove(txtdir) + end + local d = txtdir[#txtdir] + if d == "+TRT" then rlmode = -1 - elseif dir == "+TLT" then + elseif d == "+TLT" then rlmode = 1 else - rlmode = 0 + rlmode = pardir + end + if trace_directions then + logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end elseif subtype == 6 then local dir = start.dir if dir == "TRT" then - rlmode = -1 + pardir = -1 elseif dir == "TLT" then - rlmode = 1 + pardir = 1 else - rlmode = 0 + pardir = 0 + end + rlmode = pardir + --~ txtdir = { } + if trace_directions then + logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end end start = start.next @@ -9415,7 +9472,6 @@ function fonts.methods.node.otf.features(head,font,attr) start = start.next end end - end else while start do @@ -9462,25 +9518,59 @@ function fonts.methods.node.otf.features(head,font,attr) -- end elseif id == whatsit then local subtype = start.subtype - if subtype == 7 then - local dir = start.dir - if dir == "+TRT" then - rlmode = -1 - elseif dir == "+TLT" then - rlmode = 1 - else - rlmode = 0 +--~ if subtype == 7 then +--~ local dir = start.dir +--~ if dir == "+TRT" then +--~ rlmode = -1 +--~ elseif dir == "+TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ elseif subtype == 6 then +--~ local dir = start.dir +--~ if dir == "TRT" then +--~ rlmode = -1 +--~ elseif dir == "TLT" then +--~ rlmode = 1 +--~ else +--~ rlmode = 0 +--~ end +--~ end + local subtype = start.subtype + if subtype == 7 then + local dir = start.dir + if dir == "+TRT" or dir == "+TLT" then + insert(txtdir,dir) + elseif dir == "-TRT" or dir == "-TLT" then + remove(txtdir) + end + local d = txtdir[#txtdir] + if d == "+TRT" then + rlmode = -1 + elseif d == "+TLT" then + rlmode = 1 + else + rlmode = pardir + end + if trace_directions then + logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) + end + elseif subtype == 6 then + local dir = start.dir + if dir == "TRT" then + pardir = -1 + elseif dir == "TLT" then + pardir = 1 + else + pardir = 0 + end + rlmode = pardir + --~ txtdir = { } + if trace_directions then + logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) end - elseif subtype == 6 then - local dir = start.dir - if dir == "TRT" then - rlmode = -1 - elseif dir == "TLT" then - rlmode = 1 - else - rlmode = 0 end - end start = start.next else start = start.next @@ -11521,10 +11611,15 @@ function fonts.logger.save() end -- names +-- +-- Watch out, the version number is the same as the one used in +-- the mtx-fonts.lua function scripts.fonts.names as we use a +-- simplified font database in the plain solution and by using +-- a different number we're less dependent on context. fonts.names = fonts.names or { } -fonts.names.version = 1.014 +fonts.names.version = 1.001 -- not the same as in context fonts.names.basename = "luatex-fonts-names.lua" fonts.names.new_to_old = { } fonts.names.old_to_new = { } @@ -11539,16 +11634,6 @@ function fonts.names.resolve(name,sub) local foundname = resolvers.find_file(basename,format) or "" if foundname ~= "" then data = dofile(foundname) - if data then - local d = { } - for k, v in pairs(data.mapping) do - local t = v[1] - if t == "ttf" or t == "otf" or t == "ttc" or t == "dfont" then - d[k] = v - end - end - data.mapping = d - end break end end @@ -11559,9 +11644,12 @@ function fonts.names.resolve(name,sub) local condensed = string.gsub(string.lower(name),"[^%a%d]","") local found = data.mapping and data.mapping[condensed] if found then - local filename, is_sub = found[3], found[4] - if is_sub then is_sub = found[2] end - return filename, is_sub + local fontname, filename, subfont = found[1], found[2], found[3] + if subfont then + return filename, fontname + else + return filename, false + end else return name, false -- fallback to filename end |