From 9a10021cd4cb23995ad3ffa915fc5b7f6890aaf8 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Sun, 19 May 2013 19:27:00 +0200 Subject: beta 2013.05.19 19:27 --- scripts/context/lua/mtx-base.lua | 268 +- scripts/context/lua/mtx-cache.lua | 274 +-- scripts/context/lua/mtx-chars.lua | 866 +++---- scripts/context/lua/mtx-check.lua | 506 ++-- scripts/context/lua/mtx-colors.lua | 154 +- scripts/context/lua/mtx-context.lua | 2984 +++++++++++------------ scripts/context/lua/mtx-convert.lua | 350 +-- scripts/context/lua/mtx-fcd.lua | 772 +++--- scripts/context/lua/mtx-flac.lua | 476 ++-- scripts/context/lua/mtx-fonts.lua | 944 +++---- scripts/context/lua/mtx-grep.lua | 340 +-- scripts/context/lua/mtx-metatex.lua | 160 +- scripts/context/lua/mtx-mk-help.lua | 946 +++---- scripts/context/lua/mtx-modules.lua | 404 +-- scripts/context/lua/mtx-mtxworks.lua | 28 +- scripts/context/lua/mtx-package.lua | 168 +- scripts/context/lua/mtx-patterns.lua | 93 +- scripts/context/lua/mtx-pdf.lua | 598 ++--- scripts/context/lua/mtx-plain.lua | 258 +- scripts/context/lua/mtx-profile.lua | 374 +-- scripts/context/lua/mtx-rsync.lua | 378 +-- scripts/context/lua/mtx-scite.lua | 518 ++-- scripts/context/lua/mtx-server-ctx-fonttest.lua | 1498 ++++++------ scripts/context/lua/mtx-server-ctx-help.lua | 1410 +++++------ scripts/context/lua/mtx-server-ctx-startup.lua | 78 +- scripts/context/lua/mtx-server.lua | 804 +++--- scripts/context/lua/mtx-texworks.lua | 242 +- scripts/context/lua/mtx-timing.lua | 436 ++-- scripts/context/lua/mtx-tools.lua | 398 +-- scripts/context/lua/mtx-unzip.lua | 264 +- scripts/context/lua/mtx-update.lua | 1352 +++++----- scripts/context/lua/mtx-watch.lua | 862 +++---- 32 files changed, 9643 insertions(+), 9560 deletions(-) (limited to 'scripts') diff --git a/scripts/context/lua/mtx-base.lua b/scripts/context/lua/mtx-base.lua index bd6749717..66fd06624 100644 --- a/scripts/context/lua/mtx-base.lua +++ b/scripts/context/lua/mtx-base.lua @@ -1,134 +1,134 @@ -if not modules then modules = { } end modules ['mtx-base'] = { - version = 1.001, - comment = "formerly known as luatools", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-base - ConTeXt TDS Management Tool (aka luatools) - 1.35 - - - - - generate file database - show configuration variables - show configuration order - expand complex variable - expand variable (resolve paths) - expand variable (resolve references) - show path expansion of ... - report value of variable - report file location - report path of file - [or ] make luatex format - [or ] run luatex format - assemble and compile lua inifile - give a bit more info - show all found files - filter cf format specification (default 'tex', use 'any' for any match) - filter variables - enable given trackers - - - - -]] - -local application = logs.application { - name = "mtx-base", - banner = "ConTeXt TDS Management Tool (aka luatools) 1.35", - helpinfo = helpinfo, -} - -local report = application.report - --- private option --noluc for testing errors in the stub - -local instance = resolvers.instance - -local pattern = environment.arguments["pattern"] or nil -local fileformat = environment.arguments["format"] or "" -- nil ? -local allresults = environment.arguments["all"] or false -local trace = environment.arguments["trace"] - -if type(pattern) == 'boolean' then - report("invalid pattern specification") - pattern = nil -end - -if trace then - resolvers.settrace(trace) -- move to mtxrun ? -end - -if environment.arguments["find-file"] then - resolvers.load() - if pattern then - resolvers.dowithfilesandreport(resolvers.findfiles, { pattern }, fileformat, allresults) - else - resolvers.dowithfilesandreport(resolvers.findfiles, environment.files, fileformat, allresults) - end -elseif environment.arguments["find-path"] then - resolvers.load() - local path = resolvers.findpath(environment.files[1], fileformat) - print(path) -- quite basic, wil become function in logs -elseif environment.arguments["run"] then - resolvers.load("nofiles") -- ! no need for loading databases - trackers.enable("resolvers.locating") - environment.run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "") -elseif environment.arguments["fmt"] then - resolvers.load("nofiles") -- ! no need for loading databases - trackers.enable("resolvers.locating") - environment.run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "") -elseif environment.arguments["expand-braces"] then - resolvers.load("nofiles") - resolvers.dowithfilesandreport(resolvers.expandbraces, environment.files) -elseif environment.arguments["expand-path"] then - resolvers.load("nofiles") - resolvers.dowithfilesandreport(resolvers.expandpath, environment.files) -elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then - resolvers.load("nofiles") - resolvers.dowithfilesandreport(resolvers.expansion, environment.files) -elseif environment.arguments["show-path"] or environment.arguments["path-value"] then - resolvers.load("nofiles") - resolvers.dowithfilesandreport(resolvers.showpath, environment.files) -elseif environment.arguments["var-value"] or environment.arguments["show-value"] then - resolvers.load("nofiles") - resolvers.dowithfilesandreport(resolvers.variable, environment.files) -elseif environment.arguments["format-path"] then - resolvers.load() - report(caches.getwritablepath("format")) -elseif pattern then -- brrr - resolvers.load() - resolvers.dowithfilesandreport(resolvers.findfiles, { pattern }, fileformat, allresults) -elseif environment.arguments["generate"] then - instance.renewcache = true - trackers.enable("resolvers.locating") - resolvers.load() -elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then - resolvers.load() - trackers.enable("resolvers.locating") - environment.make_format(environment.files[1] or "") -elseif environment.arguments["variables"] or environment.arguments["show-variables"] or environment.arguments["expansions"] or environment.arguments["show-expansions"] then - resolvers.load("nofiles") - resolvers.listers.variables(pattern) -elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then - resolvers.load("nofiles") - resolvers.listers.configurations() -elseif environment.arguments["exporthelp"] then - application.export(environment.arguments["exporthelp"],environment.files[1]) -elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then - application.help() -elseif environment.files[1] == 'texmfcnf.lua' then - resolvers.load("nofiles") - resolvers.listers.configurations() -else - resolvers.load() - resolvers.dowithfilesandreport(resolvers.findfiles, environment.files, fileformat, allresults) -end +if not modules then modules = { } end modules ['mtx-base'] = { + version = 1.001, + comment = "formerly known as luatools", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-base + ConTeXt TDS Management Tool (aka luatools) + 1.35 + + + + + generate file database + show configuration variables + show configuration order + expand complex variable + expand variable (resolve paths) + expand variable (resolve references) + show path expansion of ... + report value of variable + report file location + report path of file + [or ] make luatex format + [or ] run luatex format + assemble and compile lua inifile + give a bit more info + show all found files + filter cf format specification (default 'tex', use 'any' for any match) + filter variables + enable given trackers + + + + +]] + +local application = logs.application { + name = "mtx-base", + banner = "ConTeXt TDS Management Tool (aka luatools) 1.35", + helpinfo = helpinfo, +} + +local report = application.report + +-- private option --noluc for testing errors in the stub + +local instance = resolvers.instance + +local pattern = environment.arguments["pattern"] or nil +local fileformat = environment.arguments["format"] or "" -- nil ? +local allresults = environment.arguments["all"] or false +local trace = environment.arguments["trace"] + +if type(pattern) == 'boolean' then + report("invalid pattern specification") + pattern = nil +end + +if trace then + resolvers.settrace(trace) -- move to mtxrun ? +end + +if environment.arguments["find-file"] then + resolvers.load() + if pattern then + resolvers.dowithfilesandreport(resolvers.findfiles, { pattern }, fileformat, allresults) + else + resolvers.dowithfilesandreport(resolvers.findfiles, environment.files, fileformat, allresults) + end +elseif environment.arguments["find-path"] then + resolvers.load() + local path = resolvers.findpath(environment.files[1], fileformat) + print(path) -- quite basic, wil become function in logs +elseif environment.arguments["run"] then + resolvers.load("nofiles") -- ! no need for loading databases + trackers.enable("resolvers.locating") + environment.run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "") +elseif environment.arguments["fmt"] then + resolvers.load("nofiles") -- ! no need for loading databases + trackers.enable("resolvers.locating") + environment.run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "") +elseif environment.arguments["expand-braces"] then + resolvers.load("nofiles") + resolvers.dowithfilesandreport(resolvers.expandbraces, environment.files) +elseif environment.arguments["expand-path"] then + resolvers.load("nofiles") + resolvers.dowithfilesandreport(resolvers.expandpath, environment.files) +elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then + resolvers.load("nofiles") + resolvers.dowithfilesandreport(resolvers.expansion, environment.files) +elseif environment.arguments["show-path"] or environment.arguments["path-value"] then + resolvers.load("nofiles") + resolvers.dowithfilesandreport(resolvers.showpath, environment.files) +elseif environment.arguments["var-value"] or environment.arguments["show-value"] then + resolvers.load("nofiles") + resolvers.dowithfilesandreport(resolvers.variable, environment.files) +elseif environment.arguments["format-path"] then + resolvers.load() + report(caches.getwritablepath("format")) +elseif pattern then -- brrr + resolvers.load() + resolvers.dowithfilesandreport(resolvers.findfiles, { pattern }, fileformat, allresults) +elseif environment.arguments["generate"] then + instance.renewcache = true + trackers.enable("resolvers.locating") + resolvers.load() +elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then + resolvers.load() + trackers.enable("resolvers.locating") + environment.make_format(environment.files[1] or "") +elseif environment.arguments["variables"] or environment.arguments["show-variables"] or environment.arguments["expansions"] or environment.arguments["show-expansions"] then + resolvers.load("nofiles") + resolvers.listers.variables(pattern) +elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then + resolvers.load("nofiles") + resolvers.listers.configurations() +elseif environment.arguments["exporthelp"] then + application.export(environment.arguments["exporthelp"],environment.files[1]) +elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then + application.help() +elseif environment.files[1] == 'texmfcnf.lua' then + resolvers.load("nofiles") + resolvers.listers.configurations() +else + resolvers.load() + resolvers.dowithfilesandreport(resolvers.findfiles, environment.files, fileformat, allresults) +end diff --git a/scripts/context/lua/mtx-cache.lua b/scripts/context/lua/mtx-cache.lua index bff1cb496..7ce5e21be 100644 --- a/scripts/context/lua/mtx-cache.lua +++ b/scripts/context/lua/mtx-cache.lua @@ -1,137 +1,137 @@ -if not modules then modules = { } end modules ['mtx-cache'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-cache - ConTeXt & MetaTeX Cache Management - 0.10 - - - - - remove not used files - completely remove cache - show cache - - - all (not yet implemented) - - - - -]] - -local application = logs.application { - name = "mtx-cache", - banner = "ConTeXt & MetaTeX Cache Management 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.cache = scripts.cache or { } - -local function collect(path) - local all = dir.glob(path .. "/**/*") - local tmas, tmcs, rest = { }, { }, { } - for i=1,#all do - local name = all[i] - local suffix = file.suffix(name) - if suffix == "tma" then - tmas[#tmas+1] = name - elseif suffix == "tmc" then - tmcs[#tmcs+1] = name - else - rest[#rest+1] = name - end - end - return tmas, tmcs, rest, all -end - -local function list(banner,path,tmas,tmcs,rest) - report("%s: %s",banner,path) - report() - report("tma : %4i",#tmas) - report("tmc : %4i",#tmcs) - report("rest : %4i",#rest) - report("total : %4i",#tmas+#tmcs+#rest) - report() -end - -local function purge(banner,path,list,all) - report("%s: %s",banner,path) - report() - local n = 0 - for i=1,#list do - local filename = list[i] - if string.find(filename,"luatex%-cache") then -- safeguard - if all then - os.remove(filename) - n = n + 1 - else - local suffix = file.suffix(filename) - if suffix == "tma" then - local checkname = file.replacesuffix(filename,"tma","tmc") - if lfs.isfile(checkname) then - os.remove(filename) - n = n + 1 - end - end - end - end - end - report("removed tma files : %i",n) - report() - return n -end - -function scripts.cache.purge() - local writable = caches.getwritablepath() - local tmas, tmcs, rest = collect(writable) - list("writable path",writable,tmas,tmcs,rest) - purge("writable path",writable,tmas) - list("writable path",writable,tmas,tmcs,rest) -end - -function scripts.cache.erase() - local writable = caches.getwritablepath() - local tmas, tmcs, rest, all = collect(writable) - list("writable path",writable,tmas,tmcs,rest) - purge("writable path",writable,all,true) - list("writable path",writable,tmas,tmcs,rest) -end - -function scripts.cache.list() - local readables = caches.getreadablepaths() - local writable = caches.getwritablepath() - local tmas, tmcs, rest = collect(writable) - list("writable path",writable,tmas,tmcs,rest) - for i=1,#readables do - local readable = readables[i] - if readable ~= writable then - local tmas, tmcs = collect(readable) - list("readable path",readable,tmas,tmcs,rest) - end - end -end - -if environment.argument("purge") then - scripts.cache.purge() -elseif environment.argument("erase") then - scripts.cache.erase() -elseif environment.argument("list") then - scripts.cache.list() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-cache'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-cache + ConTeXt & MetaTeX Cache Management + 0.10 + + + + + remove not used files + completely remove cache + show cache + + + all (not yet implemented) + + + + +]] + +local application = logs.application { + name = "mtx-cache", + banner = "ConTeXt & MetaTeX Cache Management 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.cache = scripts.cache or { } + +local function collect(path) + local all = dir.glob(path .. "/**/*") + local tmas, tmcs, rest = { }, { }, { } + for i=1,#all do + local name = all[i] + local suffix = file.suffix(name) + if suffix == "tma" then + tmas[#tmas+1] = name + elseif suffix == "tmc" then + tmcs[#tmcs+1] = name + else + rest[#rest+1] = name + end + end + return tmas, tmcs, rest, all +end + +local function list(banner,path,tmas,tmcs,rest) + report("%s: %s",banner,path) + report() + report("tma : %4i",#tmas) + report("tmc : %4i",#tmcs) + report("rest : %4i",#rest) + report("total : %4i",#tmas+#tmcs+#rest) + report() +end + +local function purge(banner,path,list,all) + report("%s: %s",banner,path) + report() + local n = 0 + for i=1,#list do + local filename = list[i] + if string.find(filename,"luatex%-cache") then -- safeguard + if all then + os.remove(filename) + n = n + 1 + else + local suffix = file.suffix(filename) + if suffix == "tma" then + local checkname = file.replacesuffix(filename,"tma","tmc") + if lfs.isfile(checkname) then + os.remove(filename) + n = n + 1 + end + end + end + end + end + report("removed tma files : %i",n) + report() + return n +end + +function scripts.cache.purge() + local writable = caches.getwritablepath() + local tmas, tmcs, rest = collect(writable) + list("writable path",writable,tmas,tmcs,rest) + purge("writable path",writable,tmas) + list("writable path",writable,tmas,tmcs,rest) +end + +function scripts.cache.erase() + local writable = caches.getwritablepath() + local tmas, tmcs, rest, all = collect(writable) + list("writable path",writable,tmas,tmcs,rest) + purge("writable path",writable,all,true) + list("writable path",writable,tmas,tmcs,rest) +end + +function scripts.cache.list() + local readables = caches.getreadablepaths() + local writable = caches.getwritablepath() + local tmas, tmcs, rest = collect(writable) + list("writable path",writable,tmas,tmcs,rest) + for i=1,#readables do + local readable = readables[i] + if readable ~= writable then + local tmas, tmcs = collect(readable) + list("readable path",readable,tmas,tmcs,rest) + end + end +end + +if environment.argument("purge") then + scripts.cache.purge() +elseif environment.argument("erase") then + scripts.cache.erase() +elseif environment.argument("list") then + scripts.cache.list() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-chars.lua b/scripts/context/lua/mtx-chars.lua index 9f6852da2..fa3b3d353 100644 --- a/scripts/context/lua/mtx-chars.lua +++ b/scripts/context/lua/mtx-chars.lua @@ -1,433 +1,433 @@ -if not modules then modules = { } end modules ['mtx-chars'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- obsolete: --stix convert stix table to math table - -local helpinfo = [[ - - - - mtx-chars - MkII Character Table Generators - 0.10 - - - - - generate xetx-*.tex (used by xetex) - generate pdfr-def.tex (used by pdftex) - generate entities table - - - - -]] - -local application = logs.application { - name = "mtx-chars", - banner = "MkII Character Table Generators 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -local format, gmatch, upper, lower = string.format, string.gmatch, string.upper, string.lower -local tonumber = tonumber -local concat = table.concat -local utfchar = utf.char - -scripts = scripts or { } -scripts.chars = scripts.chars or { } - ---~ local banner = [[ ---~ -- filename : char-mth.lua ---~ -- comment : companion to char-mth.tex (in ConTeXt) ---~ -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL ---~ -- license : see context related readme files ---~ -- comment : generated from data file downloaded from STIX website ---~ ---~ if not versions then versions = { } end versions['char-mth'] = 1.001 ---~ if not characters then characters = { } end ---~ ]] ---~ ---~ function scripts.chars.stixtomkiv(inname,outname) ---~ if inname == "" then ---~ report("aquiring math data, invalid datafilename") ---~ end ---~ local f = io.open(inname) ---~ if not f then ---~ report("aquiring math data, invalid datafile") ---~ else ---~ report("aquiring math data, processing %s",inname) ---~ if not outname or outname == "" then ---~ outname = "char-mth.lua" ---~ end ---~ local classes = { ---~ N = "normal", ---~ A = "alphabetic", ---~ D = "diacritic", ---~ P = "punctuation", ---~ B = "binary", ---~ R = "relation", ---~ L = "large", ---~ O = "opening", ---~ C = "closing", ---~ F = "fence" ---~ } ---~ local valid, done = false, { } ---~ local g = io.open(outname,'w') ---~ g:write(banner) ---~ g:write(format("\ncharacters.math = {\n")) ---~ for l in f:lines() do ---~ if not valid then ---~ valid = l:find("AMS/TeX name") ---~ end ---~ if valid then ---~ local unicode = l:sub(2,6) ---~ if unicode:sub(1,1) ~= " " and unicode ~= "" and not done[unicode] then ---~ local mathclass, adobename, texname = l:sub(57,57) or "", l:sub(13,36) or "", l:sub(84,109) or "" ---~ texname, adobename = texname:gsub("[\\ ]",""), adobename:gsub("[\\ ]","") ---~ local t = { } ---~ if mathclass ~= "" then t[#t+1] = format("mathclass='%s'", classes[mathclass] or "unknown") end ---~ if adobename ~= "" then t[#t+1] = format("adobename='%s'", adobename ) end ---~ if texname ~= "" then t[#t+1] = format("texname='%s'" , texname ) end ---~ if #t > 0 then ---~ g:write(format("\t[0x%s] = { %s },\n",unicode, concat(t,", "))) ---~ end ---~ done[unicode] = true ---~ end ---~ end ---~ end ---~ if not valid then ---~ g:write("\t-- The data file is corrupt, invalid or maybe the format has changed.\n") ---~ report("aquiring math data, problems with data table") ---~ else ---~ report("aquiring math data, table saved in %s",outname) ---~ end ---~ g:write("}\n") ---~ g:close() ---~ f:close() ---~ end ---~ end - -function scripts.chars.stixtomkiv(inname,outname) - report("we no longer use this options but use our own tables instead") -end - -local banner_pdf_1 = [[ -% filename : pdfr-def.tex -% comment : generated by mtxrun --script chars --pdf -% author : Hans Hagen, PRAGMA-ADE, Hasselt NL -% copyright: PRAGMA ADE / ConTeXt Development Team -% license : see context related readme files -% -]] - -local banner_pdf_2 = [[ -% -\endinput -]] - -function scripts.chars.makepdfr() - local chartable = resolvers.findfile("char-def.lua") or "" - if chartable ~= "" then - dofile(chartable) - if characters and characters.data then - local f = io.open("pdfr-def.tex", 'w') - if f then - f:write(banner_pdf_1) - local cd = characters.data - local sd = table.sortedkeys(cd) - for i=1,#sd do - local char = cd[sd[i]] - if char.adobename then - f:write(format("\\pdfglyphtounicode{%s}{%04X}%%\n",char.adobename,char.unicodeslot)) - end - end - f:write(banner_pdf_2) - f:close() - end - end - end -end - -local banner_utf_module = [[ -%% filename : %s -%% comment : generated by mtxrun --script chars --xtx -%% author : Hans Hagen, PRAGMA-ADE, Hasselt NL -%% copyright: PRAGMA ADE / ConTeXt Development Team -%% license : see context related readme files -]] - -local banner_utf_mappings = [[ - -% lc/uc/catcode mappings - -]] - -local banner_utf_patch = [[ - -% patch needed for turkish - -\setXTXcharcodes "201C "201C "201C -\setXTXcharcodes "201D "201D "201D - -% patch needed for french - -\setXTXcharcodes "2019 "2019 "2019 - -]] - -local banner_utf_names = [[ - -% named characters mapped onto utf (\\char is needed for accents) - -]] - -local banner_utf_classes = [[ - -% some character classes for xetex; seems to be rather hard coded, these numbers -% and also a mix of several classes; here we do linebreaks - -]] - -local banner_utf_finish = [[ - -\endinput -]] - -local xtxclasses = { - id = 1, - ex = 3, - is = 3, - cm = 256, - op = 2, - ns = 3, - cl = 3, -} - -function scripts.chars.makeencoutf() - local chartable = resolvers.findfile("char-def.lua") or "" - if chartable ~= "" then - dofile(chartable) - local function open(name,banner) - local f = io.open(name,'w') - if f then - report("writing '%s'",name) - f:write(format(banner_utf_module,name)) - f:write(banner) - f:write() - return f - end - end - local function close(f) - f:write(banner_utf_finish) - f:close() - end - local data = characters and characters.data - if data then - local list = table.sortedkeys(characters.data) - local f = open("xetx-utf.tex",banner_utf_mappings) - if f then - for i=1,#list do - local code = list[i] - if code <= 0xFFFF then - local chr = data[code] - local cc = chr.category - if cc == 'll' or cc == 'lu' or cc == 'lt' then - if not chr.lccode then chr.lccode = code end - if not chr.uccode then chr.uccode = code end - f:write(format('\\setXTXcharcodes "%05X "%05X "%05X %% %s\n',code,chr.lccode,chr.uccode,chr.description)) - end - end - end - f:write("\n") - for i=1,#list do - local code = list[i] - local chr = data[code] - if chr and chr.range then - local cc = chr.category - if cc == 'lo' then - f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharcodes\\recurselevel\\recurselevel\\recurselevel}\n',code,chr.range)) - end - end - end - f:write(banner_utf_patch) - close(f) - end - local f = open("xetx-chr.tex",banner_utf_names) - if f then - local length = 0 - for i=1,#list do - local code = list[i] - if code > 0x5B and code <= 0xFFFF then - local chr = data[code] - if chr and #(chr.contextname or "") > length then - length = #chr.contextname - end - end - end - local template = "\\def\\%-".. length .. "s{\\char\"%05X } %% %s: %s\n" - for i=1,#list do - local code = list[i] - if code > 0x5B and code <= 0xFFFF then - local chr = data[code] - if chr and chr.contextname then - local ch = utfchar(code) - f:write(format(template, chr.contextname, code, chr.description, ch)) - end - end - end - close(f) - end - local f = open("xetx-cls.tex",banner_utf_classes) - if f then - for k, v in next, xtxclasses do - f:write(format("\\defineXTXcharinjectionclass[lb:%s]\n",k)) - end - f:write("\n") - local i_first, i_last, i_clb = nil, nil, nil - local function flush() - if i_first then - if i_first == i_last then - f:write(format('\\dosetXTXcharacterclass{"%05X}{lb:%s}\n',i_first,i_clb)) - else - f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',i_first,i_last,i_clb)) - end - end - i_first, i_last, i_clb = nil, nil, nil - end - for i=1,#list do - local code = list[i] - local code_next = list[i+1] - local chr = data[code] - local chr_next = data[code_next] - local clb = chr and chr.linebreak - local lbc = xtxclasses[clb] - if not lbc then - flush() - elseif clb == i_clb then - if i_first then - i_last = code - else - i_first, i_last, i_clb = code, code, clb - end - else - flush() - i_first, i_last, i_clb = code, code, clb - end - end - flush() - f:write("\n") - for i=1,#list do - local code = list[i] - local chr = data[code] - if chr and chr.range then - local lbc = chr.linebreak - if xtxclasses[lbc] then - f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',code,chr.range,lbc)) - end - end - end - close(f) - end - end - end -end - -local entityfiles = { - "http://www.w3.org/2003/entities/2007/w3centities-f.ent", - "http://www.w3.org/2003/entities/2007/htmlmathml-f.ent", -} - -function scripts.chars.xmlentities() - local done = { } - local entities = { "local entities = utilities.storage.allocate {" } - for i=1,#entityfiles do - local f = entityfiles[i] - local s = url.hashed(f) - local b = file.basename(s.path) - local n = resolvers.findfile(b) - local data = io.loaddata(n) - for name, value in gmatch(data,'') do - if not done[name] then - done[name] = true - local str, hex - local low = lower(name) - if name == "newline" then - -- let's forget about that one - elseif name == "lt" then - str, hex = "<", format("%s %05X",hex,c) - elseif name == "gt" then - str, hex = ">", format("%s %05X",hex,c) - elseif name == "amp" then - str, hex = "&", format("%s %05X",hex,c) - else - for t, c in gmatch(value,"&#([x]*)([^;]+);") do - if t == "x" then - c = tonumber(c,16) - else - c = tonumber(c) - end - if str then - str, hex = str .. utfchar(c), format("%s %05X",hex,c) - else - str, hex = utfchar(c), format("U+%05X",c) - end - end - end - if str and hex then - entities[#entities+1] = format(' ["%s"] = %q, -- %s',name,str,hex) - end - end - end - end - entities[#entities+1] = "}" - io.savedata("xmlentities.tmp",concat(entities,"\n")) -end - -if environment.argument("stix") then - local inname = environment.files[1] or "" - local outname = environment.files[2] or "" - scripts.chars.stixtomkiv(inname,outname) -elseif environment.argument("entities") then - scripts.chars.xmlentities() -elseif environment.argument("xtx") then - scripts.chars.makeencoutf() -elseif environment.argument("pdf") then - scripts.chars.makepdfr() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end - --- local http = require("socket.http") --- local ltn12 = require("ltn12") --- --- local t = { } --- local status, message = http.request { --- url = f, --- sink = ltn12.sink.table(t) --- } --- --- local template = [[ --- --- --- --- --- This is just a placeholder. --- ]] --- --- local e = string.format(template,io.loaddata(n)) --- local x = xml.convert(e, { utfize_entities = true } ) --- local entities = x.entities +if not modules then modules = { } end modules ['mtx-chars'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- obsolete: --stix convert stix table to math table + +local helpinfo = [[ + + + + mtx-chars + MkII Character Table Generators + 0.10 + + + + + generate xetx-*.tex (used by xetex) + generate pdfr-def.tex (used by pdftex) + generate entities table + + + + +]] + +local application = logs.application { + name = "mtx-chars", + banner = "MkII Character Table Generators 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +local format, gmatch, upper, lower = string.format, string.gmatch, string.upper, string.lower +local tonumber = tonumber +local concat = table.concat +local utfchar = utf.char + +scripts = scripts or { } +scripts.chars = scripts.chars or { } + +--~ local banner = [[ +--~ -- filename : char-mth.lua +--~ -- comment : companion to char-mth.tex (in ConTeXt) +--~ -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL +--~ -- license : see context related readme files +--~ -- comment : generated from data file downloaded from STIX website +--~ +--~ if not versions then versions = { } end versions['char-mth'] = 1.001 +--~ if not characters then characters = { } end +--~ ]] +--~ +--~ function scripts.chars.stixtomkiv(inname,outname) +--~ if inname == "" then +--~ report("aquiring math data, invalid datafilename") +--~ end +--~ local f = io.open(inname) +--~ if not f then +--~ report("aquiring math data, invalid datafile") +--~ else +--~ report("aquiring math data, processing %s",inname) +--~ if not outname or outname == "" then +--~ outname = "char-mth.lua" +--~ end +--~ local classes = { +--~ N = "normal", +--~ A = "alphabetic", +--~ D = "diacritic", +--~ P = "punctuation", +--~ B = "binary", +--~ R = "relation", +--~ L = "large", +--~ O = "opening", +--~ C = "closing", +--~ F = "fence" +--~ } +--~ local valid, done = false, { } +--~ local g = io.open(outname,'w') +--~ g:write(banner) +--~ g:write(format("\ncharacters.math = {\n")) +--~ for l in f:lines() do +--~ if not valid then +--~ valid = l:find("AMS/TeX name") +--~ end +--~ if valid then +--~ local unicode = l:sub(2,6) +--~ if unicode:sub(1,1) ~= " " and unicode ~= "" and not done[unicode] then +--~ local mathclass, adobename, texname = l:sub(57,57) or "", l:sub(13,36) or "", l:sub(84,109) or "" +--~ texname, adobename = texname:gsub("[\\ ]",""), adobename:gsub("[\\ ]","") +--~ local t = { } +--~ if mathclass ~= "" then t[#t+1] = format("mathclass='%s'", classes[mathclass] or "unknown") end +--~ if adobename ~= "" then t[#t+1] = format("adobename='%s'", adobename ) end +--~ if texname ~= "" then t[#t+1] = format("texname='%s'" , texname ) end +--~ if #t > 0 then +--~ g:write(format("\t[0x%s] = { %s },\n",unicode, concat(t,", "))) +--~ end +--~ done[unicode] = true +--~ end +--~ end +--~ end +--~ if not valid then +--~ g:write("\t-- The data file is corrupt, invalid or maybe the format has changed.\n") +--~ report("aquiring math data, problems with data table") +--~ else +--~ report("aquiring math data, table saved in %s",outname) +--~ end +--~ g:write("}\n") +--~ g:close() +--~ f:close() +--~ end +--~ end + +function scripts.chars.stixtomkiv(inname,outname) + report("we no longer use this options but use our own tables instead") +end + +local banner_pdf_1 = [[ +% filename : pdfr-def.tex +% comment : generated by mtxrun --script chars --pdf +% author : Hans Hagen, PRAGMA-ADE, Hasselt NL +% copyright: PRAGMA ADE / ConTeXt Development Team +% license : see context related readme files +% +]] + +local banner_pdf_2 = [[ +% +\endinput +]] + +function scripts.chars.makepdfr() + local chartable = resolvers.findfile("char-def.lua") or "" + if chartable ~= "" then + dofile(chartable) + if characters and characters.data then + local f = io.open("pdfr-def.tex", 'w') + if f then + f:write(banner_pdf_1) + local cd = characters.data + local sd = table.sortedkeys(cd) + for i=1,#sd do + local char = cd[sd[i]] + if char.adobename then + f:write(format("\\pdfglyphtounicode{%s}{%04X}%%\n",char.adobename,char.unicodeslot)) + end + end + f:write(banner_pdf_2) + f:close() + end + end + end +end + +local banner_utf_module = [[ +%% filename : %s +%% comment : generated by mtxrun --script chars --xtx +%% author : Hans Hagen, PRAGMA-ADE, Hasselt NL +%% copyright: PRAGMA ADE / ConTeXt Development Team +%% license : see context related readme files +]] + +local banner_utf_mappings = [[ + +% lc/uc/catcode mappings + +]] + +local banner_utf_patch = [[ + +% patch needed for turkish + +\setXTXcharcodes "201C "201C "201C +\setXTXcharcodes "201D "201D "201D + +% patch needed for french + +\setXTXcharcodes "2019 "2019 "2019 + +]] + +local banner_utf_names = [[ + +% named characters mapped onto utf (\\char is needed for accents) + +]] + +local banner_utf_classes = [[ + +% some character classes for xetex; seems to be rather hard coded, these numbers +% and also a mix of several classes; here we do linebreaks + +]] + +local banner_utf_finish = [[ + +\endinput +]] + +local xtxclasses = { + id = 1, + ex = 3, + is = 3, + cm = 256, + op = 2, + ns = 3, + cl = 3, +} + +function scripts.chars.makeencoutf() + local chartable = resolvers.findfile("char-def.lua") or "" + if chartable ~= "" then + dofile(chartable) + local function open(name,banner) + local f = io.open(name,'w') + if f then + report("writing '%s'",name) + f:write(format(banner_utf_module,name)) + f:write(banner) + f:write() + return f + end + end + local function close(f) + f:write(banner_utf_finish) + f:close() + end + local data = characters and characters.data + if data then + local list = table.sortedkeys(characters.data) + local f = open("xetx-utf.tex",banner_utf_mappings) + if f then + for i=1,#list do + local code = list[i] + if code <= 0xFFFF then + local chr = data[code] + local cc = chr.category + if cc == 'll' or cc == 'lu' or cc == 'lt' then + if not chr.lccode then chr.lccode = code end + if not chr.uccode then chr.uccode = code end + f:write(format('\\setXTXcharcodes "%05X "%05X "%05X %% %s\n',code,chr.lccode,chr.uccode,chr.description)) + end + end + end + f:write("\n") + for i=1,#list do + local code = list[i] + local chr = data[code] + if chr and chr.range then + local cc = chr.category + if cc == 'lo' then + f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharcodes\\recurselevel\\recurselevel\\recurselevel}\n',code,chr.range)) + end + end + end + f:write(banner_utf_patch) + close(f) + end + local f = open("xetx-chr.tex",banner_utf_names) + if f then + local length = 0 + for i=1,#list do + local code = list[i] + if code > 0x5B and code <= 0xFFFF then + local chr = data[code] + if chr and #(chr.contextname or "") > length then + length = #chr.contextname + end + end + end + local template = "\\def\\%-".. length .. "s{\\char\"%05X } %% %s: %s\n" + for i=1,#list do + local code = list[i] + if code > 0x5B and code <= 0xFFFF then + local chr = data[code] + if chr and chr.contextname then + local ch = utfchar(code) + f:write(format(template, chr.contextname, code, chr.description, ch)) + end + end + end + close(f) + end + local f = open("xetx-cls.tex",banner_utf_classes) + if f then + for k, v in next, xtxclasses do + f:write(format("\\defineXTXcharinjectionclass[lb:%s]\n",k)) + end + f:write("\n") + local i_first, i_last, i_clb = nil, nil, nil + local function flush() + if i_first then + if i_first == i_last then + f:write(format('\\dosetXTXcharacterclass{"%05X}{lb:%s}\n',i_first,i_clb)) + else + f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',i_first,i_last,i_clb)) + end + end + i_first, i_last, i_clb = nil, nil, nil + end + for i=1,#list do + local code = list[i] + local code_next = list[i+1] + local chr = data[code] + local chr_next = data[code_next] + local clb = chr and chr.linebreak + local lbc = xtxclasses[clb] + if not lbc then + flush() + elseif clb == i_clb then + if i_first then + i_last = code + else + i_first, i_last, i_clb = code, code, clb + end + else + flush() + i_first, i_last, i_clb = code, code, clb + end + end + flush() + f:write("\n") + for i=1,#list do + local code = list[i] + local chr = data[code] + if chr and chr.range then + local lbc = chr.linebreak + if xtxclasses[lbc] then + f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',code,chr.range,lbc)) + end + end + end + close(f) + end + end + end +end + +local entityfiles = { + "http://www.w3.org/2003/entities/2007/w3centities-f.ent", + "http://www.w3.org/2003/entities/2007/htmlmathml-f.ent", +} + +function scripts.chars.xmlentities() + local done = { } + local entities = { "local entities = utilities.storage.allocate {" } + for i=1,#entityfiles do + local f = entityfiles[i] + local s = url.hashed(f) + local b = file.basename(s.path) + local n = resolvers.findfile(b) + local data = io.loaddata(n) + for name, value in gmatch(data,'') do + if not done[name] then + done[name] = true + local str, hex + local low = lower(name) + if name == "newline" then + -- let's forget about that one + elseif name == "lt" then + str, hex = "<", format("%s %05X",hex,c) + elseif name == "gt" then + str, hex = ">", format("%s %05X",hex,c) + elseif name == "amp" then + str, hex = "&", format("%s %05X",hex,c) + else + for t, c in gmatch(value,"&#([x]*)([^;]+);") do + if t == "x" then + c = tonumber(c,16) + else + c = tonumber(c) + end + if str then + str, hex = str .. utfchar(c), format("%s %05X",hex,c) + else + str, hex = utfchar(c), format("U+%05X",c) + end + end + end + if str and hex then + entities[#entities+1] = format(' ["%s"] = %q, -- %s',name,str,hex) + end + end + end + end + entities[#entities+1] = "}" + io.savedata("xmlentities.tmp",concat(entities,"\n")) +end + +if environment.argument("stix") then + local inname = environment.files[1] or "" + local outname = environment.files[2] or "" + scripts.chars.stixtomkiv(inname,outname) +elseif environment.argument("entities") then + scripts.chars.xmlentities() +elseif environment.argument("xtx") then + scripts.chars.makeencoutf() +elseif environment.argument("pdf") then + scripts.chars.makepdfr() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end + +-- local http = require("socket.http") +-- local ltn12 = require("ltn12") +-- +-- local t = { } +-- local status, message = http.request { +-- url = f, +-- sink = ltn12.sink.table(t) +-- } +-- +-- local template = [[ +-- +-- +-- +-- +-- This is just a placeholder. +-- ]] +-- +-- local e = string.format(template,io.loaddata(n)) +-- local x = xml.convert(e, { utfize_entities = true } ) +-- local entities = x.entities diff --git a/scripts/context/lua/mtx-check.lua b/scripts/context/lua/mtx-check.lua index 9f52509ec..bddb2e139 100644 --- a/scripts/context/lua/mtx-check.lua +++ b/scripts/context/lua/mtx-check.lua @@ -1,253 +1,253 @@ -if not modules then modules = { } end modules ['mtx-check'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local P, R, S, V, C, CP, CC, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cp, lpeg.Cc, lpeg.match -local gsub, sub, format = string.gsub, string.sub, string.format -local insert, remove = table.insert, table.remove - -local helpinfo = [[ - - - - mtx-check - Basic ConTeXt Syntax Checking - 0.10 - - - - - check tex file for errors - - - - -]] - -local application = logs.application { - name = "mtx-check", - banner = "Basic ConTeXt Syntax Checking 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.checker = scripts.checker or { } - -local validator = { } - -validator.n = 1 -validator.errors = { } -validator.trace = false -validator.direct = false - -validator.printer = print -validator.tracer = print - -local message = function(position, kind, extra) - local ve = validator.errors - ve[#ve+1] = { kind, position, validator.n, extra } - if validator.direct then - position = position or "eof" - if extra then - validator.printer(format("%s error at position %s (line %s) (%s)",kind,position,validator.n,extra)) - else - validator.printer(format("%s error at position %s (line %s)",kind,position,validator.n)) - end - end -end - -local progress = function(position, data, kind) - if validator.trace then - validator.tracer(format("%s at position %s: %s", kind, position, data or "")) - end -end - -local i_m, d_m = P("$"), P("$$") -local l_s, r_s = P("["), P("]") -local l_g, r_g = P("{"), P("}") - -local okay = lpeg.P("{[}") + lpeg.P("{]}") - -local esc = P("\\") -local cr = P("\r") -local lf = P("\n") -local crlf = P("\r\n") -local space = S(" \t\f\v") -local newline = crlf + cr + lf - -local line = newline / function() validator.n = validator.n + 1 end - -local startluacode = P("\\startluacode") -local stopluacode = P("\\stopluacode") - -local somecode = startluacode * (1-stopluacode)^1 * stopluacode - -local stack = { } - -local function push(p,s) --- print("start",p,s) - insert(stack,{ p, s, validator.n }) -end - -local function pop(p,s) --- print("stop",p,s) - local top = remove(stack) - if not top then - message(p,"missing start") - elseif top[2] ~= s then - message(p,"missing stop",format("see line %s",top[3])) - else - -- okay - end -end - -local cstoken = R("az","AZ","\127\255") - -local start = CP() * P("\\start") * C(cstoken^0) / push -local stop = CP() * P("\\stop") * C(cstoken^0) / pop - -local contextgrammar = P { "tokens", - ["tokens"] = (V("ignore") + V("start") + V("stop") + V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0, - ["start"] = start, - ["stop"] = stop, - ["whatever"] = line + esc * 1 + C(P("%") * (1-line)^0), - ["grouped"] = l_g * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_g - r_g))^0 * r_g, - ["setup"] = l_s * (okay + V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_s - r_s))^0 * r_s, - ["display"] = d_m * (V("whatever") + V("grouped") + (1 - d_m))^0 * d_m, - ["inline"] = i_m * (V("whatever") + V("grouped") + (1 - i_m))^0 * i_m, - ["errors"] = V("gerror") + V("serror") + V("derror") + V("ierror"), - ["gerror"] = CP() * (l_g + r_g) * CC("grouping error") / message, - ["serror"] = CP() * (l_s + r_g) * CC("setup error") / message, - ["derror"] = CP() * d_m * CC("display math error") / message, - ["ierror"] = CP() * i_m * CC("inline math error") / message, - ["ignore"] = somecode, -} - --- metafun variant - -local function push(p,s) - insert(stack,{ p, s, validator.n }) -end - -local function pop(p,s) - local top = remove(stack) - if not top then - message(p,"missing def") - end -end - -local function finish(p) - local bot = stack[1] - if bot then - message(false,format("missing enddef for %s",bot[2]),format("see line %s",bot[3])) - end - stack = { } -end - -local l_b, r_b = P("["), P("]") -local l_g, r_g = P("{"), P("}") -local l_p, r_p = P("("), P(")") - -local start = CP() * C( P("vardef") + P("primarydef") + P("secondarydef") + P("tertiarydef") + P("def") ) / push -local stop = CP() * C( P("enddef") ) / pop - -local dstring = P('"') * (1-P('"'))^0 * P('"') -local semicolon = P(";") - -local separator = line + space + semicolon - --- todo: start/stop also in () - -local metafungrammar = P { "tokens", - ["tokens"] = (V("start") + V("stop") + V("string") + V("whatever") + V("braces") + V("brackets") + V("parentheses") + V("errors") + 1)^0 - * (CP() / finish), - ["start"] = separator * start * #separator, - ["stop"] = separator * stop * #separator, - ["string"] = dstring, - ["whatever"] = line + C(P("%") * (1-line)^0), - ["braces"] = l_g * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_g - r_g))^0 * r_g, - ["brackets"] = l_b * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_b - r_b))^0 * r_b, - ["parentheses"] = l_p * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_p - r_p))^0 * r_p, - ["errors"] = V("gerror") + V("berror") + V("perror"), - ["gerror"] = CP() * (l_g + r_g) * CC("braces error") / message, - ["berror"] = CP() * (l_b + r_b) * CC("brackets error") / message, - ["perror"] = CP() * (l_p + r_p) * CC("parentheses error") / message, -} - -local grammars = { - mp = metafungrammar, - mpii = metafungrammar, - mpiv = metafungrammar, - tex = contextgrammar, - mkii = contextgrammar, - mkiv = contextgrammar, -} - -function validator.check(str,filetype) - validator.n = 1 - validator.errors = { } - local grammar = grammars[filetype] or grammars.tex - lpegmatch(grammar,str) -end - ---~ str = [[ ---~ a{oeps {oe\{\}ps} } ---~ test { oeps \} \[\] oeps \setupxxx[oeps=bla]} ---~ test $$ \hbox{$ oeps \} \[\] oeps $} $$ ---~ {$x\$xx$ $ ---~ ]] ---~ str = string.rep(str,10) - -local remapper = { - ["\n"] = " ", - ["\r"] = " ", - ["\t"] = " ", -} - -function scripts.checker.check(filename) - local str = io.loaddata(filename) - if str then - validator.check(str,file.suffix(filename)) - local errors = validator.errors - if #errors > 0 then - for k=1,#errors do - local v = errors[k] - local kind, position, line, extra = v[1], v[2], v[3], v[4] - if not position then - position = #str - end - local data = sub(str,position-30,position+30) - data = gsub(data,".", remapper) - data = gsub(data,"^ *","") - if extra then - print(format("% 5i %-10s %s (%s)", line, kind, data, extra)) - else - print(format("% 5i %-10s %s", line, kind, data)) - end - end - else - print("no error") - end - else - print("no file") - end -end - -if environment.argument("check") then - scripts.checker.check(environment.files[1]) -elseif environment.argument("help") then - application.help() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -elseif environment.files[1] then - scripts.checker.check(environment.files[1]) -else - application.help() -end - +if not modules then modules = { } end modules ['mtx-check'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local P, R, S, V, C, CP, CC, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cp, lpeg.Cc, lpeg.match +local gsub, sub, format = string.gsub, string.sub, string.format +local insert, remove = table.insert, table.remove + +local helpinfo = [[ + + + + mtx-check + Basic ConTeXt Syntax Checking + 0.10 + + + + + check tex file for errors + + + + +]] + +local application = logs.application { + name = "mtx-check", + banner = "Basic ConTeXt Syntax Checking 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.checker = scripts.checker or { } + +local validator = { } + +validator.n = 1 +validator.errors = { } +validator.trace = false +validator.direct = false + +validator.printer = print +validator.tracer = print + +local message = function(position, kind, extra) + local ve = validator.errors + ve[#ve+1] = { kind, position, validator.n, extra } + if validator.direct then + position = position or "eof" + if extra then + validator.printer(format("%s error at position %s (line %s) (%s)",kind,position,validator.n,extra)) + else + validator.printer(format("%s error at position %s (line %s)",kind,position,validator.n)) + end + end +end + +local progress = function(position, data, kind) + if validator.trace then + validator.tracer(format("%s at position %s: %s", kind, position, data or "")) + end +end + +local i_m, d_m = P("$"), P("$$") +local l_s, r_s = P("["), P("]") +local l_g, r_g = P("{"), P("}") + +local okay = lpeg.P("{[}") + lpeg.P("{]}") + +local esc = P("\\") +local cr = P("\r") +local lf = P("\n") +local crlf = P("\r\n") +local space = S(" \t\f\v") +local newline = crlf + cr + lf + +local line = newline / function() validator.n = validator.n + 1 end + +local startluacode = P("\\startluacode") +local stopluacode = P("\\stopluacode") + +local somecode = startluacode * (1-stopluacode)^1 * stopluacode + +local stack = { } + +local function push(p,s) +-- print("start",p,s) + insert(stack,{ p, s, validator.n }) +end + +local function pop(p,s) +-- print("stop",p,s) + local top = remove(stack) + if not top then + message(p,"missing start") + elseif top[2] ~= s then + message(p,"missing stop",format("see line %s",top[3])) + else + -- okay + end +end + +local cstoken = R("az","AZ","\127\255") + +local start = CP() * P("\\start") * C(cstoken^0) / push +local stop = CP() * P("\\stop") * C(cstoken^0) / pop + +local contextgrammar = P { "tokens", + ["tokens"] = (V("ignore") + V("start") + V("stop") + V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0, + ["start"] = start, + ["stop"] = stop, + ["whatever"] = line + esc * 1 + C(P("%") * (1-line)^0), + ["grouped"] = l_g * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_g - r_g))^0 * r_g, + ["setup"] = l_s * (okay + V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_s - r_s))^0 * r_s, + ["display"] = d_m * (V("whatever") + V("grouped") + (1 - d_m))^0 * d_m, + ["inline"] = i_m * (V("whatever") + V("grouped") + (1 - i_m))^0 * i_m, + ["errors"] = V("gerror") + V("serror") + V("derror") + V("ierror"), + ["gerror"] = CP() * (l_g + r_g) * CC("grouping error") / message, + ["serror"] = CP() * (l_s + r_g) * CC("setup error") / message, + ["derror"] = CP() * d_m * CC("display math error") / message, + ["ierror"] = CP() * i_m * CC("inline math error") / message, + ["ignore"] = somecode, +} + +-- metafun variant + +local function push(p,s) + insert(stack,{ p, s, validator.n }) +end + +local function pop(p,s) + local top = remove(stack) + if not top then + message(p,"missing def") + end +end + +local function finish(p) + local bot = stack[1] + if bot then + message(false,format("missing enddef for %s",bot[2]),format("see line %s",bot[3])) + end + stack = { } +end + +local l_b, r_b = P("["), P("]") +local l_g, r_g = P("{"), P("}") +local l_p, r_p = P("("), P(")") + +local start = CP() * C( P("vardef") + P("primarydef") + P("secondarydef") + P("tertiarydef") + P("def") ) / push +local stop = CP() * C( P("enddef") ) / pop + +local dstring = P('"') * (1-P('"'))^0 * P('"') +local semicolon = P(";") + +local separator = line + space + semicolon + +-- todo: start/stop also in () + +local metafungrammar = P { "tokens", + ["tokens"] = (V("start") + V("stop") + V("string") + V("whatever") + V("braces") + V("brackets") + V("parentheses") + V("errors") + 1)^0 + * (CP() / finish), + ["start"] = separator * start * #separator, + ["stop"] = separator * stop * #separator, + ["string"] = dstring, + ["whatever"] = line + C(P("%") * (1-line)^0), + ["braces"] = l_g * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_g - r_g))^0 * r_g, + ["brackets"] = l_b * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_b - r_b))^0 * r_b, + ["parentheses"] = l_p * (V("whatever") + V("string") + V("braces") + V("brackets") + V("parentheses") + (1 - l_p - r_p))^0 * r_p, + ["errors"] = V("gerror") + V("berror") + V("perror"), + ["gerror"] = CP() * (l_g + r_g) * CC("braces error") / message, + ["berror"] = CP() * (l_b + r_b) * CC("brackets error") / message, + ["perror"] = CP() * (l_p + r_p) * CC("parentheses error") / message, +} + +local grammars = { + mp = metafungrammar, + mpii = metafungrammar, + mpiv = metafungrammar, + tex = contextgrammar, + mkii = contextgrammar, + mkiv = contextgrammar, +} + +function validator.check(str,filetype) + validator.n = 1 + validator.errors = { } + local grammar = grammars[filetype] or grammars.tex + lpegmatch(grammar,str) +end + +--~ str = [[ +--~ a{oeps {oe\{\}ps} } +--~ test { oeps \} \[\] oeps \setupxxx[oeps=bla]} +--~ test $$ \hbox{$ oeps \} \[\] oeps $} $$ +--~ {$x\$xx$ $ +--~ ]] +--~ str = string.rep(str,10) + +local remapper = { + ["\n"] = " ", + ["\r"] = " ", + ["\t"] = " ", +} + +function scripts.checker.check(filename) + local str = io.loaddata(filename) + if str then + validator.check(str,file.suffix(filename)) + local errors = validator.errors + if #errors > 0 then + for k=1,#errors do + local v = errors[k] + local kind, position, line, extra = v[1], v[2], v[3], v[4] + if not position then + position = #str + end + local data = sub(str,position-30,position+30) + data = gsub(data,".", remapper) + data = gsub(data,"^ *","") + if extra then + print(format("% 5i %-10s %s (%s)", line, kind, data, extra)) + else + print(format("% 5i %-10s %s", line, kind, data)) + end + end + else + print("no error") + end + else + print("no file") + end +end + +if environment.argument("check") then + scripts.checker.check(environment.files[1]) +elseif environment.argument("help") then + application.help() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +elseif environment.files[1] then + scripts.checker.check(environment.files[1]) +else + application.help() +end + diff --git a/scripts/context/lua/mtx-colors.lua b/scripts/context/lua/mtx-colors.lua index 7dd1b4ac4..cd7dcce62 100644 --- a/scripts/context/lua/mtx-colors.lua +++ b/scripts/context/lua/mtx-colors.lua @@ -1,77 +1,77 @@ -if not modules then modules = { } end modules ['mtx-colors'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory - -local helpinfo = [[ - - - - mtx-colors - ConTeXt Color Management - 0.10 - - - - - show icc table - - - - - - Example - - mtxrun --script color --table somename - - - - -]] - -local application = logs.application { - name = "mtx-colors", - banner = "ConTeXt Color Management 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -if not fontloader then fontloader = fontforge end - -dofile(resolvers.findfile("colo-icc.lua","tex")) - -scripts = scripts or { } -scripts.colors = scripts.colors or { } - -function scripts.colors.table() - local files = environment.files - if #files > 0 then - for i=1,#files do - local profile, okay, message = colors.iccprofile(files[i]) - if not okay then - report(message) - else - report(table.serialize(profile,"profile")) - end - end - else - report("no file(s) given" ) - end -end - ---~ local track = environment.argument("track") ---~ if track then trackers.enable(track) end - -if environment.argument("table") then - scripts.colors.table() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-colors'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory + +local helpinfo = [[ + + + + mtx-colors + ConTeXt Color Management + 0.10 + + + + + show icc table + + + + + + Example + + mtxrun --script color --table somename + + + + +]] + +local application = logs.application { + name = "mtx-colors", + banner = "ConTeXt Color Management 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +if not fontloader then fontloader = fontforge end + +dofile(resolvers.findfile("colo-icc.lua","tex")) + +scripts = scripts or { } +scripts.colors = scripts.colors or { } + +function scripts.colors.table() + local files = environment.files + if #files > 0 then + for i=1,#files do + local profile, okay, message = colors.iccprofile(files[i]) + if not okay then + report(message) + else + report(table.serialize(profile,"profile")) + end + end + else + report("no file(s) given" ) + end +end + +--~ local track = environment.argument("track") +--~ if track then trackers.enable(track) end + +if environment.argument("table") then + scripts.colors.table() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 87ed3475d..3c2311eef 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -1,1492 +1,1492 @@ -if not modules then modules = { } end modules ['mtx-context'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo: more local functions --- todo: pass jobticket/ctxdata table around - -local type, next, tostring, tonumber = type, next, tostring, tonumber -local format, gmatch, match, gsub, find = string.format, string.gmatch, string.match, string.gsub, string.find -local quote, validstring = string.quote, string.valid -local concat = table.concat -local settings_to_array = utilities.parsers.settings_to_array -local appendtable = table.append -local lpegpatterns, lpegmatch, Cs, P = lpeg.patterns, lpeg.match, lpeg.Cs, lpeg.P - -local getargument = environment.getargument or environment.argument -local setargument = environment.setargument - -local application = logs.application { - name = "mtx-context", - banner = "ConTeXt Process Management 0.60", - -- helpinfo = helpinfo, -- table with { category_a = text_1, category_b = text_2 } or helpstring or xml_blob - helpinfo = "mtx-context.xml", -} - --- local luatexflags = { --- ["8bit"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["default-translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["etex"] = true, -- ignored, the etex extensions are always active --- --- ["credits"] = true, -- display credits and exit --- ["debug-format"] = true, -- enable format debugging --- ["disable-write18"] = true, -- disable \write18{SHELL COMMAND} --- ["draftmode"] = true, -- switch on draft mode (generates no output PDF) --- ["enable-write18"] = true, -- enable \write18{SHELL COMMAND} --- ["file-line-error"] = true, -- enable file:line:error style messages --- ["file-line-error-style"] = true, -- aliases of --file-line-error --- ["no-file-line-error"] = true, -- disable file:line:error style messages --- ["no-file-line-error-style"] = true, -- aliases of --no-file-line-error --- ["fmt"] = true, -- load the format file FORMAT --- ["halt-on-error"] = true, -- stop processing at the first error --- ["help"] = true, -- display help and exit --- ["ini"] = true, -- be iniluatex, for dumping formats --- ["interaction"] = true, -- set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode) --- ["jobname"] = true, -- set the job name to STRING --- ["kpathsea-debug"] = true, -- set path searching debugging flags according to the bits of NUMBER --- ["lua"] = true, -- load and execute a lua initialization script --- ["mktex"] = true, -- enable mktexFMT generation (FMT=tex/tfm) --- ["no-mktex"] = true, -- disable mktexFMT generation (FMT=tex/tfm) --- ["nosocket"] = true, -- disable the lua socket library --- ["output-comment"] = true, -- use STRING for DVI file comment instead of date (no effect for PDF) --- ["output-directory"] = true, -- use existing DIR as the directory to write files in --- ["output-format"] = true, -- use FORMAT for job output; FORMAT is 'dvi' or 'pdf' --- ["parse-first-line"] = true, -- enable parsing of the first line of the input file --- ["no-parse-first-line"] = true, -- disable parsing of the first line of the input file --- ["progname"] = true, -- set the program name to STRING --- ["recorder"] = true, -- enable filename recorder --- ["safer"] = true, -- disable easily exploitable lua commands --- ["shell-escape"] = true, -- enable \write18{SHELL COMMAND} --- ["no-shell-escape"] = true, -- disable \write18{SHELL COMMAND} --- ["shell-restricted"] = true, -- restrict \write18 to a list of commands given in texmf.cnf --- ["synctex"] = true, -- enable synctex --- ["version"] = true, -- display version and exit --- ["luaonly"] = true, -- run a lua file, then exit --- ["luaconly"] = true, -- byte-compile a lua file, then exit --- ["jiton"] = false, --- } - -local report = application.report - -scripts = scripts or { } -scripts.context = scripts.context or { } - --- for the moment here - -if getargument("jit") or getargument("jiton") then - -- bonus shortcut, we assume than --jit also indicates the engine - -- although --jit and --engine=luajittex are independent - setargument("engine","luajittex") -end - -local engine_new = getargument("engine") or directives.value("system.engine") -local engine_old = environment.ownbin - -local function restart(engine_old,engine_new) - local command = format("%s --luaonly %q %s --redirected",engine_new,environment.ownname,environment.reconstructcommandline()) - report(format("redirect %s -> %s: %s",engine_old,engine_new,command)) - local result = os.execute(command) - os.exit(result) -end - -if getargument("redirected") then - setargument("engine",engine_old) -- later on we need this -elseif engine_new == engine_old then - setargument("engine",engine_new) -- later on we need this -elseif environment.validengines[engine_new] and engine_new ~= environment.basicengines[engine_old] then - restart(engine_old,engine_new) -else - setargument("engine",engine_new) -- later on we need this -end - --- so far - --- constants - -local usedfiles = { - nop = "cont-nop.mkiv", - yes = "cont-yes.mkiv", -} - -local usedsuffixes = { - before = { - "tuc" - }, - after = { - "pdf", "tuc", "log" - }, - keep = { - "log" - }, -} - -local formatofinterface = { - en = "cont-en", - uk = "cont-uk", - de = "cont-de", - fr = "cont-fr", - nl = "cont-nl", - cs = "cont-cs", - it = "cont-it", - ro = "cont-ro", - pe = "cont-pe", -} - -local defaultformats = { - "cont-en", - "cont-nl", -} - --- process information - -local ctxrunner = { } -- namespace will go - -local ctx_locations = { '..', '../..' } - -function ctxrunner.new() - return { - ctxname = "", - jobname = "", - flags = { }, - } -end - -function ctxrunner.checkfile(ctxdata,ctxname,defaultname) - - if not ctxdata.jobname or ctxdata.jobname == "" then - return - end - - ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or "" - - if ctxdata.ctxname == "" then - return - end - - ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex') - ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx') - - report("jobname: %s",ctxdata.jobname) - report("ctxname: %s",ctxdata.ctxname) - - -- mtxrun should resolve kpse: and file: - - local usedname = ctxdata.ctxname - local found = lfs.isfile(usedname) - - -- no further test if qualified path - - if not found then - for _, path in next, ctx_locations do - local fullname = file.join(path,ctxdata.ctxname) - if lfs.isfile(fullname) then - usedname = fullname - found = true - break - end - end - end - - if not found then - usedname = resolvers.findfile(ctxdata.ctxname,"tex") - found = usedname ~= "" - end - - if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then - usedname = defaultname - found = true - end - - if not found then - return - end - - local xmldata = xml.load(usedname) - - if not xmldata then - return - else - -- test for valid, can be text file - end - - local ctxpaths = table.append({'.', file.dirname(ctxdata.ctxname)}, ctx_locations) - - xml.include(xmldata,'ctx:include','name', ctxpaths) - - local flags = ctxdata.flags - - for e in xml.collected(xmldata,"/ctx:job/ctx:flags/ctx:flag") do - local flag = xml.text(e) or "" - local key, value = match(flag,"^(.-)=(.+)$") - if key and value then - flags[key] = value - else - flags[flag] = true - end - end - -end - -function ctxrunner.checkflags(ctxdata) - if ctxdata then - for k,v in next, ctxdata.flags do - if getargument(k) == nil then - setargument(k,v) - end - end - end -end - --- multipass control - -local multipass_suffixes = { ".tuc" } -local multipass_nofruns = 8 -- or 7 to test oscillation - -local function multipass_hashfiles(jobname) - local hash = { } - for i=1,#multipass_suffixes do - local suffix = multipass_suffixes[i] - local full = jobname .. suffix - hash[full] = md5.hex(io.loaddata(full) or "unknown") - end - return hash -end - -local function multipass_changed(oldhash, newhash) - for k,v in next, oldhash do - if v ~= newhash[k] then - return true - end - end - return false -end - -local function multipass_copyluafile(jobname) - local tuaname, tucname = jobname..".tua", jobname..".tuc" - if lfs.isfile(tuaname) then - os.remove(tucname) - os.rename(tuaname,tucname) - end -end - --- - -local pattern = lpegpatterns.utfbom^-1 * (P("%% ") + P("% ")) * Cs((1-lpegpatterns.newline)^1) - -local function preamble_analyze(filename) -- only files on current path - local t = { } - local line = io.loadlines(file.addsuffix(filename,"tex")) - if line then - local preamble = lpegmatch(pattern,line) - if preamble then - for key, value in gmatch(preamble,"(%S+)%s*=%s*(%S+)") do - t[key] = value - end - t.type = "tex" - elseif find(line,"^ 0 then - -- the list of given files is processed using the stub file - mainfile = usedfiles.yes - filelist = files - files = { } - else - return - end - -- - local interface = validstring(getargument("interface")) or "en" - local formatname = formatofinterface[interface] or "cont-en" - local formatfile, scriptfile = resolvers.locateformat(formatname) -- regular engine ! - if not formatfile or not scriptfile then - report("warning: no format found, forcing remake (commandline driven)") - scripts.context.make(formatname) - formatfile, scriptfile = resolvers.locateformat(formatname) -- variant - end - if formatfile and scriptfile then - -- okay - elseif formatname then - report("error, no format found with name: %s, aborting",formatname) - return - else - report("error, no format found (provide formatname or interface)") - return - end - -- - local a_mkii = getargument("mkii") or getargument("pdftex") or getargument("xetex") - local a_purge = getargument("purge") - local a_purgeall = getargument("purgeall") - local a_purgeresult = getargument("purgeresult") - local a_global = getargument("global") - local a_timing = getargument("timing") - local a_profile = getargument("profile") - local a_batchmode = getargument("batchmode") - local a_nonstopmode = getargument("nonstopmode") - local a_once = getargument("once") - local a_synctex = getargument("synctex") - local a_backend = getargument("backend") - local a_arrange = getargument("arrange") - local a_noarrange = getargument("noarrange") - local a_jiton = getargument("jiton") - local a_texformat = getargument("texformat") - -- - a_batchmode = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil - a_synctex = tonumber(a_synctex) or (toboolean(a_synctex,true) and 1) or (a_synctex == "zipped" and 1) or (a_synctex == "unzipped" and -1) or nil - -- - for i=1,#filelist do - -- - local filename = filelist[i] - local basename = file.basename(filename) -- use splitter - local pathname = file.dirname(filename) - -- - if pathname == "" and not a_global and filename ~= usedfiles.nop then - filename = "./" .. filename - if not lfs.isfile(filename) then - report("warning: no (local) file %a, proceeding",filename) - end - end - -- - local jobname = file.removesuffix(basename) - -- local jobname = file.removesuffix(filename) - local ctxname = ctxdata and ctxdata.ctxname - -- - local analysis = preamble_analyze(filename) - -- - if a_mkii or analysis.engine == 'pdftex' or analysis.engine == 'xetex' then - run_texexec(filename,a_purge,a_purgeall) - elseif plain_format(a_texformat or analysis.texformat) then - run_plain(a_texformat or analysis.texformat,filename) - else - if analysis.interface and analysis.interface ~= interface then - formatname = formatofinterface[analysis.interface] or formatname - formatfile, scriptfile = resolvers.locateformat(formatname) - end - -- - a_jiton = (a_jiton or toboolean(analysis.jiton,true)) and true or nil - -- - if not formatfile or not scriptfile then - report("warning: no format found, forcing remake (source driven)") - scripts.context.make(formatname,a_engine) - formatfile, scriptfile = resolvers.locateformat(formatname) - end - if formatfile and scriptfile then - local suffix = validstring(getargument("suffix")) - local resultname = validstring(getargument("result")) - if suffix then - resultname = file.removesuffix(jobname) .. suffix - end - local oldbase = "" - local newbase = "" - if resultname then - oldbase = file.removesuffix(jobname) - newbase = file.removesuffix(resultname) - if oldbase ~= newbase then - if a_purgeresult then - result_push_purge(oldbase,newbase) - else - result_push_keep(oldbase,newbase) - end - else - resultname = nil - end - end - -- - local pdfview = getargument("autopdf") or getargument("closepdf") - if pdfview then - pdf_close(filename,pdfview) - if resultname then - pdf_close(resultname,pdfview) - end - end - -- - -- we could do this when locating the format and exit from luatex when - -- there is a version mismatch .. that way we can use stock luatex - -- plus mtxrun to run luajittex instead .. this saves a restart but is - -- also cleaner as then mtxrun only has to check for a special return - -- code (signaling a make + rerun) .. maybe some day - -- - local okay = statistics.checkfmtstatus(formatfile,a_engine) - if okay ~= true then - report("warning: %s, forcing remake",tostring(okay)) - scripts.context.make(formatname) - end - -- - local oldhash = multipass_hashfiles(jobname) - local newhash = { } - local maxnofruns = once and 1 or multipass_nofruns - -- - local c_flags = { - directives = validstring(environment.directives), -- gets passed via mtxrun - trackers = validstring(environment.trackers), -- gets passed via mtxrun - experiments = validstring(environment.experiments), -- gets passed via mtxrun - -- - result = validstring(resultname), - input = validstring(getargument("input") or filename), -- alternative input - fulljobname = validstring(filename), - files = concat(files,","), - ctx = validstring(ctxname), - } - -- - for k, v in next, environment.arguments do - -- the raw arguments - if c_flags[k] == nil then - c_flags[k] = v - end - end - -- - -- - local l_flags = { - ["interaction"] = a_batchmode, - ["synctex"] = a_synctex, - ["no-parse-first-line"] = true, - -- ["no-mktex"] = true, - -- ["file-line-error-style"] = true, - ["fmt"] = formatfile, - ["lua"] = scriptfile, - ["jobname"] = jobname, - ["jiton"] = a_jiton, - } - -- - if a_synctex then - report("warning: synctex is enabled") -- can add upto 5% runtime - end - -- - if not a_timing then - -- okay - elseif c_flags.usemodule then - c_flags.usemodule = format("timing,%s",c_flags.usemodule) - else - c_flags.usemodule = "timing" - end - -- - if not a_profile then - -- okay - elseif c_flags.directives then - c_flags.directives = format("system.profile,%s",c_flags.directives) - else - c_flags.directives = "system.profile" - end - -- - -- kindofrun: 1:first run, 2:successive run, 3:once, 4:last of maxruns - -- - for currentrun=1,maxnofruns do - -- - c_flags.final = false - c_flags.kindofrun = (a_once and 3) or (currentrun==1 and 1) or (currentrun==maxnofruns and 4) or 2 - c_flags.maxnofruns = maxnofruns - c_flags.currentrun = currentrun - c_flags.noarrange = a_noarrange or a_arrange or nil - -- - local command = luatex_command(l_flags,c_flags,mainfile,a_engine) - -- - report("run %s: %s",i,command) - print("") -- cleaner, else continuation on same line - local returncode, errorstring = os.spawn(command) - if not returncode then - report("fatal error: no return code, message: %s",errorstring or "?") - if resultname then - result_save_error(oldbase,newbase) - end - os.exit(1) - break - elseif returncode == 0 then - multipass_copyluafile(jobname) - newhash = multipass_hashfiles(jobname) - if multipass_changed(oldhash,newhash) then - oldhash = newhash - else - break - end - else - report("fatal error: return code: %s",returncode or "?") - if resultname then - result_save_error(oldbase,newbase) - end - os.exit(1) -- (returncode) - break - end - -- - end - -- - if a_arrange then - -- - c_flags.final = true - c_flags.kindofrun = 3 - c_flags.currentrun = c_flags.currentrun + 1 - c_flags.noarrange = nil - -- - local command = luatex_command(l_flags,c_flags,mainfile,a_engine) - -- - report("arrange run: %s",command) - local returncode, errorstring = os.spawn(command) - if not returncode then - report("fatal error: no return code, message: %s",errorstring or "?") - os.exit(1) - elseif returncode > 0 then - report("fatal error: return code: %s",returncode or "?") - os.exit(returncode) - end - -- - end - -- - if a_purge then - scripts.context.purge_job(jobname) - elseif a_purgeall then - scripts.context.purge_job(jobname,true) - end - -- - if resultname then - if a_purgeresult then - -- so, if there is no result then we don't get the old one, but - -- related files (log etc) are still there for tracing purposes - result_save_purge(oldbase,newbase) - else - result_save_keep(oldbase,newbase) - end - report("result renamed to: %s",newbase) - end - -- - if purge then - scripts.context.purge_job(resultname) - elseif purgeall then - scripts.context.purge_job(resultname,true) - end - -- - local pdfview = getargument("autopdf") - if pdfview then - pdf_open(resultname or jobname,pdfview) - end - -- - if a_timing then - report() - report("you can process (timing) statistics with:",jobname) - report() - report("context --extra=timing '%s'",jobname) - report("mtxrun --script timing --xhtml [--launch --remove] '%s'",jobname) - report() - end - else - if formatname then - report("error, no format found with name: %s, skipping",formatname) - else - report("error, no format found (provide formatname or interface)") - end - break - end - end - end - -- -end - -function scripts.context.pipe() -- still used? - -- context --pipe - -- context --pipe --purge --dummyfile=whatever.tmp - local interface = getargument("interface") - interface = (type(interface) == "string" and interface) or "en" - local formatname = formatofinterface[interface] or "cont-en" - local formatfile, scriptfile = resolvers.locateformat(formatname) - if not formatfile or not scriptfile then - report("warning: no format found, forcing remake (commandline driven)") - scripts.context.make(formatname) - formatfile, scriptfile = resolvers.locateformat(formatname) - end - if formatfile and scriptfile then - local okay = statistics.checkfmtstatus(formatfile) - if okay ~= true then - report("warning: %s, forcing remake",tostring(okay)) - scripts.context.make(formatname) - end - local l_flags = { - interaction = "scrollmode", - fmt = formatfile, - lua = scriptfile, - } - local c_flags = { - backend = "pdf", - final = false, - kindofrun = 3, - currentrun = 1, - } - local filename = getargument("dummyfile") or "" - if filename == "" then - filename = "\\relax" - report("entering scrollmode, end job with \\end") - else - filename = file.addsuffix(filename,"tmp") - io.savedata(filename,"\\relax") - report("entering scrollmode using '%s' with optionfile, end job with \\end",filename) - end - local command = luatex_command(l_flags,c_flags,filename) - os.spawn(command) - if getargument("purge") then - scripts.context.purge_job(filename) - elseif getargument("purgeall") then - scripts.context.purge_job(filename,true) - os.remove(filename) - end - else - if formatname then - report("error, no format found with name: %s, aborting",formatname) - else - report("error, no format found (provide formatname or interface)") - end - end -end - -local function make_mkiv_format(name,engine) - environment.make_format(name) -- jit is picked up later -end - -local function make_mkii_format(name,engine) - local command = format("mtxrun texexec.rb --make --%s %s",name,engine) - report("running command: %s",command) - os.spawn(command) -end - -function scripts.context.generate() - resolvers.instance.renewcache = true - trackers.enable("resolvers.locating") - resolvers.load() -end - -function scripts.context.make(name) - if not getargument("fast") then -- as in texexec - scripts.context.generate() - end - local list = (name and { name }) or (environment.files[1] and environment.files) or defaultformats - local engine = getargument("engine") or "luatex" - if getargument("jit") or getargument("jiton") then - engine = "luajittex" - end - for i=1,#list do - local name = list[i] - name = formatofinterface[name] or name or "" - if name == "" then - -- nothing - elseif engine == "luatex" or engine == "luajittex" then - make_mkiv_format(name,engine) - elseif engine == "pdftex" or engine == "xetex" then - make_mkii_format(name,engine) - end - end -end - -function scripts.context.ctx() - local ctxdata = ctxrunner.new() - ctxdata.jobname = environment.files[1] - ctxrunner.checkfile(ctxdata,getargument("ctx")) - ctxrunner.checkflags(ctxdata) - scripts.context.run(ctxdata) -end - -function scripts.context.autoctx() - local ctxdata = nil - local files = environment.files - local firstfile = #files > 0 and files[1] - if firstfile then - local suffix = file.suffix(firstfile) - if suffix == "xml" then - local chunk = io.loadchunk(firstfile) -- 1024 - if chunk then - local ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") - if ctxname then - ctxdata = ctxrunner.new() - ctxdata.jobname = firstfile - ctxrunner.checkfile(ctxdata,ctxname) - ctxrunner.checkflags(ctxdata) - end - end - elseif suffix == "tex" then - -- maybe but we scan the preamble later too - end - end - scripts.context.run(ctxdata) -end - --- no longer ok as mlib-run misses something: - --- local template = [[ --- \starttext --- \directMPgraphic{%s}{input "%s"} --- \stoptext --- ]] --- --- local loaded = false --- --- function scripts.context.metapost() --- local filename = environment.files[1] or "" --- if not loaded then --- dofile(resolvers.findfile("mlib-run.lua")) --- loaded = true --- commands = commands or { } --- commands.writestatus = report -- no longer needed --- end --- local formatname = getargument("format") or "metafun" --- if formatname == "" or type(formatname) == "boolean" then --- formatname = "metafun" --- end --- if getargument("pdf") then --- local basename = file.removesuffix(filename) --- local resultname = getargument("result") or basename --- local jobname = "mtx-context-metapost" --- local tempname = file.addsuffix(jobname,"tex") --- io.savedata(tempname,format(template,"metafun",filename)) --- environment.files[1] = tempname --- setargument("result",resultname) --- setargument("once",true) --- scripts.context.run() --- scripts.context.purge_job(jobname,true) --- scripts.context.purge_job(resultname,true) --- elseif getargument("svg") then --- metapost.directrun(formatname,filename,"svg") --- else --- metapost.directrun(formatname,filename,"mps") --- end --- end - --- -- - -function scripts.context.version() - local name = resolvers.findfile("context.mkiv") - if name ~= "" then - report("main context file: %s",name) - local data = io.loaddata(name) - if data then - local version = match(data,"\\edef\\contextversion{(.-)}") - if version then - report("current version: %s",version) - else - report("context version: unknown, no timestamp found") - end - else - report("context version: unknown, load error") - end - else - report("main context file: unknown, 'context.mkiv' not found") - end -end - --- purging files - -local generic_files = { - "texexec.tex", "texexec.tui", "texexec.tuo", - "texexec.tuc", "texexec.tua", - "texexec.ps", "texexec.pdf", "texexec.dvi", - "cont-opt.tex", "cont-opt.bak" -} - -local obsolete_results = { - "dvi", -} - -local temporary_runfiles = { - "tui", "tua", "tup", "ted", "tes", "top", - "log", "tmp", "run", "bck", "rlg", - "mpt", "mpx", "mpd", "mpo", "mpb", "ctl", - "synctex", "synctex.gz", "pgf", - "prep", -} - -local persistent_runfiles = { - "tuo", "tub", "top", "tuc" -} - -local special_runfiles = { - "-mpgraph", "-mprun", "-temp-" -} - -local function purge_file(dfile,cfile) - if cfile and lfs.isfile(cfile) then - if os.remove(dfile) then - return file.basename(dfile) - end - elseif dfile then - if os.remove(dfile) then - return file.basename(dfile) - end - end -end - -function scripts.context.purge_job(jobname,all,mkiitoo) - if jobname and jobname ~= "" then - jobname = file.basename(jobname) - local filebase = file.removesuffix(jobname) - if mkiitoo then - scripts.context.purge(all,filebase,true) -- leading "./" - else - local deleted = { } - for i=1,#obsolete_results do - deleted[#deleted+1] = purge_file(filebase.."."..obsolete_results[i],filebase..".pdf") - end - for i=1,#temporary_runfiles do - deleted[#deleted+1] = purge_file(filebase.."."..temporary_runfiles[i]) - end - if all then - for i=1,#persistent_runfiles do - deleted[#deleted+1] = purge_file(filebase.."."..persistent_runfiles[i]) - end - end - if #deleted > 0 then - report("purged files: %s", concat(deleted,", ")) - end - end - end -end - -function scripts.context.purge(all,pattern,mkiitoo) - local all = all or getargument("all") - local pattern = getargument("pattern") or (pattern and (pattern.."*")) or "*.*" - local files = dir.glob(pattern) - local obsolete = table.tohash(obsolete_results) - local temporary = table.tohash(temporary_runfiles) - local persistent = table.tohash(persistent_runfiles) - local generic = table.tohash(generic_files) - local deleted = { } - for i=1,#files do - local name = files[i] - local suffix = file.suffix(name) - local basename = file.basename(name) - if obsolete[suffix] or temporary[suffix] or persistent[suffix] or generic[basename] then - deleted[#deleted+1] = purge_file(name) - elseif mkiitoo then - for i=1,#special_runfiles do - if find(name,special_runfiles[i]) then - deleted[#deleted+1] = purge_file(name) - end - end - end - end - if #deleted > 0 then - report("purged files: %s", concat(deleted,", ")) - end -end - --- touching files (signals regeneration of formats) - -local function touch(path,name,versionpattern,kind,kindpattern) - if path and path ~= "" then - name = file.join(path,name) -print(name) - else - name = resolvers.findfile(name) - end - local olddata = io.loaddata(name) - if olddata then - local oldkind, newkind = "", kind or "" - local oldversion, newversion = "", os.date("%Y.%m.%d %H:%M") - local newdata - if versionpattern then - newdata = gsub(olddata,versionpattern,function(pre,mid,post) - oldversion = mid - return pre .. newversion .. post - end) or olddata - end - if kind and kindpattern then - newdata = gsub(newdata,kindpattern,function(pre,mid,post) - oldkind = mid - return pre .. newkind .. post - end) or newdata - end - if newdata ~= "" and (oldversion ~= newversion or oldkind ~= newkind or newdata ~= olddata) then - local backup = file.replacesuffix(name,"tmp") - os.remove(backup) - os.rename(name,backup) - io.savedata(name,newdata) - return name, oldversion, newversion, oldkind, newkind - end - end -end - -local p_contextkind = "(\\edef\\contextkind%s*{)(.-)(})" -local p_contextversion = "(\\edef\\contextversion%s*{)(.-)(})" -local p_newcontextversion = "(\\newcontextversion%s*{)(.-)(})" - -local function touchfiles(suffix,kind,path) - local foundname, oldversion, newversion, oldkind, newkind = touch(path,file.addsuffix("context",suffix),p_contextversion,kind,p_contextkind) - if foundname then - report("old version : %s (%s)",oldversion,oldkind) - report("new version : %s (%s)",newversion,newkind) - report("touched file : %s",foundname) - local foundname = touch(path,file.addsuffix("cont-new",suffix),p_newcontextversion) - if foundname then - report("touched file : %s", foundname) - end - else - report("nothing touched") - end -end - -function scripts.context.touch() - if getargument("expert") then - local touch = getargument("touch") - local kind = getargument("kind") - local path = getargument("basepath") - if touch == "mkii" or touch == "mkiv" or touch == "mkvi" then -- mkix mkxi - touchfiles(touch,kind,path) - else - touchfiles("mkii",kind,path) - touchfiles("mkiv",kind,path) - touchfiles("mkvi",kind,path) - end - else - report("touching needs --expert") - end -end - --- modules - -local labels = { "title", "comment", "status" } -local cards = { "*.mkvi", "*.mkiv", "*.mkxi", "*.mkix", "*.tex" } - -function scripts.context.modules(pattern) - local list = { } - local found = resolvers.findfile("context.mkiv") - if not pattern or pattern == "" then - -- official files in the tree - for i=1,#cards do - resolvers.findwildcardfiles(cards[i],list) - end - -- my dev path - for i=1,#cards do - dir.glob(file.join(file.dirname(found),cards[i]),list) - end - else - resolvers.findwildcardfiles(pattern,list) - dir.glob(file.join(file.dirname(found,pattern)),list) - end - local done = { } -- todo : sort - for i=1,#list do - local v = list[i] - local base = file.basename(v) - if not done[base] then - done[base] = true - local suffix = file.suffix(base) - if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" or suffix == "mkix" or suffix == "mkxi" then - local prefix = match(base,"^([xmst])%-") - if prefix then - v = resolvers.findfile(base) -- so that files on my dev path are seen - local data = io.loaddata(v) or "" - data = match(data,"%% begin info(.-)%% end info") - if data then - local info = { } - for label, text in gmatch(data,"%% +([^ ]+) *: *(.-)[\n\r]") do - info[label] = text - end - report() - report("%-7s : %s","module",base) - report() - for i=1,#labels do - local l = labels[i] - if info[l] then - report("%-7s : %s",l,info[l]) - end - end - report() - end - end - end - end - end -end - --- extras - -function scripts.context.extras(pattern) - -- only in base path, i.e. only official ones - if type(pattern) ~= "string" then - pattern = "*" - end - local found = resolvers.findfile("context.mkiv") - if found ~= "" then - pattern = file.join(dir.expandname(file.dirname(found)),format("mtx-context-%s.tex",pattern or "*")) - local list = dir.glob(pattern) - for i=1,#list do - local v = list[i] - local data = io.loaddata(v) or "" - data = match(data,"%% begin help(.-)%% end help") - if data then - report() - report("extra: %s (%s)",(gsub(v,"^.*mtx%-context%-(.-)%.tex$","%1")),v) - for s in gmatch(data,"%% *(.-)[\n\r]") do - report(s) - end - report() - end - end - end -end - -function scripts.context.extra() - local extra = getargument("extra") - if type(extra) ~= "string" then - scripts.context.extras() - elseif getargument("help") then - scripts.context.extras(extra) - else - local fullextra = extra - if not find(fullextra,"mtx%-context%-") then - fullextra = "mtx-context-" .. extra - end - local foundextra = resolvers.findfile(fullextra) - if foundextra == "" then - scripts.context.extras() - return - else - report("processing extra: %s", foundextra) - end - setargument("purgeall",true) - local result = getargument("result") or "" - if result == "" then - setargument("result","context-extra") - end - scripts.context.run(nil,foundextra) - end -end - --- todo: we need to do a dummy run - -function scripts.context.trackers() - environment.files = { resolvers.findfile("m-trackers.mkiv") } - multipass_nofruns = 1 - setargument("purgeall",true) - scripts.context.run() -end - -function scripts.context.directives() - environment.files = { resolvers.findfile("m-directives.mkiv") } - multipass_nofruns = 1 - setargument("purgeall",true) - scripts.context.run() -end - -function scripts.context.logcategories() - environment.files = { resolvers.findfile("m-logcategories.mkiv") } - multipass_nofruns = 1 - setargument("purgeall",true) - scripts.context.run() -end - --- updating (often one will use mtx-update instead) - -function scripts.context.timed(action) - statistics.timed(action) -end - -local zipname = "cont-tmf.zip" -local mainzip = "http://www.pragma-ade.com/context/latest/" .. zipname -local validtrees = { "texmf-local", "texmf-context" } -local selfscripts = { "mtxrun.lua" } -- was: { "luatools.lua", "mtxrun.lua" } - -function zip.loaddata(zipfile,filename) -- should be in zip lib - local f = zipfile:open(filename) - if f then - local data = f:read("*a") - f:close() - return data - end - return nil -end - -function scripts.context.update() - local force = getargument("force") - local socket = require("socket") - local http = require("socket.http") - local basepath = resolvers.findfile("context.mkiv") or "" - if basepath == "" then - report("quiting, no 'context.mkiv' found") - return - end - local basetree = basepath.match(basepath,"^(.-)tex/context/base/context.mkiv$") or "" - if basetree == "" then - report("quiting, no proper tds structure (%s)",basepath) - return - end - local function is_okay(basetree) - for _, tree in next, validtrees do - local pattern = gsub(tree,"%-","%%-") - if find(basetree,pattern) then - return tree - end - end - return false - end - local okay = is_okay(basetree) - if not okay then - report("quiting, tree '%s' is protected",okay) - return - else - report("updating tree '%s'",okay) - end - if not lfs.chdir(basetree) then - report("quiting, unable to change to '%s'",okay) - return - end - report("fetching '%s'",mainzip) - local latest = http.request(mainzip) - if not latest then - report("context tree '%s' can be updated, use --force",okay) - return - end - io.savedata("cont-tmf.zip",latest) - if false then - -- variant 1 - os.execute("mtxrun --script unzip cont-tmf.zip") - else - -- variant 2 - local zipfile = zip.open(zipname) - if not zipfile then - report("quiting, unable to open '%s'",zipname) - return - end - local newfile = zip.loaddata(zipfile,"tex/context/base/context.mkiv") - if not newfile then - report("quiting, unable to open '%s'","context.mkiv") - return - end - local oldfile = io.loaddata(resolvers.findfile("context.mkiv")) or "" - local function versiontonumber(what,str) - local version = match(str,"\\edef\\contextversion{(.-)}") or "" - local year, month, day, hour, minute = match(str,"\\edef\\contextversion{(%d+)%.(%d+)%.(%d+) *(%d+)%:(%d+)}") - if year and minute then - local time = os.time { year=year,month=month,day=day,hour=hour,minute=minute} - report("%s version: %s (%s)",what,version,time) - return time - else - report("%s version: %s (unknown)",what,version) - return nil - end - end - local oldversion = versiontonumber("old",oldfile) - local newversion = versiontonumber("new",newfile) - if not oldversion or not newversion then - report("quiting, version cannot be determined") - return - elseif oldversion == newversion then - report("quiting, your current version is up-to-date") - return - elseif oldversion > newversion then - report("quiting, your current version is newer") - return - end - for k in zipfile:files() do - local filename = k.filename - if find(filename,"/$") then - lfs.mkdir(filename) - else - local data = zip.loaddata(zipfile,filename) - if data then - if force then - io.savedata(filename,data) - end - report(filename) - end - end - end - for _, scriptname in next, selfscripts do - local oldscript = resolvers.findfile(scriptname) or "" - if oldscript ~= "" and is_okay(oldscript) then - local newscript = "./scripts/context/lua/" .. scriptname - local data = io.loaddata(newscript) or "" - if data ~= "" then - report("replacing script '%s' by '%s'",oldscript,newscript) - if force then - io.savedata(oldscript,data) - end - end - else - report("keeping script '%s'",oldscript) - end - end - if force then - scripts.context.make() - end - end - if force then - report("context tree '%s' has been updated",okay) - else - report("context tree '%s' can been updated (use --force)",okay) - end -end - --- getting it done - -if getargument("nostats") then - setargument("nostatistics",true) - setargument("nostat",nil) -end - -if getargument("batch") then - setargument("batchmode",true) - setargument("batch",nil) -end - -if getargument("nonstop") then - setargument("nonstopmode",true) - setargument("nonstop",nil) -end - -do - - local silent = getargument("silent") - if type(silent) == "string" then - directives.enable(format("logs.blocked={%s}",silent)) - elseif silent then - directives.enable("logs.blocked") - end - -end - -if getargument("once") then - multipass_nofruns = 1 -elseif getargument("runs") then - multipass_nofruns = tonumber(getargument("runs")) or nil -end - -if getargument("run") then - scripts.context.timed(scripts.context.autoctx) -elseif getargument("make") then - scripts.context.timed(function() scripts.context.make() end) -elseif getargument("generate") then - scripts.context.timed(function() scripts.context.generate() end) -elseif getargument("ctx") then - scripts.context.timed(scripts.context.ctx) --- elseif getargument("mp") or getargument("metapost") then --- scripts.context.timed(scripts.context.metapost) -elseif getargument("version") then - application.identify() - scripts.context.version() -elseif getargument("touch") then - scripts.context.touch() -elseif getargument("update") then - scripts.context.update() -elseif getargument("expert") then - application.help("expert", "special") -elseif getargument("modules") then - scripts.context.modules() -elseif getargument("extras") then - scripts.context.extras(environment.files[1] or getargument("extras")) -elseif getargument("extra") then - scripts.context.extra() -elseif getargument("exporthelp") then - -- application.export(getargument("exporthelp"),environment.files[1]) - application.export() -elseif getargument("help") then - if environment.files[1] == "extras" then - scripts.context.extras() - else - application.help("basic") - end -elseif getargument("showtrackers") or getargument("trackers") == true then - scripts.context.trackers() -elseif getargument("showdirectives") or getargument("directives") == true then - scripts.context.directives() -elseif getargument("showlogcategories") then - scripts.context.logcategories() -elseif environment.files[1] or getargument("nofile") then - scripts.context.timed(scripts.context.autoctx) -elseif getargument("pipe") then - scripts.context.timed(scripts.context.pipe) -elseif getargument("purge") then - -- only when no filename given, supports --pattern - scripts.context.purge() -elseif getargument("purgeall") then - -- only when no filename given, supports --pattern - scripts.context.purge(true,nil,true) -else - application.help("basic") -end +if not modules then modules = { } end modules ['mtx-context'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: more local functions +-- todo: pass jobticket/ctxdata table around + +local type, next, tostring, tonumber = type, next, tostring, tonumber +local format, gmatch, match, gsub, find = string.format, string.gmatch, string.match, string.gsub, string.find +local quote, validstring = string.quote, string.valid +local concat = table.concat +local settings_to_array = utilities.parsers.settings_to_array +local appendtable = table.append +local lpegpatterns, lpegmatch, Cs, P = lpeg.patterns, lpeg.match, lpeg.Cs, lpeg.P + +local getargument = environment.getargument or environment.argument +local setargument = environment.setargument + +local application = logs.application { + name = "mtx-context", + banner = "ConTeXt Process Management 0.60", + -- helpinfo = helpinfo, -- table with { category_a = text_1, category_b = text_2 } or helpstring or xml_blob + helpinfo = "mtx-context.xml", +} + +-- local luatexflags = { +-- ["8bit"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["default-translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["etex"] = true, -- ignored, the etex extensions are always active +-- +-- ["credits"] = true, -- display credits and exit +-- ["debug-format"] = true, -- enable format debugging +-- ["disable-write18"] = true, -- disable \write18{SHELL COMMAND} +-- ["draftmode"] = true, -- switch on draft mode (generates no output PDF) +-- ["enable-write18"] = true, -- enable \write18{SHELL COMMAND} +-- ["file-line-error"] = true, -- enable file:line:error style messages +-- ["file-line-error-style"] = true, -- aliases of --file-line-error +-- ["no-file-line-error"] = true, -- disable file:line:error style messages +-- ["no-file-line-error-style"] = true, -- aliases of --no-file-line-error +-- ["fmt"] = true, -- load the format file FORMAT +-- ["halt-on-error"] = true, -- stop processing at the first error +-- ["help"] = true, -- display help and exit +-- ["ini"] = true, -- be iniluatex, for dumping formats +-- ["interaction"] = true, -- set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode) +-- ["jobname"] = true, -- set the job name to STRING +-- ["kpathsea-debug"] = true, -- set path searching debugging flags according to the bits of NUMBER +-- ["lua"] = true, -- load and execute a lua initialization script +-- ["mktex"] = true, -- enable mktexFMT generation (FMT=tex/tfm) +-- ["no-mktex"] = true, -- disable mktexFMT generation (FMT=tex/tfm) +-- ["nosocket"] = true, -- disable the lua socket library +-- ["output-comment"] = true, -- use STRING for DVI file comment instead of date (no effect for PDF) +-- ["output-directory"] = true, -- use existing DIR as the directory to write files in +-- ["output-format"] = true, -- use FORMAT for job output; FORMAT is 'dvi' or 'pdf' +-- ["parse-first-line"] = true, -- enable parsing of the first line of the input file +-- ["no-parse-first-line"] = true, -- disable parsing of the first line of the input file +-- ["progname"] = true, -- set the program name to STRING +-- ["recorder"] = true, -- enable filename recorder +-- ["safer"] = true, -- disable easily exploitable lua commands +-- ["shell-escape"] = true, -- enable \write18{SHELL COMMAND} +-- ["no-shell-escape"] = true, -- disable \write18{SHELL COMMAND} +-- ["shell-restricted"] = true, -- restrict \write18 to a list of commands given in texmf.cnf +-- ["synctex"] = true, -- enable synctex +-- ["version"] = true, -- display version and exit +-- ["luaonly"] = true, -- run a lua file, then exit +-- ["luaconly"] = true, -- byte-compile a lua file, then exit +-- ["jiton"] = false, +-- } + +local report = application.report + +scripts = scripts or { } +scripts.context = scripts.context or { } + +-- for the moment here + +if getargument("jit") or getargument("jiton") then + -- bonus shortcut, we assume than --jit also indicates the engine + -- although --jit and --engine=luajittex are independent + setargument("engine","luajittex") +end + +local engine_new = getargument("engine") or directives.value("system.engine") +local engine_old = environment.ownbin + +local function restart(engine_old,engine_new) + local command = format("%s --luaonly %q %s --redirected",engine_new,environment.ownname,environment.reconstructcommandline()) + report(format("redirect %s -> %s: %s",engine_old,engine_new,command)) + local result = os.execute(command) + os.exit(result) +end + +if getargument("redirected") then + setargument("engine",engine_old) -- later on we need this +elseif engine_new == engine_old then + setargument("engine",engine_new) -- later on we need this +elseif environment.validengines[engine_new] and engine_new ~= environment.basicengines[engine_old] then + restart(engine_old,engine_new) +else + setargument("engine",engine_new) -- later on we need this +end + +-- so far + +-- constants + +local usedfiles = { + nop = "cont-nop.mkiv", + yes = "cont-yes.mkiv", +} + +local usedsuffixes = { + before = { + "tuc" + }, + after = { + "pdf", "tuc", "log" + }, + keep = { + "log" + }, +} + +local formatofinterface = { + en = "cont-en", + uk = "cont-uk", + de = "cont-de", + fr = "cont-fr", + nl = "cont-nl", + cs = "cont-cs", + it = "cont-it", + ro = "cont-ro", + pe = "cont-pe", +} + +local defaultformats = { + "cont-en", + "cont-nl", +} + +-- process information + +local ctxrunner = { } -- namespace will go + +local ctx_locations = { '..', '../..' } + +function ctxrunner.new() + return { + ctxname = "", + jobname = "", + flags = { }, + } +end + +function ctxrunner.checkfile(ctxdata,ctxname,defaultname) + + if not ctxdata.jobname or ctxdata.jobname == "" then + return + end + + ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or "" + + if ctxdata.ctxname == "" then + return + end + + ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex') + ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx') + + report("jobname: %s",ctxdata.jobname) + report("ctxname: %s",ctxdata.ctxname) + + -- mtxrun should resolve kpse: and file: + + local usedname = ctxdata.ctxname + local found = lfs.isfile(usedname) + + -- no further test if qualified path + + if not found then + for _, path in next, ctx_locations do + local fullname = file.join(path,ctxdata.ctxname) + if lfs.isfile(fullname) then + usedname = fullname + found = true + break + end + end + end + + if not found then + usedname = resolvers.findfile(ctxdata.ctxname,"tex") + found = usedname ~= "" + end + + if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then + usedname = defaultname + found = true + end + + if not found then + return + end + + local xmldata = xml.load(usedname) + + if not xmldata then + return + else + -- test for valid, can be text file + end + + local ctxpaths = table.append({'.', file.dirname(ctxdata.ctxname)}, ctx_locations) + + xml.include(xmldata,'ctx:include','name', ctxpaths) + + local flags = ctxdata.flags + + for e in xml.collected(xmldata,"/ctx:job/ctx:flags/ctx:flag") do + local flag = xml.text(e) or "" + local key, value = match(flag,"^(.-)=(.+)$") + if key and value then + flags[key] = value + else + flags[flag] = true + end + end + +end + +function ctxrunner.checkflags(ctxdata) + if ctxdata then + for k,v in next, ctxdata.flags do + if getargument(k) == nil then + setargument(k,v) + end + end + end +end + +-- multipass control + +local multipass_suffixes = { ".tuc" } +local multipass_nofruns = 8 -- or 7 to test oscillation + +local function multipass_hashfiles(jobname) + local hash = { } + for i=1,#multipass_suffixes do + local suffix = multipass_suffixes[i] + local full = jobname .. suffix + hash[full] = md5.hex(io.loaddata(full) or "unknown") + end + return hash +end + +local function multipass_changed(oldhash, newhash) + for k,v in next, oldhash do + if v ~= newhash[k] then + return true + end + end + return false +end + +local function multipass_copyluafile(jobname) + local tuaname, tucname = jobname..".tua", jobname..".tuc" + if lfs.isfile(tuaname) then + os.remove(tucname) + os.rename(tuaname,tucname) + end +end + +-- + +local pattern = lpegpatterns.utfbom^-1 * (P("%% ") + P("% ")) * Cs((1-lpegpatterns.newline)^1) + +local function preamble_analyze(filename) -- only files on current path + local t = { } + local line = io.loadlines(file.addsuffix(filename,"tex")) + if line then + local preamble = lpegmatch(pattern,line) + if preamble then + for key, value in gmatch(preamble,"(%S+)%s*=%s*(%S+)") do + t[key] = value + end + t.type = "tex" + elseif find(line,"^ 0 then + -- the list of given files is processed using the stub file + mainfile = usedfiles.yes + filelist = files + files = { } + else + return + end + -- + local interface = validstring(getargument("interface")) or "en" + local formatname = formatofinterface[interface] or "cont-en" + local formatfile, scriptfile = resolvers.locateformat(formatname) -- regular engine ! + if not formatfile or not scriptfile then + report("warning: no format found, forcing remake (commandline driven)") + scripts.context.make(formatname) + formatfile, scriptfile = resolvers.locateformat(formatname) -- variant + end + if formatfile and scriptfile then + -- okay + elseif formatname then + report("error, no format found with name: %s, aborting",formatname) + return + else + report("error, no format found (provide formatname or interface)") + return + end + -- + local a_mkii = getargument("mkii") or getargument("pdftex") or getargument("xetex") + local a_purge = getargument("purge") + local a_purgeall = getargument("purgeall") + local a_purgeresult = getargument("purgeresult") + local a_global = getargument("global") + local a_timing = getargument("timing") + local a_profile = getargument("profile") + local a_batchmode = getargument("batchmode") + local a_nonstopmode = getargument("nonstopmode") + local a_once = getargument("once") + local a_synctex = getargument("synctex") + local a_backend = getargument("backend") + local a_arrange = getargument("arrange") + local a_noarrange = getargument("noarrange") + local a_jiton = getargument("jiton") + local a_texformat = getargument("texformat") + -- + a_batchmode = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil + a_synctex = tonumber(a_synctex) or (toboolean(a_synctex,true) and 1) or (a_synctex == "zipped" and 1) or (a_synctex == "unzipped" and -1) or nil + -- + for i=1,#filelist do + -- + local filename = filelist[i] + local basename = file.basename(filename) -- use splitter + local pathname = file.dirname(filename) + -- + if pathname == "" and not a_global and filename ~= usedfiles.nop then + filename = "./" .. filename + if not lfs.isfile(filename) then + report("warning: no (local) file %a, proceeding",filename) + end + end + -- + local jobname = file.removesuffix(basename) + -- local jobname = file.removesuffix(filename) + local ctxname = ctxdata and ctxdata.ctxname + -- + local analysis = preamble_analyze(filename) + -- + if a_mkii or analysis.engine == 'pdftex' or analysis.engine == 'xetex' then + run_texexec(filename,a_purge,a_purgeall) + elseif plain_format(a_texformat or analysis.texformat) then + run_plain(a_texformat or analysis.texformat,filename) + else + if analysis.interface and analysis.interface ~= interface then + formatname = formatofinterface[analysis.interface] or formatname + formatfile, scriptfile = resolvers.locateformat(formatname) + end + -- + a_jiton = (a_jiton or toboolean(analysis.jiton,true)) and true or nil + -- + if not formatfile or not scriptfile then + report("warning: no format found, forcing remake (source driven)") + scripts.context.make(formatname,a_engine) + formatfile, scriptfile = resolvers.locateformat(formatname) + end + if formatfile and scriptfile then + local suffix = validstring(getargument("suffix")) + local resultname = validstring(getargument("result")) + if suffix then + resultname = file.removesuffix(jobname) .. suffix + end + local oldbase = "" + local newbase = "" + if resultname then + oldbase = file.removesuffix(jobname) + newbase = file.removesuffix(resultname) + if oldbase ~= newbase then + if a_purgeresult then + result_push_purge(oldbase,newbase) + else + result_push_keep(oldbase,newbase) + end + else + resultname = nil + end + end + -- + local pdfview = getargument("autopdf") or getargument("closepdf") + if pdfview then + pdf_close(filename,pdfview) + if resultname then + pdf_close(resultname,pdfview) + end + end + -- + -- we could do this when locating the format and exit from luatex when + -- there is a version mismatch .. that way we can use stock luatex + -- plus mtxrun to run luajittex instead .. this saves a restart but is + -- also cleaner as then mtxrun only has to check for a special return + -- code (signaling a make + rerun) .. maybe some day + -- + local okay = statistics.checkfmtstatus(formatfile,a_engine) + if okay ~= true then + report("warning: %s, forcing remake",tostring(okay)) + scripts.context.make(formatname) + end + -- + local oldhash = multipass_hashfiles(jobname) + local newhash = { } + local maxnofruns = once and 1 or multipass_nofruns + -- + local c_flags = { + directives = validstring(environment.directives), -- gets passed via mtxrun + trackers = validstring(environment.trackers), -- gets passed via mtxrun + experiments = validstring(environment.experiments), -- gets passed via mtxrun + -- + result = validstring(resultname), + input = validstring(getargument("input") or filename), -- alternative input + fulljobname = validstring(filename), + files = concat(files,","), + ctx = validstring(ctxname), + } + -- + for k, v in next, environment.arguments do + -- the raw arguments + if c_flags[k] == nil then + c_flags[k] = v + end + end + -- + -- + local l_flags = { + ["interaction"] = a_batchmode, + ["synctex"] = a_synctex, + ["no-parse-first-line"] = true, + -- ["no-mktex"] = true, + -- ["file-line-error-style"] = true, + ["fmt"] = formatfile, + ["lua"] = scriptfile, + ["jobname"] = jobname, + ["jiton"] = a_jiton, + } + -- + if a_synctex then + report("warning: synctex is enabled") -- can add upto 5% runtime + end + -- + if not a_timing then + -- okay + elseif c_flags.usemodule then + c_flags.usemodule = format("timing,%s",c_flags.usemodule) + else + c_flags.usemodule = "timing" + end + -- + if not a_profile then + -- okay + elseif c_flags.directives then + c_flags.directives = format("system.profile,%s",c_flags.directives) + else + c_flags.directives = "system.profile" + end + -- + -- kindofrun: 1:first run, 2:successive run, 3:once, 4:last of maxruns + -- + for currentrun=1,maxnofruns do + -- + c_flags.final = false + c_flags.kindofrun = (a_once and 3) or (currentrun==1 and 1) or (currentrun==maxnofruns and 4) or 2 + c_flags.maxnofruns = maxnofruns + c_flags.currentrun = currentrun + c_flags.noarrange = a_noarrange or a_arrange or nil + -- + local command = luatex_command(l_flags,c_flags,mainfile,a_engine) + -- + report("run %s: %s",i,command) + print("") -- cleaner, else continuation on same line + local returncode, errorstring = os.spawn(command) + if not returncode then + report("fatal error: no return code, message: %s",errorstring or "?") + if resultname then + result_save_error(oldbase,newbase) + end + os.exit(1) + break + elseif returncode == 0 then + multipass_copyluafile(jobname) + newhash = multipass_hashfiles(jobname) + if multipass_changed(oldhash,newhash) then + oldhash = newhash + else + break + end + else + report("fatal error: return code: %s",returncode or "?") + if resultname then + result_save_error(oldbase,newbase) + end + os.exit(1) -- (returncode) + break + end + -- + end + -- + if a_arrange then + -- + c_flags.final = true + c_flags.kindofrun = 3 + c_flags.currentrun = c_flags.currentrun + 1 + c_flags.noarrange = nil + -- + local command = luatex_command(l_flags,c_flags,mainfile,a_engine) + -- + report("arrange run: %s",command) + local returncode, errorstring = os.spawn(command) + if not returncode then + report("fatal error: no return code, message: %s",errorstring or "?") + os.exit(1) + elseif returncode > 0 then + report("fatal error: return code: %s",returncode or "?") + os.exit(returncode) + end + -- + end + -- + if a_purge then + scripts.context.purge_job(jobname) + elseif a_purgeall then + scripts.context.purge_job(jobname,true) + end + -- + if resultname then + if a_purgeresult then + -- so, if there is no result then we don't get the old one, but + -- related files (log etc) are still there for tracing purposes + result_save_purge(oldbase,newbase) + else + result_save_keep(oldbase,newbase) + end + report("result renamed to: %s",newbase) + end + -- + if purge then + scripts.context.purge_job(resultname) + elseif purgeall then + scripts.context.purge_job(resultname,true) + end + -- + local pdfview = getargument("autopdf") + if pdfview then + pdf_open(resultname or jobname,pdfview) + end + -- + if a_timing then + report() + report("you can process (timing) statistics with:",jobname) + report() + report("context --extra=timing '%s'",jobname) + report("mtxrun --script timing --xhtml [--launch --remove] '%s'",jobname) + report() + end + else + if formatname then + report("error, no format found with name: %s, skipping",formatname) + else + report("error, no format found (provide formatname or interface)") + end + break + end + end + end + -- +end + +function scripts.context.pipe() -- still used? + -- context --pipe + -- context --pipe --purge --dummyfile=whatever.tmp + local interface = getargument("interface") + interface = (type(interface) == "string" and interface) or "en" + local formatname = formatofinterface[interface] or "cont-en" + local formatfile, scriptfile = resolvers.locateformat(formatname) + if not formatfile or not scriptfile then + report("warning: no format found, forcing remake (commandline driven)") + scripts.context.make(formatname) + formatfile, scriptfile = resolvers.locateformat(formatname) + end + if formatfile and scriptfile then + local okay = statistics.checkfmtstatus(formatfile) + if okay ~= true then + report("warning: %s, forcing remake",tostring(okay)) + scripts.context.make(formatname) + end + local l_flags = { + interaction = "scrollmode", + fmt = formatfile, + lua = scriptfile, + } + local c_flags = { + backend = "pdf", + final = false, + kindofrun = 3, + currentrun = 1, + } + local filename = getargument("dummyfile") or "" + if filename == "" then + filename = "\\relax" + report("entering scrollmode, end job with \\end") + else + filename = file.addsuffix(filename,"tmp") + io.savedata(filename,"\\relax") + report("entering scrollmode using '%s' with optionfile, end job with \\end",filename) + end + local command = luatex_command(l_flags,c_flags,filename) + os.spawn(command) + if getargument("purge") then + scripts.context.purge_job(filename) + elseif getargument("purgeall") then + scripts.context.purge_job(filename,true) + os.remove(filename) + end + else + if formatname then + report("error, no format found with name: %s, aborting",formatname) + else + report("error, no format found (provide formatname or interface)") + end + end +end + +local function make_mkiv_format(name,engine) + environment.make_format(name) -- jit is picked up later +end + +local function make_mkii_format(name,engine) + local command = format("mtxrun texexec.rb --make --%s %s",name,engine) + report("running command: %s",command) + os.spawn(command) +end + +function scripts.context.generate() + resolvers.instance.renewcache = true + trackers.enable("resolvers.locating") + resolvers.load() +end + +function scripts.context.make(name) + if not getargument("fast") then -- as in texexec + scripts.context.generate() + end + local list = (name and { name }) or (environment.files[1] and environment.files) or defaultformats + local engine = getargument("engine") or "luatex" + if getargument("jit") or getargument("jiton") then + engine = "luajittex" + end + for i=1,#list do + local name = list[i] + name = formatofinterface[name] or name or "" + if name == "" then + -- nothing + elseif engine == "luatex" or engine == "luajittex" then + make_mkiv_format(name,engine) + elseif engine == "pdftex" or engine == "xetex" then + make_mkii_format(name,engine) + end + end +end + +function scripts.context.ctx() + local ctxdata = ctxrunner.new() + ctxdata.jobname = environment.files[1] + ctxrunner.checkfile(ctxdata,getargument("ctx")) + ctxrunner.checkflags(ctxdata) + scripts.context.run(ctxdata) +end + +function scripts.context.autoctx() + local ctxdata = nil + local files = environment.files + local firstfile = #files > 0 and files[1] + if firstfile then + local suffix = file.suffix(firstfile) + if suffix == "xml" then + local chunk = io.loadchunk(firstfile) -- 1024 + if chunk then + local ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") + if ctxname then + ctxdata = ctxrunner.new() + ctxdata.jobname = firstfile + ctxrunner.checkfile(ctxdata,ctxname) + ctxrunner.checkflags(ctxdata) + end + end + elseif suffix == "tex" then + -- maybe but we scan the preamble later too + end + end + scripts.context.run(ctxdata) +end + +-- no longer ok as mlib-run misses something: + +-- local template = [[ +-- \starttext +-- \directMPgraphic{%s}{input "%s"} +-- \stoptext +-- ]] +-- +-- local loaded = false +-- +-- function scripts.context.metapost() +-- local filename = environment.files[1] or "" +-- if not loaded then +-- dofile(resolvers.findfile("mlib-run.lua")) +-- loaded = true +-- commands = commands or { } +-- commands.writestatus = report -- no longer needed +-- end +-- local formatname = getargument("format") or "metafun" +-- if formatname == "" or type(formatname) == "boolean" then +-- formatname = "metafun" +-- end +-- if getargument("pdf") then +-- local basename = file.removesuffix(filename) +-- local resultname = getargument("result") or basename +-- local jobname = "mtx-context-metapost" +-- local tempname = file.addsuffix(jobname,"tex") +-- io.savedata(tempname,format(template,"metafun",filename)) +-- environment.files[1] = tempname +-- setargument("result",resultname) +-- setargument("once",true) +-- scripts.context.run() +-- scripts.context.purge_job(jobname,true) +-- scripts.context.purge_job(resultname,true) +-- elseif getargument("svg") then +-- metapost.directrun(formatname,filename,"svg") +-- else +-- metapost.directrun(formatname,filename,"mps") +-- end +-- end + +-- -- + +function scripts.context.version() + local name = resolvers.findfile("context.mkiv") + if name ~= "" then + report("main context file: %s",name) + local data = io.loaddata(name) + if data then + local version = match(data,"\\edef\\contextversion{(.-)}") + if version then + report("current version: %s",version) + else + report("context version: unknown, no timestamp found") + end + else + report("context version: unknown, load error") + end + else + report("main context file: unknown, 'context.mkiv' not found") + end +end + +-- purging files + +local generic_files = { + "texexec.tex", "texexec.tui", "texexec.tuo", + "texexec.tuc", "texexec.tua", + "texexec.ps", "texexec.pdf", "texexec.dvi", + "cont-opt.tex", "cont-opt.bak" +} + +local obsolete_results = { + "dvi", +} + +local temporary_runfiles = { + "tui", "tua", "tup", "ted", "tes", "top", + "log", "tmp", "run", "bck", "rlg", + "mpt", "mpx", "mpd", "mpo", "mpb", "ctl", + "synctex", "synctex.gz", "pgf", + "prep", +} + +local persistent_runfiles = { + "tuo", "tub", "top", "tuc" +} + +local special_runfiles = { + "-mpgraph", "-mprun", "-temp-" +} + +local function purge_file(dfile,cfile) + if cfile and lfs.isfile(cfile) then + if os.remove(dfile) then + return file.basename(dfile) + end + elseif dfile then + if os.remove(dfile) then + return file.basename(dfile) + end + end +end + +function scripts.context.purge_job(jobname,all,mkiitoo) + if jobname and jobname ~= "" then + jobname = file.basename(jobname) + local filebase = file.removesuffix(jobname) + if mkiitoo then + scripts.context.purge(all,filebase,true) -- leading "./" + else + local deleted = { } + for i=1,#obsolete_results do + deleted[#deleted+1] = purge_file(filebase.."."..obsolete_results[i],filebase..".pdf") + end + for i=1,#temporary_runfiles do + deleted[#deleted+1] = purge_file(filebase.."."..temporary_runfiles[i]) + end + if all then + for i=1,#persistent_runfiles do + deleted[#deleted+1] = purge_file(filebase.."."..persistent_runfiles[i]) + end + end + if #deleted > 0 then + report("purged files: %s", concat(deleted,", ")) + end + end + end +end + +function scripts.context.purge(all,pattern,mkiitoo) + local all = all or getargument("all") + local pattern = getargument("pattern") or (pattern and (pattern.."*")) or "*.*" + local files = dir.glob(pattern) + local obsolete = table.tohash(obsolete_results) + local temporary = table.tohash(temporary_runfiles) + local persistent = table.tohash(persistent_runfiles) + local generic = table.tohash(generic_files) + local deleted = { } + for i=1,#files do + local name = files[i] + local suffix = file.suffix(name) + local basename = file.basename(name) + if obsolete[suffix] or temporary[suffix] or persistent[suffix] or generic[basename] then + deleted[#deleted+1] = purge_file(name) + elseif mkiitoo then + for i=1,#special_runfiles do + if find(name,special_runfiles[i]) then + deleted[#deleted+1] = purge_file(name) + end + end + end + end + if #deleted > 0 then + report("purged files: %s", concat(deleted,", ")) + end +end + +-- touching files (signals regeneration of formats) + +local function touch(path,name,versionpattern,kind,kindpattern) + if path and path ~= "" then + name = file.join(path,name) +print(name) + else + name = resolvers.findfile(name) + end + local olddata = io.loaddata(name) + if olddata then + local oldkind, newkind = "", kind or "" + local oldversion, newversion = "", os.date("%Y.%m.%d %H:%M") + local newdata + if versionpattern then + newdata = gsub(olddata,versionpattern,function(pre,mid,post) + oldversion = mid + return pre .. newversion .. post + end) or olddata + end + if kind and kindpattern then + newdata = gsub(newdata,kindpattern,function(pre,mid,post) + oldkind = mid + return pre .. newkind .. post + end) or newdata + end + if newdata ~= "" and (oldversion ~= newversion or oldkind ~= newkind or newdata ~= olddata) then + local backup = file.replacesuffix(name,"tmp") + os.remove(backup) + os.rename(name,backup) + io.savedata(name,newdata) + return name, oldversion, newversion, oldkind, newkind + end + end +end + +local p_contextkind = "(\\edef\\contextkind%s*{)(.-)(})" +local p_contextversion = "(\\edef\\contextversion%s*{)(.-)(})" +local p_newcontextversion = "(\\newcontextversion%s*{)(.-)(})" + +local function touchfiles(suffix,kind,path) + local foundname, oldversion, newversion, oldkind, newkind = touch(path,file.addsuffix("context",suffix),p_contextversion,kind,p_contextkind) + if foundname then + report("old version : %s (%s)",oldversion,oldkind) + report("new version : %s (%s)",newversion,newkind) + report("touched file : %s",foundname) + local foundname = touch(path,file.addsuffix("cont-new",suffix),p_newcontextversion) + if foundname then + report("touched file : %s", foundname) + end + else + report("nothing touched") + end +end + +function scripts.context.touch() + if getargument("expert") then + local touch = getargument("touch") + local kind = getargument("kind") + local path = getargument("basepath") + if touch == "mkii" or touch == "mkiv" or touch == "mkvi" then -- mkix mkxi + touchfiles(touch,kind,path) + else + touchfiles("mkii",kind,path) + touchfiles("mkiv",kind,path) + touchfiles("mkvi",kind,path) + end + else + report("touching needs --expert") + end +end + +-- modules + +local labels = { "title", "comment", "status" } +local cards = { "*.mkvi", "*.mkiv", "*.mkxi", "*.mkix", "*.tex" } + +function scripts.context.modules(pattern) + local list = { } + local found = resolvers.findfile("context.mkiv") + if not pattern or pattern == "" then + -- official files in the tree + for i=1,#cards do + resolvers.findwildcardfiles(cards[i],list) + end + -- my dev path + for i=1,#cards do + dir.glob(file.join(file.dirname(found),cards[i]),list) + end + else + resolvers.findwildcardfiles(pattern,list) + dir.glob(file.join(file.dirname(found,pattern)),list) + end + local done = { } -- todo : sort + for i=1,#list do + local v = list[i] + local base = file.basename(v) + if not done[base] then + done[base] = true + local suffix = file.suffix(base) + if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" or suffix == "mkix" or suffix == "mkxi" then + local prefix = match(base,"^([xmst])%-") + if prefix then + v = resolvers.findfile(base) -- so that files on my dev path are seen + local data = io.loaddata(v) or "" + data = match(data,"%% begin info(.-)%% end info") + if data then + local info = { } + for label, text in gmatch(data,"%% +([^ ]+) *: *(.-)[\n\r]") do + info[label] = text + end + report() + report("%-7s : %s","module",base) + report() + for i=1,#labels do + local l = labels[i] + if info[l] then + report("%-7s : %s",l,info[l]) + end + end + report() + end + end + end + end + end +end + +-- extras + +function scripts.context.extras(pattern) + -- only in base path, i.e. only official ones + if type(pattern) ~= "string" then + pattern = "*" + end + local found = resolvers.findfile("context.mkiv") + if found ~= "" then + pattern = file.join(dir.expandname(file.dirname(found)),format("mtx-context-%s.tex",pattern or "*")) + local list = dir.glob(pattern) + for i=1,#list do + local v = list[i] + local data = io.loaddata(v) or "" + data = match(data,"%% begin help(.-)%% end help") + if data then + report() + report("extra: %s (%s)",(gsub(v,"^.*mtx%-context%-(.-)%.tex$","%1")),v) + for s in gmatch(data,"%% *(.-)[\n\r]") do + report(s) + end + report() + end + end + end +end + +function scripts.context.extra() + local extra = getargument("extra") + if type(extra) ~= "string" then + scripts.context.extras() + elseif getargument("help") then + scripts.context.extras(extra) + else + local fullextra = extra + if not find(fullextra,"mtx%-context%-") then + fullextra = "mtx-context-" .. extra + end + local foundextra = resolvers.findfile(fullextra) + if foundextra == "" then + scripts.context.extras() + return + else + report("processing extra: %s", foundextra) + end + setargument("purgeall",true) + local result = getargument("result") or "" + if result == "" then + setargument("result","context-extra") + end + scripts.context.run(nil,foundextra) + end +end + +-- todo: we need to do a dummy run + +function scripts.context.trackers() + environment.files = { resolvers.findfile("m-trackers.mkiv") } + multipass_nofruns = 1 + setargument("purgeall",true) + scripts.context.run() +end + +function scripts.context.directives() + environment.files = { resolvers.findfile("m-directives.mkiv") } + multipass_nofruns = 1 + setargument("purgeall",true) + scripts.context.run() +end + +function scripts.context.logcategories() + environment.files = { resolvers.findfile("m-logcategories.mkiv") } + multipass_nofruns = 1 + setargument("purgeall",true) + scripts.context.run() +end + +-- updating (often one will use mtx-update instead) + +function scripts.context.timed(action) + statistics.timed(action) +end + +local zipname = "cont-tmf.zip" +local mainzip = "http://www.pragma-ade.com/context/latest/" .. zipname +local validtrees = { "texmf-local", "texmf-context" } +local selfscripts = { "mtxrun.lua" } -- was: { "luatools.lua", "mtxrun.lua" } + +function zip.loaddata(zipfile,filename) -- should be in zip lib + local f = zipfile:open(filename) + if f then + local data = f:read("*a") + f:close() + return data + end + return nil +end + +function scripts.context.update() + local force = getargument("force") + local socket = require("socket") + local http = require("socket.http") + local basepath = resolvers.findfile("context.mkiv") or "" + if basepath == "" then + report("quiting, no 'context.mkiv' found") + return + end + local basetree = basepath.match(basepath,"^(.-)tex/context/base/context.mkiv$") or "" + if basetree == "" then + report("quiting, no proper tds structure (%s)",basepath) + return + end + local function is_okay(basetree) + for _, tree in next, validtrees do + local pattern = gsub(tree,"%-","%%-") + if find(basetree,pattern) then + return tree + end + end + return false + end + local okay = is_okay(basetree) + if not okay then + report("quiting, tree '%s' is protected",okay) + return + else + report("updating tree '%s'",okay) + end + if not lfs.chdir(basetree) then + report("quiting, unable to change to '%s'",okay) + return + end + report("fetching '%s'",mainzip) + local latest = http.request(mainzip) + if not latest then + report("context tree '%s' can be updated, use --force",okay) + return + end + io.savedata("cont-tmf.zip",latest) + if false then + -- variant 1 + os.execute("mtxrun --script unzip cont-tmf.zip") + else + -- variant 2 + local zipfile = zip.open(zipname) + if not zipfile then + report("quiting, unable to open '%s'",zipname) + return + end + local newfile = zip.loaddata(zipfile,"tex/context/base/context.mkiv") + if not newfile then + report("quiting, unable to open '%s'","context.mkiv") + return + end + local oldfile = io.loaddata(resolvers.findfile("context.mkiv")) or "" + local function versiontonumber(what,str) + local version = match(str,"\\edef\\contextversion{(.-)}") or "" + local year, month, day, hour, minute = match(str,"\\edef\\contextversion{(%d+)%.(%d+)%.(%d+) *(%d+)%:(%d+)}") + if year and minute then + local time = os.time { year=year,month=month,day=day,hour=hour,minute=minute} + report("%s version: %s (%s)",what,version,time) + return time + else + report("%s version: %s (unknown)",what,version) + return nil + end + end + local oldversion = versiontonumber("old",oldfile) + local newversion = versiontonumber("new",newfile) + if not oldversion or not newversion then + report("quiting, version cannot be determined") + return + elseif oldversion == newversion then + report("quiting, your current version is up-to-date") + return + elseif oldversion > newversion then + report("quiting, your current version is newer") + return + end + for k in zipfile:files() do + local filename = k.filename + if find(filename,"/$") then + lfs.mkdir(filename) + else + local data = zip.loaddata(zipfile,filename) + if data then + if force then + io.savedata(filename,data) + end + report(filename) + end + end + end + for _, scriptname in next, selfscripts do + local oldscript = resolvers.findfile(scriptname) or "" + if oldscript ~= "" and is_okay(oldscript) then + local newscript = "./scripts/context/lua/" .. scriptname + local data = io.loaddata(newscript) or "" + if data ~= "" then + report("replacing script '%s' by '%s'",oldscript,newscript) + if force then + io.savedata(oldscript,data) + end + end + else + report("keeping script '%s'",oldscript) + end + end + if force then + scripts.context.make() + end + end + if force then + report("context tree '%s' has been updated",okay) + else + report("context tree '%s' can been updated (use --force)",okay) + end +end + +-- getting it done + +if getargument("nostats") then + setargument("nostatistics",true) + setargument("nostat",nil) +end + +if getargument("batch") then + setargument("batchmode",true) + setargument("batch",nil) +end + +if getargument("nonstop") then + setargument("nonstopmode",true) + setargument("nonstop",nil) +end + +do + + local silent = getargument("silent") + if type(silent) == "string" then + directives.enable(format("logs.blocked={%s}",silent)) + elseif silent then + directives.enable("logs.blocked") + end + +end + +if getargument("once") then + multipass_nofruns = 1 +elseif getargument("runs") then + multipass_nofruns = tonumber(getargument("runs")) or nil +end + +if getargument("run") then + scripts.context.timed(scripts.context.autoctx) +elseif getargument("make") then + scripts.context.timed(function() scripts.context.make() end) +elseif getargument("generate") then + scripts.context.timed(function() scripts.context.generate() end) +elseif getargument("ctx") then + scripts.context.timed(scripts.context.ctx) +-- elseif getargument("mp") or getargument("metapost") then +-- scripts.context.timed(scripts.context.metapost) +elseif getargument("version") then + application.identify() + scripts.context.version() +elseif getargument("touch") then + scripts.context.touch() +elseif getargument("update") then + scripts.context.update() +elseif getargument("expert") then + application.help("expert", "special") +elseif getargument("modules") then + scripts.context.modules() +elseif getargument("extras") then + scripts.context.extras(environment.files[1] or getargument("extras")) +elseif getargument("extra") then + scripts.context.extra() +elseif getargument("exporthelp") then + -- application.export(getargument("exporthelp"),environment.files[1]) + application.export() +elseif getargument("help") then + if environment.files[1] == "extras" then + scripts.context.extras() + else + application.help("basic") + end +elseif getargument("showtrackers") or getargument("trackers") == true then + scripts.context.trackers() +elseif getargument("showdirectives") or getargument("directives") == true then + scripts.context.directives() +elseif getargument("showlogcategories") then + scripts.context.logcategories() +elseif environment.files[1] or getargument("nofile") then + scripts.context.timed(scripts.context.autoctx) +elseif getargument("pipe") then + scripts.context.timed(scripts.context.pipe) +elseif getargument("purge") then + -- only when no filename given, supports --pattern + scripts.context.purge() +elseif getargument("purgeall") then + -- only when no filename given, supports --pattern + scripts.context.purge(true,nil,true) +else + application.help("basic") +end diff --git a/scripts/context/lua/mtx-convert.lua b/scripts/context/lua/mtx-convert.lua index b76b3baaf..e6de9356e 100644 --- a/scripts/context/lua/mtx-convert.lua +++ b/scripts/context/lua/mtx-convert.lua @@ -1,175 +1,175 @@ -if not modules then modules = { } end modules ['mtx-convert'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo: eps and svg - -local helpinfo = [[ - - - - mtx-convert - ConTeXT Graphic Conversion Helpers - 0.10 - - - - - convert all graphics on path - original graphics path - converted graphics path - watch folders - force conversion (even if older) - time between sweeps - - - - -]] - -local application = logs.application { - name = "mtx-convert", - banner = "ConTeXT Graphic Conversion Helpers 0.10", - helpinfo = helpinfo, -} - -local format, find = string.format, string.find -local concat = table.concat - -local report = application.report - -scripts = scripts or { } -scripts.convert = scripts.convert or { } -local convert = scripts.convert -convert.converters = convert.converters or { } -local converters = convert.converters - -local gsprogram = os.type == "windows" and "gswin32c" or "gs" -local gstemplate_eps = "%s -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dEPSCrop -dNOPAUSE -dSAFER -dNOCACHE -dBATCH -dAutoRotatePages=/None -dProcessColorModel=/DeviceCMYK -sOutputFile=%s %s -c quit" -local gstemplate_ps = "%s -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dNOPAUSE -dSAFER -dNOCACHE -dBATCH -dAutoRotatePages=/None -dProcessColorModel=/DeviceCMYK -sOutputFile=%s %s -c quit" - -function converters.eps(oldname,newname) - return format(gstemplate_eps,gsprogram,newname,oldname) -end - -function converters.ps(oldname,newname) - return format(gstemplate_ps,gsprogram,newname,oldname) -end - -local improgram = "convert" -local imtemplate = { - low = "%s -quality 0 -compress zip %s pdf:%s", - medium = "%s -quality 75 -compress zip %s pdf:%s", - high = "%s -quality 100 -compress zip %s pdf:%s", -} - -function converters.jpg(oldname,newname) - local ea = environment.arguments - local quality = (ea.high and 'high') or (ea.medium and 'medium') or (ea.low and 'low') or 'high' - return format(imtemplate[quality],improgram,oldname,newname) -end - -converters.gif = converters.jpg -converters.tif = converters.jpg -converters.tiff = converters.jpg -converters.png = converters.jpg - -function converters.convertgraphic(kind,oldname,newname) - if converters[kind] then -- extra test - local tmpname = file.replacesuffix(newname,"tmp") - local command = converters[kind](oldname,tmpname) - report("command: %s",command) - io.flush() - os.spawn(command) - os.remove(newname) - os.rename(tmpname,newname) - if lfs.attributes(newname,"size") == 0 then - os.remove(newname) - end - end -end - -function converters.convertpath(inputpath,outputpath) - inputpath = inputpath or "." - outputpath = outputpath or "." - for name in lfs.dir(inputpath) do - local suffix = file.suffix(name) - if find(name,"%.$") then - -- skip . and .. - elseif converters[suffix] then - local oldname = file.join(inputpath,name) - local newname = file.join(outputpath,file.replacesuffix(name,"pdf")) - local et = lfs.attributes(oldname,"modification") - local pt = lfs.attributes(newname,"modification") - if not pt or et > pt then - dir.mkdirs(outputpath) - converters.convertgraphic(suffix,oldname,newname) - end - elseif lfs.isdir(inputpath .. "/".. name) then - converters.convertpath(inputpath .. "/".. name,outputpath .. "/".. name) - end - end -end - -function converters.convertfile(oldname) - local suffix = file.suffix(oldname) - if converters[suffix] then - local newname = file.replacesuffix(oldname,"pdf") - if oldname == newname then - -- todo: downsample, crop etc - elseif environment.argument("force") then - converters.convertgraphic(suffix,oldname,newname) - else - local et = lfs.attributes(oldname,"modification") - local pt = lfs.attributes(newname,"modification") - if not pt or et > pt then - converters.convertgraphic(suffix,oldname,newname) - end - end - end -end - -if environment.ownscript then - -- stand alone -else - report(application.banner) - return convert -end - -convert.delay = 5 * 60 -- 5 minutes - -function convert.convertall() - local watch = environment.arguments.watch or false - local delay = environment.arguments.delay or convert.delay - local input = environment.arguments.inputpath or "." - local output = environment.arguments.outputpath or "." - while true do - converters.convertpath(input, output) - if watch then - os.sleep(delay) - else - break - end - end -end - -function convert.convertgiven() - local files = environment.files - for i=1,#files do - converters.convertfile(files[i]) - end -end - -if environment.arguments.convertall then - convert.convertall() -elseif environment.files[1] then - convert.convertgiven() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-convert'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: eps and svg + +local helpinfo = [[ + + + + mtx-convert + ConTeXT Graphic Conversion Helpers + 0.10 + + + + + convert all graphics on path + original graphics path + converted graphics path + watch folders + force conversion (even if older) + time between sweeps + + + + +]] + +local application = logs.application { + name = "mtx-convert", + banner = "ConTeXT Graphic Conversion Helpers 0.10", + helpinfo = helpinfo, +} + +local format, find = string.format, string.find +local concat = table.concat + +local report = application.report + +scripts = scripts or { } +scripts.convert = scripts.convert or { } +local convert = scripts.convert +convert.converters = convert.converters or { } +local converters = convert.converters + +local gsprogram = os.type == "windows" and "gswin32c" or "gs" +local gstemplate_eps = "%s -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dEPSCrop -dNOPAUSE -dSAFER -dNOCACHE -dBATCH -dAutoRotatePages=/None -dProcessColorModel=/DeviceCMYK -sOutputFile=%s %s -c quit" +local gstemplate_ps = "%s -q -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dNOPAUSE -dSAFER -dNOCACHE -dBATCH -dAutoRotatePages=/None -dProcessColorModel=/DeviceCMYK -sOutputFile=%s %s -c quit" + +function converters.eps(oldname,newname) + return format(gstemplate_eps,gsprogram,newname,oldname) +end + +function converters.ps(oldname,newname) + return format(gstemplate_ps,gsprogram,newname,oldname) +end + +local improgram = "convert" +local imtemplate = { + low = "%s -quality 0 -compress zip %s pdf:%s", + medium = "%s -quality 75 -compress zip %s pdf:%s", + high = "%s -quality 100 -compress zip %s pdf:%s", +} + +function converters.jpg(oldname,newname) + local ea = environment.arguments + local quality = (ea.high and 'high') or (ea.medium and 'medium') or (ea.low and 'low') or 'high' + return format(imtemplate[quality],improgram,oldname,newname) +end + +converters.gif = converters.jpg +converters.tif = converters.jpg +converters.tiff = converters.jpg +converters.png = converters.jpg + +function converters.convertgraphic(kind,oldname,newname) + if converters[kind] then -- extra test + local tmpname = file.replacesuffix(newname,"tmp") + local command = converters[kind](oldname,tmpname) + report("command: %s",command) + io.flush() + os.spawn(command) + os.remove(newname) + os.rename(tmpname,newname) + if lfs.attributes(newname,"size") == 0 then + os.remove(newname) + end + end +end + +function converters.convertpath(inputpath,outputpath) + inputpath = inputpath or "." + outputpath = outputpath or "." + for name in lfs.dir(inputpath) do + local suffix = file.suffix(name) + if find(name,"%.$") then + -- skip . and .. + elseif converters[suffix] then + local oldname = file.join(inputpath,name) + local newname = file.join(outputpath,file.replacesuffix(name,"pdf")) + local et = lfs.attributes(oldname,"modification") + local pt = lfs.attributes(newname,"modification") + if not pt or et > pt then + dir.mkdirs(outputpath) + converters.convertgraphic(suffix,oldname,newname) + end + elseif lfs.isdir(inputpath .. "/".. name) then + converters.convertpath(inputpath .. "/".. name,outputpath .. "/".. name) + end + end +end + +function converters.convertfile(oldname) + local suffix = file.suffix(oldname) + if converters[suffix] then + local newname = file.replacesuffix(oldname,"pdf") + if oldname == newname then + -- todo: downsample, crop etc + elseif environment.argument("force") then + converters.convertgraphic(suffix,oldname,newname) + else + local et = lfs.attributes(oldname,"modification") + local pt = lfs.attributes(newname,"modification") + if not pt or et > pt then + converters.convertgraphic(suffix,oldname,newname) + end + end + end +end + +if environment.ownscript then + -- stand alone +else + report(application.banner) + return convert +end + +convert.delay = 5 * 60 -- 5 minutes + +function convert.convertall() + local watch = environment.arguments.watch or false + local delay = environment.arguments.delay or convert.delay + local input = environment.arguments.inputpath or "." + local output = environment.arguments.outputpath or "." + while true do + converters.convertpath(input, output) + if watch then + os.sleep(delay) + else + break + end + end +end + +function convert.convertgiven() + local files = environment.files + for i=1,#files do + converters.convertfile(files[i]) + end +end + +if environment.arguments.convertall then + convert.convertall() +elseif environment.files[1] then + convert.convertgiven() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-fcd.lua b/scripts/context/lua/mtx-fcd.lua index ba9299020..81e67ca2f 100644 --- a/scripts/context/lua/mtx-fcd.lua +++ b/scripts/context/lua/mtx-fcd.lua @@ -1,386 +1,386 @@ -if not modules then modules = { } end modules ['mtx-fcd'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files", - comment = "based on the ruby version from 2005", -} - --- This is a kind of variant of the good old ncd (norton change directory) program. This --- script uses the same indirect cmd trick as Erwin Waterlander's wcd program. --- --- The program is called via the stubs fcd.cmd or fcd.sh. On unix one should probably source --- the file: ". fcd args" in order to make the chdir persistent. --- --- You need to create a stub with: --- --- mtxrun --script fcd --stub > fcd.cmd --- mtxrun --script fcd --stub > fcd.sh --- --- The stub starts this script and afterwards runs the created directory change script as --- part if the same run, so that indeed we change. - -local helpinfo = [[ - - - - mtx-fcd - Fast Directory Change - 1.00 - - - - - clear the cache - [entry] clear the history - clear the cache and add given path(s) - add given path(s) - find given path (can be substring) - find given path (can be substring) but don't use history - print platform stub file - show roots of cached dirs - show history of chosen dirs - show this help - - - - - - Example - - fcd --scan t:\ - fcd --add f:\project - fcd [--find] whatever - fcd --list - - - - -]] - -local application = logs.application { - name = "mtx-fcd", - banner = "Fast Directory Change 1.00", - helpinfo = helpinfo, -} - -local report = application.report -local writeln = print -- texio.write_nl - -local find, char, byte, lower, gsub, format = string.find, string.char, string.byte, string.lower, string.gsub, string.format - -local mswinstub = [[@echo off - -rem this is: fcd.cmd - -@echo off - -if not exist "%HOME%" goto homepath - -:home - -mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 - -if exist "%HOME%\mtx-fcd-goto.cmd" call "%HOME%\mtx-fcd-goto.cmd" - -goto end - -:homepath - -if not exist "%HOMEDRIVE%\%HOMEPATH%" goto end - -mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 - -if exist "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" call "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" - -goto end - -:end -]] - -local unixstub = [[#!/usr/bin/env sh - -# this is: fcd.sh - -# mv fcd.sh fcd -# chmod fcd 755 -# . fcd [args] - -ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9 - -if test -f "$HOME/fcd_stage.sh" ; then - . $HOME/fcd_stage.sh ; -fi; - -]] - -local gotofile -local datafile -local stubfile -local stubdata -local stubdummy -local stubchdir - -if os.platform == 'mswin' then - gotofile = 'mtx-fcd-goto.cmd' - datafile = 'mtx-fcd-data.lua' - stubfile = 'fcd.cmd' - stubdata = mswinstub - stubdummy = 'rem no dir to change to' - stubchdir = 'cd /d "%s"' -else - gotofile = 'mtx-fcd-goto.sh' - datafile = 'mtx-fcd-data.lua' - stubfile = 'fcd.sh' - stubdata = unixstub - stubdummy = '# no dir to change to' - stubchdir = '# cd "%s"' -end - -local homedir = os.env["HOME"] or "" -- no longer TMP etc - -if homedir == "" then - homedir = format("%s/%s",os.env["HOMEDRIVE"] or "",os.env["HOMEPATH"] or "") -end - -if homedir == "/" or not lfs.isdir(homedir) then - os.exit() -end - -local datafile = file.join(homedir,datafile) -local gotofile = file.join(homedir,gotofile) -local hash = nil -local found = { } -local pattern = "" -local version = modules['mtx-fcd'].version - -io.savedata(gotofile,stubdummy) - -if not lfs.isfile(gotofile) then - -- write error - os.exit() -end - -local function fcd_clear(onlyhistory,what) - if onlyhistory and hash and hash.history then - if what and what ~= "" then - hash.history[what] = nil - else - hash.history = { } - end - else - hash = { - name = "fcd cache", - comment = "generated by mtx-fcd.lua", - created = os.date(), - version = version, - paths = { }, - history = { }, - } - end -end - -local function fcd_changeto(dir) - if dir and dir ~= "" then - io.savedata(gotofile,format(stubchdir,dir)) - end -end - -local function fcd_load(forcecreate) - if lfs.isfile(datafile) then - hash = dofile(datafile) - end - if not hash or hash.version ~= version then - if forcecache then - fcd_clear() - else - writeln("empty dir cache") - fcd_clear() - os.exit() - end - end -end - -local function fcd_save() - if hash then - io.savedata(datafile,table.serialize(hash,true)) - end -end - -local function fcd_list(onlyhistory) - if hash then - writeln("") - if onlyhistory then - if next(hash.history) then - for k, v in table.sortedhash(hash.history) do - writeln(format("%s => %s",k,v)) - end - else - writeln("no history") - end - else - local paths = hash.paths - if #paths > 0 then - for i=1,#paths do - local path = paths[i] - writeln(format("%4i %s",#path[2],path[1])) - end - else - writeln("empty cache") - end - end - end -end - -local function fcd_find() - found = { } - pattern = environment.files[1] or "" - if pattern ~= "" then - pattern = string.escapedpattern(pattern) - local paths = hash.paths - for i=1,#paths do - local paths = paths[i][2] - for i=1,#paths do - local path = paths[i] - if find(path,pattern) then - found[#found+1] = path - end - end - end - end -end - -local function fcd_choose(new) - if pattern == "" then - writeln(format("staying in dir %q",(gsub(lfs.currentdir(),"\\","/")))) - return - end - if #found == 0 then - writeln(format("dir %q not found",pattern)) - return - end - local okay = #found == 1 and found[1] or (not new and hash.history[pattern]) - if okay then - writeln(format("changing to %q",okay)) - fcd_changeto(okay) - return - end - local offset = 0 - while true do - if not found[offset] then - offset = 0 - end - io.write("\n") - for i=1,26 do - local v = found[i+offset] - if v then - writeln(format("%s %3i %s",char(i+96),offset+i,v)) - else - break - end - end - offset = offset + 26 - if found[offset+1] then - io.write("\n[press enter for more or select letter]\n\n>> ") - else - io.write("\n[select letter]\n\n>> ") - end - local answer = lower(io.read() or "") - if not answer or answer == 'quit' then - break - elseif #answer > 0 then - local choice = tonumber(answer) - if not choice then - if answer >= "a" and answer <= "z" then - choice = byte(answer) - 96 + offset - 26 - end - end - local newdir = found[choice] - if newdir then - hash.history[pattern] = newdir - writeln(format("changing to %q",newdir)) - fcd_changeto(newdir) - fcd_save() - return - end - else - -- try again - end - end -end - -local function globdirs(path,dirs) - local dirs = dirs or { } - for name in lfs.dir(path) do - if not find(name,"%.$") then - local fullname = path .. "/" .. name - if lfs.isdir(fullname) and not find(fullname,"/%.") then - dirs[#dirs+1] = fullname - globdirs(fullname,dirs) - end - end - end - return dirs -end - -local function fcd_scan() - if hash then - local paths = hash.paths - for i=1,#environment.files do - local name = environment.files[i] - local name = gsub(name,"\\","/") - local name = gsub(name,"/$","") - local list = globdirs(name) - local done = false - for i=1,#paths do - if paths[i][1] == name then - paths[i][2] = list - done = true - break - end - end - if not done then - paths[#paths+1] = { name, list } - end - end - end -end - -local argument = environment.argument - -if argument("clear") then - if argument("history") then - fcd_load() - fcd_clear(true) - else - fcd_clear() - end - fcd_save() -elseif argument("scan") then - fcd_clear() - fcd_scan() - fcd_save() -elseif argument("add") then - fcd_load(true) - fcd_scan() - fcd_save() -elseif argument("stub") then - writeln(stubdata) -elseif argument("list") then - fcd_load() - if argument("history") then - fcd_list(true) - else - fcd_list() - end -elseif argument("help") then - application.help() -elseif argument("exporthelp") then - application.export(argument("exporthelp"),environment.files[1]) -else -- also argument("find") - fcd_load() - fcd_find() - fcd_choose(argument("nohistory")) -end - +if not modules then modules = { } end modules ['mtx-fcd'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + comment = "based on the ruby version from 2005", +} + +-- This is a kind of variant of the good old ncd (norton change directory) program. This +-- script uses the same indirect cmd trick as Erwin Waterlander's wcd program. +-- +-- The program is called via the stubs fcd.cmd or fcd.sh. On unix one should probably source +-- the file: ". fcd args" in order to make the chdir persistent. +-- +-- You need to create a stub with: +-- +-- mtxrun --script fcd --stub > fcd.cmd +-- mtxrun --script fcd --stub > fcd.sh +-- +-- The stub starts this script and afterwards runs the created directory change script as +-- part if the same run, so that indeed we change. + +local helpinfo = [[ + + + + mtx-fcd + Fast Directory Change + 1.00 + + + + + clear the cache + [entry] clear the history + clear the cache and add given path(s) + add given path(s) + find given path (can be substring) + find given path (can be substring) but don't use history + print platform stub file + show roots of cached dirs + show history of chosen dirs + show this help + + + + + + Example + + fcd --scan t:\ + fcd --add f:\project + fcd [--find] whatever + fcd --list + + + + +]] + +local application = logs.application { + name = "mtx-fcd", + banner = "Fast Directory Change 1.00", + helpinfo = helpinfo, +} + +local report = application.report +local writeln = print -- texio.write_nl + +local find, char, byte, lower, gsub, format = string.find, string.char, string.byte, string.lower, string.gsub, string.format + +local mswinstub = [[@echo off + +rem this is: fcd.cmd + +@echo off + +if not exist "%HOME%" goto homepath + +:home + +mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 + +if exist "%HOME%\mtx-fcd-goto.cmd" call "%HOME%\mtx-fcd-goto.cmd" + +goto end + +:homepath + +if not exist "%HOMEDRIVE%\%HOMEPATH%" goto end + +mtxrun --script mtx-fcd.lua %1 %2 %3 %4 %5 %6 %7 %8 %9 + +if exist "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" call "%HOMEDRIVE%\%HOMEPATH%\mtx-fcd-goto.cmd" + +goto end + +:end +]] + +local unixstub = [[#!/usr/bin/env sh + +# this is: fcd.sh + +# mv fcd.sh fcd +# chmod fcd 755 +# . fcd [args] + +ruby -S fcd_start.rb $1 $2 $3 $4 $5 $6 $7 $8 $9 + +if test -f "$HOME/fcd_stage.sh" ; then + . $HOME/fcd_stage.sh ; +fi; + +]] + +local gotofile +local datafile +local stubfile +local stubdata +local stubdummy +local stubchdir + +if os.platform == 'mswin' then + gotofile = 'mtx-fcd-goto.cmd' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.cmd' + stubdata = mswinstub + stubdummy = 'rem no dir to change to' + stubchdir = 'cd /d "%s"' +else + gotofile = 'mtx-fcd-goto.sh' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.sh' + stubdata = unixstub + stubdummy = '# no dir to change to' + stubchdir = '# cd "%s"' +end + +local homedir = os.env["HOME"] or "" -- no longer TMP etc + +if homedir == "" then + homedir = format("%s/%s",os.env["HOMEDRIVE"] or "",os.env["HOMEPATH"] or "") +end + +if homedir == "/" or not lfs.isdir(homedir) then + os.exit() +end + +local datafile = file.join(homedir,datafile) +local gotofile = file.join(homedir,gotofile) +local hash = nil +local found = { } +local pattern = "" +local version = modules['mtx-fcd'].version + +io.savedata(gotofile,stubdummy) + +if not lfs.isfile(gotofile) then + -- write error + os.exit() +end + +local function fcd_clear(onlyhistory,what) + if onlyhistory and hash and hash.history then + if what and what ~= "" then + hash.history[what] = nil + else + hash.history = { } + end + else + hash = { + name = "fcd cache", + comment = "generated by mtx-fcd.lua", + created = os.date(), + version = version, + paths = { }, + history = { }, + } + end +end + +local function fcd_changeto(dir) + if dir and dir ~= "" then + io.savedata(gotofile,format(stubchdir,dir)) + end +end + +local function fcd_load(forcecreate) + if lfs.isfile(datafile) then + hash = dofile(datafile) + end + if not hash or hash.version ~= version then + if forcecache then + fcd_clear() + else + writeln("empty dir cache") + fcd_clear() + os.exit() + end + end +end + +local function fcd_save() + if hash then + io.savedata(datafile,table.serialize(hash,true)) + end +end + +local function fcd_list(onlyhistory) + if hash then + writeln("") + if onlyhistory then + if next(hash.history) then + for k, v in table.sortedhash(hash.history) do + writeln(format("%s => %s",k,v)) + end + else + writeln("no history") + end + else + local paths = hash.paths + if #paths > 0 then + for i=1,#paths do + local path = paths[i] + writeln(format("%4i %s",#path[2],path[1])) + end + else + writeln("empty cache") + end + end + end +end + +local function fcd_find() + found = { } + pattern = environment.files[1] or "" + if pattern ~= "" then + pattern = string.escapedpattern(pattern) + local paths = hash.paths + for i=1,#paths do + local paths = paths[i][2] + for i=1,#paths do + local path = paths[i] + if find(path,pattern) then + found[#found+1] = path + end + end + end + end +end + +local function fcd_choose(new) + if pattern == "" then + writeln(format("staying in dir %q",(gsub(lfs.currentdir(),"\\","/")))) + return + end + if #found == 0 then + writeln(format("dir %q not found",pattern)) + return + end + local okay = #found == 1 and found[1] or (not new and hash.history[pattern]) + if okay then + writeln(format("changing to %q",okay)) + fcd_changeto(okay) + return + end + local offset = 0 + while true do + if not found[offset] then + offset = 0 + end + io.write("\n") + for i=1,26 do + local v = found[i+offset] + if v then + writeln(format("%s %3i %s",char(i+96),offset+i,v)) + else + break + end + end + offset = offset + 26 + if found[offset+1] then + io.write("\n[press enter for more or select letter]\n\n>> ") + else + io.write("\n[select letter]\n\n>> ") + end + local answer = lower(io.read() or "") + if not answer or answer == 'quit' then + break + elseif #answer > 0 then + local choice = tonumber(answer) + if not choice then + if answer >= "a" and answer <= "z" then + choice = byte(answer) - 96 + offset - 26 + end + end + local newdir = found[choice] + if newdir then + hash.history[pattern] = newdir + writeln(format("changing to %q",newdir)) + fcd_changeto(newdir) + fcd_save() + return + end + else + -- try again + end + end +end + +local function globdirs(path,dirs) + local dirs = dirs or { } + for name in lfs.dir(path) do + if not find(name,"%.$") then + local fullname = path .. "/" .. name + if lfs.isdir(fullname) and not find(fullname,"/%.") then + dirs[#dirs+1] = fullname + globdirs(fullname,dirs) + end + end + end + return dirs +end + +local function fcd_scan() + if hash then + local paths = hash.paths + for i=1,#environment.files do + local name = environment.files[i] + local name = gsub(name,"\\","/") + local name = gsub(name,"/$","") + local list = globdirs(name) + local done = false + for i=1,#paths do + if paths[i][1] == name then + paths[i][2] = list + done = true + break + end + end + if not done then + paths[#paths+1] = { name, list } + end + end + end +end + +local argument = environment.argument + +if argument("clear") then + if argument("history") then + fcd_load() + fcd_clear(true) + else + fcd_clear() + end + fcd_save() +elseif argument("scan") then + fcd_clear() + fcd_scan() + fcd_save() +elseif argument("add") then + fcd_load(true) + fcd_scan() + fcd_save() +elseif argument("stub") then + writeln(stubdata) +elseif argument("list") then + fcd_load() + if argument("history") then + fcd_list(true) + else + fcd_list() + end +elseif argument("help") then + application.help() +elseif argument("exporthelp") then + application.export(argument("exporthelp"),environment.files[1]) +else -- also argument("find") + fcd_load() + fcd_find() + fcd_choose(argument("nohistory")) +end + diff --git a/scripts/context/lua/mtx-flac.lua b/scripts/context/lua/mtx-flac.lua index 2155b24be..2e988b412 100644 --- a/scripts/context/lua/mtx-flac.lua +++ b/scripts/context/lua/mtx-flac.lua @@ -1,238 +1,238 @@ -if not modules then modules = { } end modules ['mtx-flac'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local sub, match, byte, lower = string.sub, string.match, string.byte, string.lower -local readstring, readnumber = io.readstring, io.readnumber -local concat, sortedpairs = table.concat, table.sortedpairs -local tonumber = tonumber -local tobitstring = number.tobitstring -local lpegmatch = lpeg.match -local p_escaped = lpeg.patterns.xml.escaped - --- rather silly: pack info in bits while a flac file is large anyway - -flac = flac or { } - -flac.report = string.format - -local splitter = lpeg.splitat("=") -local readers = { } - -readers[0] = function(f,size,target) -- not yet ok .. todo: use bit32 lib - local info = { } - target.info = info - info.minimum_block_size = readnumber(f,-2) - info.maximum_block_size = readnumber(f,-2) - info.minimum_frame_size = readnumber(f,-3) - info.maximum_frame_size = readnumber(f,-3) - local buffer = { } - for i=1,8 do - buffer[i] = tobitstring(readnumber(f,1)) - end - local bytes = concat(buffer) - info.sample_rate_in_hz = tonumber(sub(bytes, 1,20),2) -- 20 - info.number_of_channels = tonumber(sub(bytes,21,23),2) -- 3 - info.bits_per_sample = tonumber(sub(bytes,24,28),2) -- 5 - info.samples_in_stream = tonumber(sub(bytes,29,64),2) -- 36 - info.md5_signature = readstring(f,16) -- 128 -end - -readers[4] = function(f,size,target,banner) - local tags = { } - target.tags = tags - target.vendor = readstring(f,readnumber(f,-4)) - for i=1,readnumber(f,-4) do - local key, value = lpeg.match(splitter,readstring(f,readnumber(f,-4))) - tags[lower(key)] = value - end -end - -readers.default = function(f,size,target) - f:seek("cur",size) -end - -function flac.getmetadata(filename) - local f = io.open(filename, "rb") - if f then - local banner = readstring(f,4) - if banner == "fLaC" then - local data = { - banner = banner, - filename = filename, - filesize = lfs.attributes(filename,"size"), - } - while true do - local flag = readnumber(f,1) - local size = readnumber(f,3) - local last = flag > 127 - if last then - flag = flag - 128 - end - local reader = readers[flag] or readers.default - reader(f,size,data,banner) - if last then - f:close() - return data - end - end - else - flac.report("no flac file: %s (%s)",filename,banner) - end - f:close() - else - flac.report("no file: %s",filename) - end -end - -function flac.savecollection(pattern,filename) - pattern = (pattern ~= "" and pattern) or "**/*.flac" - filename = (filename ~= "" and filename) or "music-collection.xml" - flac.report("identifying files using pattern %q" ,pattern) - local files = dir.glob(pattern) - flac.report("%s files found, analyzing files",#files) - local music = { } - for i=1,#files do - local data = flac.getmetadata(files[i]) - if data then - local tags = data.tags - local info = data.info - local artist = tags.artist - local album = tags.album - local albums = music[artist] - if not albums then - albums = { } - music[artist] = albums - end - local albumx = albums[album] - if not albumx then - albumx = { - year = tags.date, - tracks = { }, - } - albums[album] = albumx - end - albumx.tracks[tonumber(tags.tracknumber) or 0] = { - title = tags.title, - length = math.round((info.samples_in_stream/info.sample_rate_in_hz)), - } - end - end - -- inspect(music) - local nofartists, nofalbums, noftracks, noferrors = 0, 0, 0, 0 - local f = io.open(filename,"wb") - if f then - flac.report("saving data in file %q",filename) - f:write("\n\n") - f:write("\n") - for artist, albums in sortedpairs(music) do - nofartists = nofartists + 1 - f:write("\t\n") - f:write("\t\t",lpegmatch(p_escaped,artist),"\n") - f:write("\t\t\n") - for album, data in sortedpairs(albums) do - nofalbums = nofalbums + 1 - f:write("\t\t\t\n") - f:write("\t\t\t\t",lpegmatch(p_escaped,album),"\n") - f:write("\t\t\t\t\n") - local tracks = data.tracks - for i=1,#tracks do - local track = tracks[i] - if track then - noftracks = noftracks + 1 - f:write("\t\t\t\t\t",lpegmatch(p_escaped,track.title),"\n") - else - noferrors = noferrors + 1 - flac.report("error in album: %q of %q, no track %s",album,artist,i) - f:write("\t\t\t\t\t\n") - end - end - f:write("\t\t\t\t\n") - f:write("\t\t\t\n") - end - f:write("\t\t\n") - f:write("\t\n") - end - f:write("\n") - f:close() - flac.report("%s tracks of %s albums of %s artists saved in %q (%s errors)",noftracks,nofalbums,nofartists,filename,noferrors) - else - flac.report("unable to save data in file %q",filename) - end -end - --- - -local helpinfo = [[ - - - - mtx-flac - ConTeXt Flac Helpers - 0.10 - - - - - collect albums in xml file - - - - - - Example - - mtxrun --script flac --collect somename.flac - mtxrun --script flac --collect --pattern="m:/music/**") - - - - -]] - -local application = logs.application { - name = "mtx-flac", - banner = "ConTeXt Flac Helpers 0.10", - helpinfo = helpinfo, -} - -flac.report = application.report - --- script code - -scripts = scripts or { } -scripts.flac = scripts.flac or { } - -function scripts.flac.collect() - local files = environment.files - local pattern = environment.arguments.pattern - if #files > 0 then - for i=1,#files do - local filename = files[1] - if file.suffix(filename) == "flac" then - flac.savecollection(filename,file.replacesuffix(filename,"xml")) - elseif lfs.isdir(filename) then - local pattern = filename .. "/**.flac" - flac.savecollection(pattern,file.addsuffix(file.basename(filename),"xml")) - else - flac.savecollection(file.replacesuffix(filename,"flac"),file.replacesuffix(filename,"xml")) - end - end - elseif pattern then - flac.savecollection(file.addsuffix(pattern,"flac"),"music-collection.xml") - else - flac.report("no file(s) or pattern given" ) - end -end - -if environment.argument("collect") then - scripts.flac.collect() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-flac'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local sub, match, byte, lower = string.sub, string.match, string.byte, string.lower +local readstring, readnumber = io.readstring, io.readnumber +local concat, sortedpairs = table.concat, table.sortedpairs +local tonumber = tonumber +local tobitstring = number.tobitstring +local lpegmatch = lpeg.match +local p_escaped = lpeg.patterns.xml.escaped + +-- rather silly: pack info in bits while a flac file is large anyway + +flac = flac or { } + +flac.report = string.format + +local splitter = lpeg.splitat("=") +local readers = { } + +readers[0] = function(f,size,target) -- not yet ok .. todo: use bit32 lib + local info = { } + target.info = info + info.minimum_block_size = readnumber(f,-2) + info.maximum_block_size = readnumber(f,-2) + info.minimum_frame_size = readnumber(f,-3) + info.maximum_frame_size = readnumber(f,-3) + local buffer = { } + for i=1,8 do + buffer[i] = tobitstring(readnumber(f,1)) + end + local bytes = concat(buffer) + info.sample_rate_in_hz = tonumber(sub(bytes, 1,20),2) -- 20 + info.number_of_channels = tonumber(sub(bytes,21,23),2) -- 3 + info.bits_per_sample = tonumber(sub(bytes,24,28),2) -- 5 + info.samples_in_stream = tonumber(sub(bytes,29,64),2) -- 36 + info.md5_signature = readstring(f,16) -- 128 +end + +readers[4] = function(f,size,target,banner) + local tags = { } + target.tags = tags + target.vendor = readstring(f,readnumber(f,-4)) + for i=1,readnumber(f,-4) do + local key, value = lpeg.match(splitter,readstring(f,readnumber(f,-4))) + tags[lower(key)] = value + end +end + +readers.default = function(f,size,target) + f:seek("cur",size) +end + +function flac.getmetadata(filename) + local f = io.open(filename, "rb") + if f then + local banner = readstring(f,4) + if banner == "fLaC" then + local data = { + banner = banner, + filename = filename, + filesize = lfs.attributes(filename,"size"), + } + while true do + local flag = readnumber(f,1) + local size = readnumber(f,3) + local last = flag > 127 + if last then + flag = flag - 128 + end + local reader = readers[flag] or readers.default + reader(f,size,data,banner) + if last then + f:close() + return data + end + end + else + flac.report("no flac file: %s (%s)",filename,banner) + end + f:close() + else + flac.report("no file: %s",filename) + end +end + +function flac.savecollection(pattern,filename) + pattern = (pattern ~= "" and pattern) or "**/*.flac" + filename = (filename ~= "" and filename) or "music-collection.xml" + flac.report("identifying files using pattern %q" ,pattern) + local files = dir.glob(pattern) + flac.report("%s files found, analyzing files",#files) + local music = { } + for i=1,#files do + local data = flac.getmetadata(files[i]) + if data then + local tags = data.tags + local info = data.info + local artist = tags.artist + local album = tags.album + local albums = music[artist] + if not albums then + albums = { } + music[artist] = albums + end + local albumx = albums[album] + if not albumx then + albumx = { + year = tags.date, + tracks = { }, + } + albums[album] = albumx + end + albumx.tracks[tonumber(tags.tracknumber) or 0] = { + title = tags.title, + length = math.round((info.samples_in_stream/info.sample_rate_in_hz)), + } + end + end + -- inspect(music) + local nofartists, nofalbums, noftracks, noferrors = 0, 0, 0, 0 + local f = io.open(filename,"wb") + if f then + flac.report("saving data in file %q",filename) + f:write("\n\n") + f:write("\n") + for artist, albums in sortedpairs(music) do + nofartists = nofartists + 1 + f:write("\t\n") + f:write("\t\t",lpegmatch(p_escaped,artist),"\n") + f:write("\t\t\n") + for album, data in sortedpairs(albums) do + nofalbums = nofalbums + 1 + f:write("\t\t\t\n") + f:write("\t\t\t\t",lpegmatch(p_escaped,album),"\n") + f:write("\t\t\t\t\n") + local tracks = data.tracks + for i=1,#tracks do + local track = tracks[i] + if track then + noftracks = noftracks + 1 + f:write("\t\t\t\t\t",lpegmatch(p_escaped,track.title),"\n") + else + noferrors = noferrors + 1 + flac.report("error in album: %q of %q, no track %s",album,artist,i) + f:write("\t\t\t\t\t\n") + end + end + f:write("\t\t\t\t\n") + f:write("\t\t\t\n") + end + f:write("\t\t\n") + f:write("\t\n") + end + f:write("\n") + f:close() + flac.report("%s tracks of %s albums of %s artists saved in %q (%s errors)",noftracks,nofalbums,nofartists,filename,noferrors) + else + flac.report("unable to save data in file %q",filename) + end +end + +-- + +local helpinfo = [[ + + + + mtx-flac + ConTeXt Flac Helpers + 0.10 + + + + + collect albums in xml file + + + + + + Example + + mtxrun --script flac --collect somename.flac + mtxrun --script flac --collect --pattern="m:/music/**") + + + + +]] + +local application = logs.application { + name = "mtx-flac", + banner = "ConTeXt Flac Helpers 0.10", + helpinfo = helpinfo, +} + +flac.report = application.report + +-- script code + +scripts = scripts or { } +scripts.flac = scripts.flac or { } + +function scripts.flac.collect() + local files = environment.files + local pattern = environment.arguments.pattern + if #files > 0 then + for i=1,#files do + local filename = files[1] + if file.suffix(filename) == "flac" then + flac.savecollection(filename,file.replacesuffix(filename,"xml")) + elseif lfs.isdir(filename) then + local pattern = filename .. "/**.flac" + flac.savecollection(pattern,file.addsuffix(file.basename(filename),"xml")) + else + flac.savecollection(file.replacesuffix(filename,"flac"),file.replacesuffix(filename,"xml")) + end + end + elseif pattern then + flac.savecollection(file.addsuffix(pattern,"flac"),"music-collection.xml") + else + flac.report("no file(s) or pattern given" ) + end +end + +if environment.argument("collect") then + scripts.flac.collect() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index b171dd611..2c28f63d9 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -1,472 +1,472 @@ -if not modules then modules = { } end modules ['mtx-fonts'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local getargument = environment.getargument -local setargument = environment.setargument -local givenfiles = environment.files - -local helpinfo = [[ - - - - mtx-fonts - ConTeXt Font Database Management - 0.21 - - - - - save open type font in raw table - save a tma file in a more readable format - - - generate new font database (use when in doubt) - :generate luatex-fonts-names.lua (not for context!) - - - : list installed fonts, filter by name [] - : list installed fonts, filter by spec [] - : list installed fonts, filter by file [] - - - filter files using pattern - key-value pairs - show all found instances (combined with other flags) - give more details - enable trackers - some info about the database - - - - - - 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" - mtxrun --script font --list --spec --filter="familyname=crap*,weight=bold,style=italic" - - - mtxrun --script font --list --all - mtxrun --script font --list --file somename - mtxrun --script font --list --file --all somename - mtxrun --script font --list --file --pattern=*somename* - - - - -]] - -local application = logs.application { - name = "mtx-fonts", - banner = "ConTeXt Font Database Management 0.21", - helpinfo = helpinfo, -} - -local report = application.report - --- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory - -if not fontloader then fontloader = fontforge end - -dofile(resolvers.findfile("font-otp.lua","tex")) -- we need to unpack the font for analysis -dofile(resolvers.findfile("font-trt.lua","tex")) -dofile(resolvers.findfile("font-syn.lua","tex")) -dofile(resolvers.findfile("font-mis.lua","tex")) - -scripts = scripts or { } -scripts.fonts = scripts.fonts or { } - -function fonts.names.statistics() - fonts.names.load() - - local data = fonts.names.data - local statistics = data.statistics - - local function counted(t) - local n = { } - for k, v in next, t do - n[k] = table.count(v) - end - return table.sequenced(n) - end - - report("cache uuid : %s", data.cache_uuid) - report("cache version : %s", data.cache_version) - report("number of trees : %s", #data.datastate) - report() - report("number of fonts : %s", statistics.fonts or 0) - report("used files : %s", statistics.readfiles or 0) - report("skipped files : %s", statistics.skippedfiles or 0) - report("duplicate files : %s", statistics.duplicatefiles or 0) - report("specifications : %s", #data.specifications) - report("families : %s", table.count(data.families)) - report() - report("mappings : %s", counted(data.mappings)) - report("fallbacks : %s", counted(data.fallbacks)) - report() - report("used styles : %s", table.sequenced(statistics.used_styles)) - report("used variants : %s", table.sequenced(statistics.used_variants)) - report("used weights : %s", table.sequenced(statistics.used_weights)) - report("used widths : %s", table.sequenced(statistics.used_widths)) - report() - report("found styles : %s", table.sequenced(statistics.styles)) - report("found variants : %s", table.sequenced(statistics.variants)) - report("found weights : %s", table.sequenced(statistics.weights)) - report("found widths : %s", table.sequenced(statistics.widths)) - -end - -function fonts.names.simple() - local simpleversion = 1.001 - local simplelist = { "ttf", "otf", "ttc", "dfont" } - local name = "luatex-fonts-names.lua" - local path = file.collapsepath(caches.getwritablepath("..","..","generic","fonts","data")) - fonts.names.filters.list = simplelist - fonts.names.version = simpleversion -- this number is the same as in font-dum.lua - report("generating font database for 'luatex-fonts' version %s",fonts.names.version) - fonts.names.identify(true) - local data = fonts.names.data - if data then - local simplemappings = { } - local simplified = { - mappings = simplemappings, - version = simpleversion, - cache_version = simpleversion, - } - local specifications = data.specifications - for i=1,#simplelist do - local format = simplelist[i] - for tag, index in next, data.mappings[format] do - local s = specifications[index] - simplemappings[tag] = { s.rawname, s.filename, s.subfont } - end - end - if environment.arguments.nocache then - report("not using cache path %a",path) - else - dir.mkdirs(path) - if lfs.isdir(path) then - report("saving names on cache path %a",path) - name = file.join(path,name) - else - report("invalid cache path %a",path) - end - end - report("saving names in %a",name) - io.savedata(name,table.serialize(simplified,true)) - local data = io.loaddata(resolvers.findfile("luatex-fonts-syn.lua","tex")) or "" - local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)") - if tonumber(dummy) ~= simpleversion then - report("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 - -function scripts.fonts.reload() - if getargument("simple") then - fonts.names.simple() - else - fonts.names.load(true,getargument("force")) - end -end - -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 showfeatures(tag,specification) - report() - report("mapping : %s",tag) - report("fontname: %s",specification.fontname) - report("fullname: %s",specification.fullname) - report("filename: %s",specification.filename) - report("family : %s",specification.familyname or "") - report("weight : %s",specification.weight or "") - report("style : %s",specification.style or "") - report("width : %s",specification.width or "") - report("variant : %s",specification.variant or "") - report("subfont : %s",subfont(specification.subfont)) - report("fweight : %s",fontweight(specification.fontweight)) - -- maybe more - local features = fonts.helpers.getfeatures(specification.filename,specification.format) - if features then - for what, v in table.sortedhash(features) do - local data = features[what] - if data and next(data) then - report() - report("%s features:",what) - report() - report("feature script languages") - report() - for f,ff in table.sortedhash(data) do - local done = false - for s, ss in table.sortedhash(ff) do - if s == "*" then s = "all" end - if ss ["*"] then ss["*"] = nil ss.all = true end - if done then - f = "" - else - done = true - end - report("% -8s % -8s % -8s",f,s,table.concat(table.sortedkeys(ss), " ")) -- todo: padd 4 - end - end - end - end - else - report("no features") - end - report() -end - -local function reloadbase(reload) - if reload then - report("fontnames, reloading font database") - names.load(true,getargument("force")) - report("fontnames, done\n\n") - end -end - -local function list_specifications(t,info) - if t then - local s = table.sortedkeys(t) - if info then - for k=1,#s do - local v = s[k] - showfeatures(v,t[v]) - end - else - for k=1,#s do - local v = s[k] - local entry = t[v] - s[k] = { - entry.familyname or "", - entry.weight or "", - entry.style or "", - entry.width or "", - entry.variant or "", - entry.fontname, - entry.filename, - subfont(entry.subfont), - fontweight(entry.fontweight), - } - end - utilities.formatters.formatcolumns(s) - for k=1,#s do - texio.write_nl(s[k]) - end - end - end -end - -local function list_matches(t,info) - if t then - local s, w = table.sortedkeys(t), { 0, 0, 0 } - if info then - for k=1,#s do - local v = s[k] - showfeatures(v,t[v]) - end - else - for k=1,#s do - local v = s[k] - local entry = t[v] - s[k] = { - v, - entry.fontname, - entry.filename, - subfont(entry.subfont) - } - end - utilities.formatters.formatcolumns(s) - for k=1,#s do - texio.write_nl(s[k]) - end - end - end -end - -function scripts.fonts.list() - - local all = getargument("all") - local info = getargument("info") - local reload = getargument("reload") - local pattern = getargument("pattern") - local filter = getargument("filter") - local given = givenfiles[1] - - reloadbase(reload) - - if getargument("name") then - if pattern then - --~ mtxrun --script font --list --name --pattern=*somename* - list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) - elseif filter then - report("not supported: --list --name --filter",name) - elseif given then - --~ mtxrun --script font --list --name somename - list_matches(fonts.names.list(given,reload,all),info) - else - report("not supported: --list --name ",name) - end - elseif getargument("spec") then - if pattern then - --~ mtxrun --script font --list --spec --pattern=*somename* - report("not supported: --list --spec --pattern",name) - elseif filter then - --~ mtxrun --script font --list --spec --filter="fontname=somename" - list_specifications(fonts.names.getlookups(filter),info) - elseif given then - --~ mtxrun --script font --list --spec somename - list_specifications(fonts.names.collectspec(given,reload,all),info) - else - report("not supported: --list --spec ",name) - end - elseif getargument("file") then - if pattern then - --~ mtxrun --script font --list --file --pattern=*somename* - list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all),info) - elseif filter then - report("not supported: --list --spec",name) - elseif given then - --~ mtxrun --script font --list --file somename - list_specifications(fonts.names.collectfiles(given,reload,all),info) - else - report("not supported: --list --file ",name) - end - elseif pattern then - --~ mtxrun --script font --list --pattern=*somename* - list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) - elseif given then - --~ mtxrun --script font --list somename - list_matches(fonts.names.list(given,reload,all),info) - elseif all then - pattern = "*" - list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) - else - report("not supported: --list ",name) - end - -end - -function scripts.fonts.justload() - local fullname = environment.files[1] - if fullname then - local result = fontloader.open(fullname) - if type(result) == "table" then - report("loading %s: %s","succeeded",fullname) - end - end - report("loading %s: %s","failed",fullname) -end - -function scripts.fonts.unpack() - local name = file.removesuffix(file.basename(givenfiles[1] or "")) - if name and name ~= "" then - local cache = containers.define("fonts", "otf", 2.742, true) - local cleanname = containers.cleanname(name) - local data = containers.read(cache,cleanname) - if data then - local savename = file.addsuffix(cleanname .. "-unpacked","tma") - report("fontsave, saving data in %s",savename) - fonts.handlers.otf.enhancers.unpack(data) - io.savedata(savename,table.serialize(data,true)) - else - report("unknown file %a",name) - end - end -end - -function scripts.fonts.save() - local name = givenfiles[1] or "" - local sub = givenfiles[2] or "" - local function save(savename,fontblob) - if fontblob then - savename = file.addsuffix(string.lower(savename),"lua") - report("fontsave, saving data in %s",savename) - table.tofile(savename,fontloader.to_table(fontblob),"return") - fontloader.close(fontblob) - end - end - if name and name ~= "" then - local filename = resolvers.findfile(name) -- maybe also search for opentype - if filename and filename ~= "" then - local suffix = string.lower(file.suffix(filename)) - if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' or suffix == "dfont" then - local fontinfo = fontloader.info(filename) - if fontinfo then - report("font: %s located as %s",name,filename) - if fontinfo[1] then - for k=1,#fontinfo do - local v = fontinfo[k] - save(v.fontname,fontloader.open(filename,v.fullname)) - end - else - save(fontinfo.fullname,fontloader.open(filename)) - end - else - report("font: %s cannot be read",filename) - end - else - report("font: %s not saved",filename) - end - else - report("font: %s not found",name) - end - else - report("font: no name given") - end -end - -if getargument("names") then - setargument("reload",true) - setargument("simple",true) -end - -if getargument("list") then - scripts.fonts.list() -elseif getargument("reload") then - scripts.fonts.reload() -elseif getargument("save") then - scripts.fonts.save() -elseif getargument("justload") then - scripts.fonts.justload() -elseif getargument("unpack") then - scripts.fonts.unpack() -elseif getargument("statistics") then - fonts.names.statistics() -elseif getargument("exporthelp") then - application.export(getargument("exporthelp"),givenfiles[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-fonts'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local getargument = environment.getargument +local setargument = environment.setargument +local givenfiles = environment.files + +local helpinfo = [[ + + + + mtx-fonts + ConTeXt Font Database Management + 0.21 + + + + + save open type font in raw table + save a tma file in a more readable format + + + generate new font database (use when in doubt) + :generate luatex-fonts-names.lua (not for context!) + + + : list installed fonts, filter by name [] + : list installed fonts, filter by spec [] + : list installed fonts, filter by file [] + + + filter files using pattern + key-value pairs + show all found instances (combined with other flags) + give more details + enable trackers + some info about the database + + + + + + 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" + mtxrun --script font --list --spec --filter="familyname=crap*,weight=bold,style=italic" + + + mtxrun --script font --list --all + mtxrun --script font --list --file somename + mtxrun --script font --list --file --all somename + mtxrun --script font --list --file --pattern=*somename* + + + + +]] + +local application = logs.application { + name = "mtx-fonts", + banner = "ConTeXt Font Database Management 0.21", + helpinfo = helpinfo, +} + +local report = application.report + +-- todo: fc-cache -v en check dirs, or better is: fc-cat -v | grep Directory + +if not fontloader then fontloader = fontforge end + +dofile(resolvers.findfile("font-otp.lua","tex")) -- we need to unpack the font for analysis +dofile(resolvers.findfile("font-trt.lua","tex")) +dofile(resolvers.findfile("font-syn.lua","tex")) +dofile(resolvers.findfile("font-mis.lua","tex")) + +scripts = scripts or { } +scripts.fonts = scripts.fonts or { } + +function fonts.names.statistics() + fonts.names.load() + + local data = fonts.names.data + local statistics = data.statistics + + local function counted(t) + local n = { } + for k, v in next, t do + n[k] = table.count(v) + end + return table.sequenced(n) + end + + report("cache uuid : %s", data.cache_uuid) + report("cache version : %s", data.cache_version) + report("number of trees : %s", #data.datastate) + report() + report("number of fonts : %s", statistics.fonts or 0) + report("used files : %s", statistics.readfiles or 0) + report("skipped files : %s", statistics.skippedfiles or 0) + report("duplicate files : %s", statistics.duplicatefiles or 0) + report("specifications : %s", #data.specifications) + report("families : %s", table.count(data.families)) + report() + report("mappings : %s", counted(data.mappings)) + report("fallbacks : %s", counted(data.fallbacks)) + report() + report("used styles : %s", table.sequenced(statistics.used_styles)) + report("used variants : %s", table.sequenced(statistics.used_variants)) + report("used weights : %s", table.sequenced(statistics.used_weights)) + report("used widths : %s", table.sequenced(statistics.used_widths)) + report() + report("found styles : %s", table.sequenced(statistics.styles)) + report("found variants : %s", table.sequenced(statistics.variants)) + report("found weights : %s", table.sequenced(statistics.weights)) + report("found widths : %s", table.sequenced(statistics.widths)) + +end + +function fonts.names.simple() + local simpleversion = 1.001 + local simplelist = { "ttf", "otf", "ttc", "dfont" } + local name = "luatex-fonts-names.lua" + local path = file.collapsepath(caches.getwritablepath("..","..","generic","fonts","data")) + fonts.names.filters.list = simplelist + fonts.names.version = simpleversion -- this number is the same as in font-dum.lua + report("generating font database for 'luatex-fonts' version %s",fonts.names.version) + fonts.names.identify(true) + local data = fonts.names.data + if data then + local simplemappings = { } + local simplified = { + mappings = simplemappings, + version = simpleversion, + cache_version = simpleversion, + } + local specifications = data.specifications + for i=1,#simplelist do + local format = simplelist[i] + for tag, index in next, data.mappings[format] do + local s = specifications[index] + simplemappings[tag] = { s.rawname, s.filename, s.subfont } + end + end + if environment.arguments.nocache then + report("not using cache path %a",path) + else + dir.mkdirs(path) + if lfs.isdir(path) then + report("saving names on cache path %a",path) + name = file.join(path,name) + else + report("invalid cache path %a",path) + end + end + report("saving names in %a",name) + io.savedata(name,table.serialize(simplified,true)) + local data = io.loaddata(resolvers.findfile("luatex-fonts-syn.lua","tex")) or "" + local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)") + if tonumber(dummy) ~= simpleversion then + report("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 + +function scripts.fonts.reload() + if getargument("simple") then + fonts.names.simple() + else + fonts.names.load(true,getargument("force")) + end +end + +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 showfeatures(tag,specification) + report() + report("mapping : %s",tag) + report("fontname: %s",specification.fontname) + report("fullname: %s",specification.fullname) + report("filename: %s",specification.filename) + report("family : %s",specification.familyname or "") + report("weight : %s",specification.weight or "") + report("style : %s",specification.style or "") + report("width : %s",specification.width or "") + report("variant : %s",specification.variant or "") + report("subfont : %s",subfont(specification.subfont)) + report("fweight : %s",fontweight(specification.fontweight)) + -- maybe more + local features = fonts.helpers.getfeatures(specification.filename,specification.format) + if features then + for what, v in table.sortedhash(features) do + local data = features[what] + if data and next(data) then + report() + report("%s features:",what) + report() + report("feature script languages") + report() + for f,ff in table.sortedhash(data) do + local done = false + for s, ss in table.sortedhash(ff) do + if s == "*" then s = "all" end + if ss ["*"] then ss["*"] = nil ss.all = true end + if done then + f = "" + else + done = true + end + report("% -8s % -8s % -8s",f,s,table.concat(table.sortedkeys(ss), " ")) -- todo: padd 4 + end + end + end + end + else + report("no features") + end + report() +end + +local function reloadbase(reload) + if reload then + report("fontnames, reloading font database") + names.load(true,getargument("force")) + report("fontnames, done\n\n") + end +end + +local function list_specifications(t,info) + if t then + local s = table.sortedkeys(t) + if info then + for k=1,#s do + local v = s[k] + showfeatures(v,t[v]) + end + else + for k=1,#s do + local v = s[k] + local entry = t[v] + s[k] = { + entry.familyname or "", + entry.weight or "", + entry.style or "", + entry.width or "", + entry.variant or "", + entry.fontname, + entry.filename, + subfont(entry.subfont), + fontweight(entry.fontweight), + } + end + utilities.formatters.formatcolumns(s) + for k=1,#s do + texio.write_nl(s[k]) + end + end + end +end + +local function list_matches(t,info) + if t then + local s, w = table.sortedkeys(t), { 0, 0, 0 } + if info then + for k=1,#s do + local v = s[k] + showfeatures(v,t[v]) + end + else + for k=1,#s do + local v = s[k] + local entry = t[v] + s[k] = { + v, + entry.fontname, + entry.filename, + subfont(entry.subfont) + } + end + utilities.formatters.formatcolumns(s) + for k=1,#s do + texio.write_nl(s[k]) + end + end + end +end + +function scripts.fonts.list() + + local all = getargument("all") + local info = getargument("info") + local reload = getargument("reload") + local pattern = getargument("pattern") + local filter = getargument("filter") + local given = givenfiles[1] + + reloadbase(reload) + + if getargument("name") then + if pattern then + --~ mtxrun --script font --list --name --pattern=*somename* + list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) + elseif filter then + report("not supported: --list --name --filter",name) + elseif given then + --~ mtxrun --script font --list --name somename + list_matches(fonts.names.list(given,reload,all),info) + else + report("not supported: --list --name ",name) + end + elseif getargument("spec") then + if pattern then + --~ mtxrun --script font --list --spec --pattern=*somename* + report("not supported: --list --spec --pattern",name) + elseif filter then + --~ mtxrun --script font --list --spec --filter="fontname=somename" + list_specifications(fonts.names.getlookups(filter),info) + elseif given then + --~ mtxrun --script font --list --spec somename + list_specifications(fonts.names.collectspec(given,reload,all),info) + else + report("not supported: --list --spec ",name) + end + elseif getargument("file") then + if pattern then + --~ mtxrun --script font --list --file --pattern=*somename* + list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all),info) + elseif filter then + report("not supported: --list --spec",name) + elseif given then + --~ mtxrun --script font --list --file somename + list_specifications(fonts.names.collectfiles(given,reload,all),info) + else + report("not supported: --list --file ",name) + end + elseif pattern then + --~ mtxrun --script font --list --pattern=*somename* + list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) + elseif given then + --~ mtxrun --script font --list somename + list_matches(fonts.names.list(given,reload,all),info) + elseif all then + pattern = "*" + list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info) + else + report("not supported: --list ",name) + end + +end + +function scripts.fonts.justload() + local fullname = environment.files[1] + if fullname then + local result = fontloader.open(fullname) + if type(result) == "table" then + report("loading %s: %s","succeeded",fullname) + end + end + report("loading %s: %s","failed",fullname) +end + +function scripts.fonts.unpack() + local name = file.removesuffix(file.basename(givenfiles[1] or "")) + if name and name ~= "" then + local cache = containers.define("fonts", "otf", 2.742, true) + local cleanname = containers.cleanname(name) + local data = containers.read(cache,cleanname) + if data then + local savename = file.addsuffix(cleanname .. "-unpacked","tma") + report("fontsave, saving data in %s",savename) + fonts.handlers.otf.enhancers.unpack(data) + io.savedata(savename,table.serialize(data,true)) + else + report("unknown file %a",name) + end + end +end + +function scripts.fonts.save() + local name = givenfiles[1] or "" + local sub = givenfiles[2] or "" + local function save(savename,fontblob) + if fontblob then + savename = file.addsuffix(string.lower(savename),"lua") + report("fontsave, saving data in %s",savename) + table.tofile(savename,fontloader.to_table(fontblob),"return") + fontloader.close(fontblob) + end + end + if name and name ~= "" then + local filename = resolvers.findfile(name) -- maybe also search for opentype + if filename and filename ~= "" then + local suffix = string.lower(file.suffix(filename)) + if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' or suffix == "dfont" then + local fontinfo = fontloader.info(filename) + if fontinfo then + report("font: %s located as %s",name,filename) + if fontinfo[1] then + for k=1,#fontinfo do + local v = fontinfo[k] + save(v.fontname,fontloader.open(filename,v.fullname)) + end + else + save(fontinfo.fullname,fontloader.open(filename)) + end + else + report("font: %s cannot be read",filename) + end + else + report("font: %s not saved",filename) + end + else + report("font: %s not found",name) + end + else + report("font: no name given") + end +end + +if getargument("names") then + setargument("reload",true) + setargument("simple",true) +end + +if getargument("list") then + scripts.fonts.list() +elseif getargument("reload") then + scripts.fonts.reload() +elseif getargument("save") then + scripts.fonts.save() +elseif getargument("justload") then + scripts.fonts.justload() +elseif getargument("unpack") then + scripts.fonts.unpack() +elseif getargument("statistics") then + fonts.names.statistics() +elseif getargument("exporthelp") then + application.export(getargument("exporthelp"),givenfiles[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-grep.lua b/scripts/context/lua/mtx-grep.lua index dbcce67f6..cd4856040 100644 --- a/scripts/context/lua/mtx-grep.lua +++ b/scripts/context/lua/mtx-grep.lua @@ -1,170 +1,170 @@ -if not modules then modules = { } end modules ['mtx-babel'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-grep - Simple Grepper - 0.10 - - - - - search for pattern (optional) - count matches only - skip lines that start with %% or # - pattern is lpath expression - - - - - patterns are lua patterns and need to be escaped accordingly - - -]] - -local application = logs.application { - name = "mtx-grep", - banner = "Simple Grepper 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.grep = scripts.grep or { } - -local find, format = string.find, string.format - -local cr = lpeg.P("\r") -local lf = lpeg.P("\n") -local crlf = cr * lf -local newline = crlf + cr + lf -local content = lpeg.C((1-newline)^0) * newline + lpeg.C(lpeg.P(1)^1) - -local write_nl = texio.write_nl - - -- local pattern = "LIJST[@TYPE='BULLET']/LIJSTITEM[contains(text(),'Kern')]" - -function scripts.grep.find(pattern, files, offset) - if pattern and pattern ~= "" then - statistics.starttiming(scripts.grep) - local nofmatches, noffiles, nofmatchedfiles = 0, 0, 0 - local n, m, name, check = 0, 0, "", nil - local count, nocomment = environment.argument("count"), environment.argument("nocomment") - if environment.argument("xml") then - for i=offset or 1, #files do - local globbed = dir.glob(files[i]) - for i=1,#globbed do - local nam = globbed[i] - name = nam - local data = xml.load(name) - if data and not data.error then - n, m, noffiles = 0, 0, noffiles + 1 - if count then - for c in xml.collected(data,pattern) do - m = m + 1 - end - if m > 0 then - nofmatches = nofmatches + m - nofmatchedfiles = nofmatchedfiles + 1 - write_nl(format("%5i %s",m,name)) - io.flush() - end - else - for c in xml.collected(data,pattern) do - m = m + 1 - write_nl(format("%s: %s",name,xml.tostring(c))) - end - end - end - end - end - else - if nocomment then - if count then - check = function(line) - n = n + 1 - if find(line,"^[%%#]") then - -- skip - elseif find(line,pattern) then - m = m + 1 - end - end - else - check = function(line) - n = n + 1 - if find(line,"^[%%#]") then - -- skip - elseif find(line,pattern) then - m = m + 1 - write_nl(format("%s %6i: %s",name,n,line)) - io.flush() - end - end - end - else - if count then - check = function(line) - n = n + 1 - if find(line,pattern) then - m = m + 1 - end - end - else - check = function(line) - n = n + 1 - if find(line,pattern) then - m = m + 1 - write_nl(format("%s %6i: %s",name,n,line)) - io.flush() - end - end - end - end - local capture = (content/check)^0 - for i=offset or 1, #files do - local globbed = dir.glob(files[i]) - for i=1,#globbed do - local nam = globbed[i] - name = nam - local data = io.loaddata(name) - if data then - n, m, noffiles = 0, 0, noffiles + 1 - capture:match(data) - if count and m > 0 then - nofmatches = nofmatches + m - nofmatchedfiles = nofmatchedfiles + 1 - write_nl(format("%5i %s",m,name)) - io.flush() - end - end - end - end - end - statistics.stoptiming(scripts.grep) - if count and nofmatches > 0 then - write_nl(format("\nfiles: %s, matches: %s, matched files: %s, runtime: %0.3f seconds",noffiles,nofmatches,nofmatchedfiles,statistics.elapsedtime(scripts.grep))) - end - end -end - -local pattern = environment.argument("pattern") -local files = environment.files and #environment.files > 0 and environment.files - -if environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),files[1]) -elseif pattern and files then - scripts.grep.find(pattern, files) -elseif files then - scripts.grep.find(files[1], files, 2) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-babel'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-grep + Simple Grepper + 0.10 + + + + + search for pattern (optional) + count matches only + skip lines that start with %% or # + pattern is lpath expression + + + + + patterns are lua patterns and need to be escaped accordingly + + +]] + +local application = logs.application { + name = "mtx-grep", + banner = "Simple Grepper 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.grep = scripts.grep or { } + +local find, format = string.find, string.format + +local cr = lpeg.P("\r") +local lf = lpeg.P("\n") +local crlf = cr * lf +local newline = crlf + cr + lf +local content = lpeg.C((1-newline)^0) * newline + lpeg.C(lpeg.P(1)^1) + +local write_nl = texio.write_nl + + -- local pattern = "LIJST[@TYPE='BULLET']/LIJSTITEM[contains(text(),'Kern')]" + +function scripts.grep.find(pattern, files, offset) + if pattern and pattern ~= "" then + statistics.starttiming(scripts.grep) + local nofmatches, noffiles, nofmatchedfiles = 0, 0, 0 + local n, m, name, check = 0, 0, "", nil + local count, nocomment = environment.argument("count"), environment.argument("nocomment") + if environment.argument("xml") then + for i=offset or 1, #files do + local globbed = dir.glob(files[i]) + for i=1,#globbed do + local nam = globbed[i] + name = nam + local data = xml.load(name) + if data and not data.error then + n, m, noffiles = 0, 0, noffiles + 1 + if count then + for c in xml.collected(data,pattern) do + m = m + 1 + end + if m > 0 then + nofmatches = nofmatches + m + nofmatchedfiles = nofmatchedfiles + 1 + write_nl(format("%5i %s",m,name)) + io.flush() + end + else + for c in xml.collected(data,pattern) do + m = m + 1 + write_nl(format("%s: %s",name,xml.tostring(c))) + end + end + end + end + end + else + if nocomment then + if count then + check = function(line) + n = n + 1 + if find(line,"^[%%#]") then + -- skip + elseif find(line,pattern) then + m = m + 1 + end + end + else + check = function(line) + n = n + 1 + if find(line,"^[%%#]") then + -- skip + elseif find(line,pattern) then + m = m + 1 + write_nl(format("%s %6i: %s",name,n,line)) + io.flush() + end + end + end + else + if count then + check = function(line) + n = n + 1 + if find(line,pattern) then + m = m + 1 + end + end + else + check = function(line) + n = n + 1 + if find(line,pattern) then + m = m + 1 + write_nl(format("%s %6i: %s",name,n,line)) + io.flush() + end + end + end + end + local capture = (content/check)^0 + for i=offset or 1, #files do + local globbed = dir.glob(files[i]) + for i=1,#globbed do + local nam = globbed[i] + name = nam + local data = io.loaddata(name) + if data then + n, m, noffiles = 0, 0, noffiles + 1 + capture:match(data) + if count and m > 0 then + nofmatches = nofmatches + m + nofmatchedfiles = nofmatchedfiles + 1 + write_nl(format("%5i %s",m,name)) + io.flush() + end + end + end + end + end + statistics.stoptiming(scripts.grep) + if count and nofmatches > 0 then + write_nl(format("\nfiles: %s, matches: %s, matched files: %s, runtime: %0.3f seconds",noffiles,nofmatches,nofmatchedfiles,statistics.elapsedtime(scripts.grep))) + end + end +end + +local pattern = environment.argument("pattern") +local files = environment.files and #environment.files > 0 and environment.files + +if environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),files[1]) +elseif pattern and files then + scripts.grep.find(pattern, files) +elseif files then + scripts.grep.find(files[1], files, 2) +else + application.help() +end diff --git a/scripts/context/lua/mtx-metatex.lua b/scripts/context/lua/mtx-metatex.lua index 455ecbd52..ff13d00e3 100644 --- a/scripts/context/lua/mtx-metatex.lua +++ b/scripts/context/lua/mtx-metatex.lua @@ -1,80 +1,80 @@ -if not modules then modules = { } end modules ['mtx-metatex'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- future versions will deal with specific variants of metatex - -local helpinfo = [[ - - - - mtx-metatex - MetaTeX Process Management - 0.10 - - - - - process (one or more) files (default action) - create metatex format(s) - - - - -]] - -local application = logs.application { - name = "mtx-metatex", - banner = "MetaTeX Process Management 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.metatex = scripts.metatex or { } - --- metatex - -function scripts.metatex.make() - environment.make_format("metatex") -end - -function scripts.metatex.run(ctxdata,filename) - local filename = environment.files[1] or "" - if filename ~= "" then - local formatfile, scriptfile = resolvers.locateformat("metatex") - if formatfile and scriptfile then - local command = string.format("luatex --fmt=%s --lua=%s %s", - string.quote(formatfile), string.quote(scriptfile), string.quote(filename)) - report("running command: %s",command) - os.spawn(command) - elseif formatname then - report("error, no format found with name: %s",formatname) - else - report("error, no format found (provide formatname or interface)") - end - end -end - -function scripts.metatex.timed(action) - statistics.timed(action) -end - -if environment.argument("run") then - scripts.metatex.timed(scripts.metatex.run) -elseif environment.argument("make") then - scripts.metatex.timed(scripts.metatex.make) -elseif environment.argument("help") then - logs.help(messages.help,false) -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -elseif environment.files[1] then - scripts.metatex.timed(scripts.metatex.run) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-metatex'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- future versions will deal with specific variants of metatex + +local helpinfo = [[ + + + + mtx-metatex + MetaTeX Process Management + 0.10 + + + + + process (one or more) files (default action) + create metatex format(s) + + + + +]] + +local application = logs.application { + name = "mtx-metatex", + banner = "MetaTeX Process Management 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.metatex = scripts.metatex or { } + +-- metatex + +function scripts.metatex.make() + environment.make_format("metatex") +end + +function scripts.metatex.run(ctxdata,filename) + local filename = environment.files[1] or "" + if filename ~= "" then + local formatfile, scriptfile = resolvers.locateformat("metatex") + if formatfile and scriptfile then + local command = string.format("luatex --fmt=%s --lua=%s %s", + string.quote(formatfile), string.quote(scriptfile), string.quote(filename)) + report("running command: %s",command) + os.spawn(command) + elseif formatname then + report("error, no format found with name: %s",formatname) + else + report("error, no format found (provide formatname or interface)") + end + end +end + +function scripts.metatex.timed(action) + statistics.timed(action) +end + +if environment.argument("run") then + scripts.metatex.timed(scripts.metatex.run) +elseif environment.argument("make") then + scripts.metatex.timed(scripts.metatex.make) +elseif environment.argument("help") then + logs.help(messages.help,false) +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +elseif environment.files[1] then + scripts.metatex.timed(scripts.metatex.run) +else + application.help() +end diff --git a/scripts/context/lua/mtx-mk-help.lua b/scripts/context/lua/mtx-mk-help.lua index 794bbca37..68ad16f93 100644 --- a/scripts/context/lua/mtx-mk-help.lua +++ b/scripts/context/lua/mtx-mk-help.lua @@ -1,473 +1,473 @@ -if not modules then modules = { } end modules ['mtx-mk-help'] = { - version = 1.001, - comment = "a script for making help files", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - ---[[ - -mtxrun --exporthelp=all %targetpath%\mkiv\mtxrun.tmp -context --exporthelp=all %targetpath%\mkiv\context.tmp -mtxrun --script context --exporthelp=all %targetpath%\mkiv\mtx-context.tmp - -mtxrun --script babel --exporthelp=all %targetpath%\mkiv\mtx-babel.tmp -mtxrun --script base --exporthelp=all %targetpath%\mkiv\mtx-base.tmp -mtxrun --script cache --exporthelp=all %targetpath%\mkiv\mtx-cache.tmp -mtxrun --script chars --exporthelp=all %targetpath%\mkiv\mtx-chars.tmp -mtxrun --script check --exporthelp=all %targetpath%\mkiv\mtx-check.tmp -mtxrun --script colors --exporthelp=all %targetpath%\mkiv\mtx-colors.tmp -mtxrun --script convert --exporthelp=all %targetpath%\mkiv\mtx-convert.tmp -mtxrun --script epub --exporthelp=all %targetpath%\mkiv\mtx-epub.tmp -mtxrun --script fcd --exporthelp=all %targetpath%\mkiv\mtx-fcd.tmp -mtxrun --script flac --exporthelp=all %targetpath%\mkiv\mtx-flac.tmp -mtxrun --script fonts --exporthelp=all %targetpath%\mkiv\mtx-fonts.tmp -mtxrun --script grep --exporthelp=all %targetpath%\mkiv\mtx-grep.tmp -mtxrun --script interface --exporthelp=all %targetpath%\mkiv\mtx-interface.tmp -mtxrun --script metapost --exporthelp=all %targetpath%\mkiv\mtx-metapost.tmp -mtxrun --script metatex --exporthelp=all %targetpath%\mkiv\mtx-metatex.tmp -mtxrun --script modules --exporthelp=all %targetpath%\mkiv\mtx-modules.tmp -mtxrun --script mtxworks --exporthelp=all %targetpath%\mkiv\mtx-mtxworks.tmp -mtxrun --script package --exporthelp=all %targetpath%\mkiv\mtx-package.tmp -mtxrun --script patterns --exporthelp=all %targetpath%\mkiv\mtx-patterns.tmp -mtxrun --script pdf --exporthelp=all %targetpath%\mkiv\mtx-pdf.tmp -mtxrun --script profile --exporthelp=all %targetpath%\mkiv\mtx-profile.tmp -mtxrun --script rsync --exporthelp=all %targetpath%\mkiv\mtx-rsync.tmp -mtxrun --script scite --exporthelp=all %targetpath%\mkiv\mtx-scite.tmp -mtxrun --script server --exporthelp=all %targetpath%\mkiv\mtx-server.tmp -mtxrun --script texworks --exporthelp=all %targetpath%\mkiv\mtx-texworks.tmp -mtxrun --script timing --exporthelp=all %targetpath%\mkiv\mtx-timing.tmp -mtxrun --script tools --exporthelp=all %targetpath%\mkiv\mtx-tools.tmp -mtxrun --script unzip --exporthelp=all %targetpath%\mkiv\mtx-unzip.tmp -mtxrun --script update --exporthelp=all %targetpath%\mkiv\mtx-update.tmp -mtxrun --script watch --exporthelp=all %targetpath%\mkiv\mtx-watch.tmp - -mtxrun --script mk-help luatools --exporthelp=all %targetpath%\mkiv\luatools.tmp - -mtxrun --script mk-help texmfstart --exporthelp=all %targetpath%\mkii\texmfstart.tmp -mtxrun --script mk-help texexec --exporthelp=all %targetpath%\mkii\texexec.tmp -mtxrun --script mk-help texutil --exporthelp=all %targetpath%\mkii\texutil.tmp -mtxrun --script mk-help ctxtools --exporthelp=all %targetpath%\mkii\ctxtools.tmp -mtxrun --script mk-help textools --exporthelp=all %targetpath%\mkii\textools.tmp -mtxrun --script mk-help pdftools --exporthelp=all %targetpath%\mkii\pdftools.tmp -mtxrun --script mk-help tmftools --exporthelp=all %targetpath%\mkii\tmftools.tmp -mtxrun --script mk-help xmltools --exporthelp=all %targetpath%\mkii\xmltools.tmp -mtxrun --script mk-help pstopdf --exporthelp=all %targetpath%\mkii\pstopdf.tmp -mtxrun --script mk-help rlxtools --exporthelp=all %targetpath%\mkii\rlxtools.tmp -mtxrun --script mk-help imgtopdf --exporthelp=all %targetpath%\mkii\imgtopdf.tmp - -]]-- - -local helpinfo = os.resultof("mtxrun --exporthelp") or "" -local helpinfo = string.match(helpinfo,[[^.-(.-)]]) or [[]] - -local texmfstart = logs.application { - name = "texmfstart", - banner = "texmfstart 7.0.0", - helpinfo = [[]] .. helpinfo, -} - --- let's also put luatools here: - -local helpinfo = os.resultof("luatools --exporthelp") or "" -local helpinfo = string.match(helpinfo,[[^.-(.-)]]) or [[]] -local helpinfo = string.gsub(helpinfo,"mtx%-base","luatools") - -local luatools = logs.application { - name = "luatools", - banner = "luatools 1.35", - helpinfo = [[]] .. helpinfo, -} - --- - -local helpinfo = [[ - - - - texexec - TeXExec - 6.2.1 - - - - - make formats - check versions - process file - process mp file - process mpx file - process mp file to stand-alone graphics - process mp/ctx file to stand-alone graphics - list of file content - generate overview of figures - generate module documentation - impose pages (booklets) - select pages from file(s) - copy pages from file(s) - trim pages from file(s) - combine multiple pages - split file in pages - - - - -]] - -local texexec = logs.application { - name = "texexec", - banner = "TeXExec 6.2.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - texutil - TeXUtil - 9.1.0 - - - - - convert tui file into tuo file - generate figure dimensions file - filter essential log messages - remove most temporary files - remove all temporary files - generate documentation file from source - analyze pdf file - - - -]] - -local texutil = logs.application { - name = "texutil", - banner = "TeXUtil 9.1.0", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - ctxtools - CtxTools - 1.3.5 - - - - - update context version - report context version - generate jedit syntax files [ - generate bbedit syntax files [ - generate scite syntax files [ - generate raw syntax files [ - generate interface files (xml) [nl de ..] - remove temporary files [ [basename] - [filename] - ) # no help, hidden temporary feature - convert pdftex mapfiles to dvipdfmx [ [texmfroot] - create doctype entity definition from enco-uc.tex - add context copyright notice [ - replace line-endings [ [pattern] - [filename] - download latest version and remake formats [ - remove utf bom [ - - - - -]] - -local ctxtools = logs.application { - name = "ctxtools", - banner = "CtxTools 1.3.5", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - textools - TeXTools - 1.3.1 - - - - - [pattern] [ - [pattern] [ - [pattern] [ - [pattern] [ - filename [ - [pattern] [ - [pattern] [ - [pattern] [ - [texmfroot] [ - filename [ - fromroot toroot [ - [ [ - [ [ - filename - afmfile encodingname - tpm file (run in texmf root) - - - - -]] - -local textools = logs.application { - name = "textools", - banner = "TeXTools 1.3.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - pdftools - PDFTools - 1.2.1 - - - - - [ - [ ] - filename [ - filename [ - filename - [ - [ - filename - - - - -]] - -local pdftools = logs.application { - name = "pdftools", - banner = "PDFTools 1.2.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - tmftools - TMFTools - 1.1.0 - - - - - [ ] [pattern] - - - act as kpse server - - - - -]] - -local tmftools = logs.application { - name = "tmftools", - banner = "TMFTools 1.2.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - xmltools - XMLTools - 1.2.2 - - - - - generate directory listing - generate graphic from mathml - report entities and elements [ ] - cleanup xml file [] - enhance xml file (partial) - filter elements from xml file [] - generate ddirectory listing - - - - -]] - -local xmltools = logs.application { - name = "xmltools", - banner = "XMLTools 1.2.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - pstopdf - PStoPDF - 2.0.1 - - - - - handles exa request file - watch folders for conversions (untested) - - - - -]] - -local pstopdf = logs.application { - name = "pstopdf", - banner = "PStoPDF 2.0.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - rlxtools - RlxTools - 1.0.1 - - - - - [ manipulatorfile resourselog - [ filename - - - - -]] - -local rlxtools = logs.application { - name = "rlxtools", - banner = "RlxTools 1.0.1", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - imgtopdf - ImgToPdf - 1.1.2 - - - - - convert image into pdf - level of compression in percent - image depth in bits - colorspace (rgb,cmyk,gray) - quality in percent - path where files are looked for - path where files end up - determine settings automatically - - - - -]] - -local imgtopdf = logs.application { - name = "imgtopdf", - banner = "ImgToPdf 1.1.2", - helpinfo = helpinfo, -} - -local helpinfo = [[ - - - - mptopdf - convert MetaPost to PDF - 1.4.1 - - - - - use the metafun format to process the file (default is mpost) - use texexec (context) to process text snippets - use latex to process text snippets - - - - -]] - -local mptopdf = logs.application { - name = "mptopdf", - banner = "MPtoPDF 1.4.1", - helpinfo = helpinfo, -} - --- texmfstart.rb is normally replaced by mtxrun --- runtools.rb is run from within context --- concheck.rb is run from within editors --- texsync.rb is no longer in the zip --- mpstools.rb is no longer in the zip --- rscortool.rb is only run indirectly --- rsfiltool.rb is only run indirectly --- rslibtool.rb is only run indirectly - -local application = logs.application { - name = "mk-help", - banner = "Mk Help generator 1.00", -} - -local filename = environment.files[1] - -if not filename then - application.report("no mk script given") - return -end - -local mkapplication - -if filename == "texmfstart" then mkapplication = texmfstart -elseif filename == "luatools" then mkapplication = luatools -elseif filename == "texexec" then mkapplication = texexec -elseif filename == "texutil" then mkapplication = texutil -elseif filename == "ctxtools" then mkapplication = ctxtools -elseif filename == "textools" then mkapplication = textools -elseif filename == "pdftools" then mkapplication = pdftools -elseif filename == "tmftools" then mkapplication = tmftools -elseif filename == "xmltools" then mkapplication = xmltools -elseif filename == "pstopdf" then mkapplication = pstopdf -elseif filename == "rlxtools" then mkapplication = rlxtools -elseif filename == "imgtopdf" then mkapplication = imgtopdf -elseif filename == "mptopdf" then mkapplication = mptopdf end - -if not mkapplication then - application.report("no valid mk script given") - return -end - -if environment.argument("exporthelp") then - mkapplication.export(environment.argument("exporthelp"),environment.files[2]) -else - mkapplication.help() -end +if not modules then modules = { } end modules ['mtx-mk-help'] = { + version = 1.001, + comment = "a script for making help files", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +--[[ + +mtxrun --exporthelp=all %targetpath%\mkiv\mtxrun.tmp +context --exporthelp=all %targetpath%\mkiv\context.tmp +mtxrun --script context --exporthelp=all %targetpath%\mkiv\mtx-context.tmp + +mtxrun --script babel --exporthelp=all %targetpath%\mkiv\mtx-babel.tmp +mtxrun --script base --exporthelp=all %targetpath%\mkiv\mtx-base.tmp +mtxrun --script cache --exporthelp=all %targetpath%\mkiv\mtx-cache.tmp +mtxrun --script chars --exporthelp=all %targetpath%\mkiv\mtx-chars.tmp +mtxrun --script check --exporthelp=all %targetpath%\mkiv\mtx-check.tmp +mtxrun --script colors --exporthelp=all %targetpath%\mkiv\mtx-colors.tmp +mtxrun --script convert --exporthelp=all %targetpath%\mkiv\mtx-convert.tmp +mtxrun --script epub --exporthelp=all %targetpath%\mkiv\mtx-epub.tmp +mtxrun --script fcd --exporthelp=all %targetpath%\mkiv\mtx-fcd.tmp +mtxrun --script flac --exporthelp=all %targetpath%\mkiv\mtx-flac.tmp +mtxrun --script fonts --exporthelp=all %targetpath%\mkiv\mtx-fonts.tmp +mtxrun --script grep --exporthelp=all %targetpath%\mkiv\mtx-grep.tmp +mtxrun --script interface --exporthelp=all %targetpath%\mkiv\mtx-interface.tmp +mtxrun --script metapost --exporthelp=all %targetpath%\mkiv\mtx-metapost.tmp +mtxrun --script metatex --exporthelp=all %targetpath%\mkiv\mtx-metatex.tmp +mtxrun --script modules --exporthelp=all %targetpath%\mkiv\mtx-modules.tmp +mtxrun --script mtxworks --exporthelp=all %targetpath%\mkiv\mtx-mtxworks.tmp +mtxrun --script package --exporthelp=all %targetpath%\mkiv\mtx-package.tmp +mtxrun --script patterns --exporthelp=all %targetpath%\mkiv\mtx-patterns.tmp +mtxrun --script pdf --exporthelp=all %targetpath%\mkiv\mtx-pdf.tmp +mtxrun --script profile --exporthelp=all %targetpath%\mkiv\mtx-profile.tmp +mtxrun --script rsync --exporthelp=all %targetpath%\mkiv\mtx-rsync.tmp +mtxrun --script scite --exporthelp=all %targetpath%\mkiv\mtx-scite.tmp +mtxrun --script server --exporthelp=all %targetpath%\mkiv\mtx-server.tmp +mtxrun --script texworks --exporthelp=all %targetpath%\mkiv\mtx-texworks.tmp +mtxrun --script timing --exporthelp=all %targetpath%\mkiv\mtx-timing.tmp +mtxrun --script tools --exporthelp=all %targetpath%\mkiv\mtx-tools.tmp +mtxrun --script unzip --exporthelp=all %targetpath%\mkiv\mtx-unzip.tmp +mtxrun --script update --exporthelp=all %targetpath%\mkiv\mtx-update.tmp +mtxrun --script watch --exporthelp=all %targetpath%\mkiv\mtx-watch.tmp + +mtxrun --script mk-help luatools --exporthelp=all %targetpath%\mkiv\luatools.tmp + +mtxrun --script mk-help texmfstart --exporthelp=all %targetpath%\mkii\texmfstart.tmp +mtxrun --script mk-help texexec --exporthelp=all %targetpath%\mkii\texexec.tmp +mtxrun --script mk-help texutil --exporthelp=all %targetpath%\mkii\texutil.tmp +mtxrun --script mk-help ctxtools --exporthelp=all %targetpath%\mkii\ctxtools.tmp +mtxrun --script mk-help textools --exporthelp=all %targetpath%\mkii\textools.tmp +mtxrun --script mk-help pdftools --exporthelp=all %targetpath%\mkii\pdftools.tmp +mtxrun --script mk-help tmftools --exporthelp=all %targetpath%\mkii\tmftools.tmp +mtxrun --script mk-help xmltools --exporthelp=all %targetpath%\mkii\xmltools.tmp +mtxrun --script mk-help pstopdf --exporthelp=all %targetpath%\mkii\pstopdf.tmp +mtxrun --script mk-help rlxtools --exporthelp=all %targetpath%\mkii\rlxtools.tmp +mtxrun --script mk-help imgtopdf --exporthelp=all %targetpath%\mkii\imgtopdf.tmp + +]]-- + +local helpinfo = os.resultof("mtxrun --exporthelp") or "" +local helpinfo = string.match(helpinfo,[[^.-(.-)]]) or [[]] + +local texmfstart = logs.application { + name = "texmfstart", + banner = "texmfstart 7.0.0", + helpinfo = [[]] .. helpinfo, +} + +-- let's also put luatools here: + +local helpinfo = os.resultof("luatools --exporthelp") or "" +local helpinfo = string.match(helpinfo,[[^.-(.-)]]) or [[]] +local helpinfo = string.gsub(helpinfo,"mtx%-base","luatools") + +local luatools = logs.application { + name = "luatools", + banner = "luatools 1.35", + helpinfo = [[]] .. helpinfo, +} + +-- + +local helpinfo = [[ + + + + texexec + TeXExec + 6.2.1 + + + + + make formats + check versions + process file + process mp file + process mpx file + process mp file to stand-alone graphics + process mp/ctx file to stand-alone graphics + list of file content + generate overview of figures + generate module documentation + impose pages (booklets) + select pages from file(s) + copy pages from file(s) + trim pages from file(s) + combine multiple pages + split file in pages + + + + +]] + +local texexec = logs.application { + name = "texexec", + banner = "TeXExec 6.2.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + texutil + TeXUtil + 9.1.0 + + + + + convert tui file into tuo file + generate figure dimensions file + filter essential log messages + remove most temporary files + remove all temporary files + generate documentation file from source + analyze pdf file + + + +]] + +local texutil = logs.application { + name = "texutil", + banner = "TeXUtil 9.1.0", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + ctxtools + CtxTools + 1.3.5 + + + + + update context version + report context version + generate jedit syntax files [ + generate bbedit syntax files [ + generate scite syntax files [ + generate raw syntax files [ + generate interface files (xml) [nl de ..] + remove temporary files [ [basename] + [filename] + ) # no help, hidden temporary feature + convert pdftex mapfiles to dvipdfmx [ [texmfroot] + create doctype entity definition from enco-uc.tex + add context copyright notice [ + replace line-endings [ [pattern] + [filename] + download latest version and remake formats [ + remove utf bom [ + + + + +]] + +local ctxtools = logs.application { + name = "ctxtools", + banner = "CtxTools 1.3.5", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + textools + TeXTools + 1.3.1 + + + + + [pattern] [ + [pattern] [ + [pattern] [ + [pattern] [ + filename [ + [pattern] [ + [pattern] [ + [pattern] [ + [texmfroot] [ + filename [ + fromroot toroot [ + [ [ + [ [ + filename + afmfile encodingname + tpm file (run in texmf root) + + + + +]] + +local textools = logs.application { + name = "textools", + banner = "TeXTools 1.3.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + pdftools + PDFTools + 1.2.1 + + + + + [ + [ ] + filename [ + filename [ + filename + [ + [ + filename + + + + +]] + +local pdftools = logs.application { + name = "pdftools", + banner = "PDFTools 1.2.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + tmftools + TMFTools + 1.1.0 + + + + + [ ] [pattern] + + + act as kpse server + + + + +]] + +local tmftools = logs.application { + name = "tmftools", + banner = "TMFTools 1.2.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + xmltools + XMLTools + 1.2.2 + + + + + generate directory listing + generate graphic from mathml + report entities and elements [ ] + cleanup xml file [] + enhance xml file (partial) + filter elements from xml file [] + generate ddirectory listing + + + + +]] + +local xmltools = logs.application { + name = "xmltools", + banner = "XMLTools 1.2.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + pstopdf + PStoPDF + 2.0.1 + + + + + handles exa request file + watch folders for conversions (untested) + + + + +]] + +local pstopdf = logs.application { + name = "pstopdf", + banner = "PStoPDF 2.0.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + rlxtools + RlxTools + 1.0.1 + + + + + [ manipulatorfile resourselog + [ filename + + + + +]] + +local rlxtools = logs.application { + name = "rlxtools", + banner = "RlxTools 1.0.1", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + imgtopdf + ImgToPdf + 1.1.2 + + + + + convert image into pdf + level of compression in percent + image depth in bits + colorspace (rgb,cmyk,gray) + quality in percent + path where files are looked for + path where files end up + determine settings automatically + + + + +]] + +local imgtopdf = logs.application { + name = "imgtopdf", + banner = "ImgToPdf 1.1.2", + helpinfo = helpinfo, +} + +local helpinfo = [[ + + + + mptopdf + convert MetaPost to PDF + 1.4.1 + + + + + use the metafun format to process the file (default is mpost) + use texexec (context) to process text snippets + use latex to process text snippets + + + + +]] + +local mptopdf = logs.application { + name = "mptopdf", + banner = "MPtoPDF 1.4.1", + helpinfo = helpinfo, +} + +-- texmfstart.rb is normally replaced by mtxrun +-- runtools.rb is run from within context +-- concheck.rb is run from within editors +-- texsync.rb is no longer in the zip +-- mpstools.rb is no longer in the zip +-- rscortool.rb is only run indirectly +-- rsfiltool.rb is only run indirectly +-- rslibtool.rb is only run indirectly + +local application = logs.application { + name = "mk-help", + banner = "Mk Help generator 1.00", +} + +local filename = environment.files[1] + +if not filename then + application.report("no mk script given") + return +end + +local mkapplication + +if filename == "texmfstart" then mkapplication = texmfstart +elseif filename == "luatools" then mkapplication = luatools +elseif filename == "texexec" then mkapplication = texexec +elseif filename == "texutil" then mkapplication = texutil +elseif filename == "ctxtools" then mkapplication = ctxtools +elseif filename == "textools" then mkapplication = textools +elseif filename == "pdftools" then mkapplication = pdftools +elseif filename == "tmftools" then mkapplication = tmftools +elseif filename == "xmltools" then mkapplication = xmltools +elseif filename == "pstopdf" then mkapplication = pstopdf +elseif filename == "rlxtools" then mkapplication = rlxtools +elseif filename == "imgtopdf" then mkapplication = imgtopdf +elseif filename == "mptopdf" then mkapplication = mptopdf end + +if not mkapplication then + application.report("no valid mk script given") + return +end + +if environment.argument("exporthelp") then + mkapplication.export(environment.argument("exporthelp"),environment.files[2]) +else + mkapplication.help() +end diff --git a/scripts/context/lua/mtx-modules.lua b/scripts/context/lua/mtx-modules.lua index f4003c1db..766be6b49 100644 --- a/scripts/context/lua/mtx-modules.lua +++ b/scripts/context/lua/mtx-modules.lua @@ -1,202 +1,202 @@ -if not modules then modules = { } end modules ['mtx-modules'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -scripts = scripts or { } -scripts.modules = scripts.modules or { } - -local helpinfo = [[ - - - - mtx-modules - ConTeXt Module Documentation Generators - 1.00 - - - - - convert source files (tex, mkii, mkiv, mp) to 'ted' files - process source files (tex, mkii, mkiv, mp) to 'pdf' files - use original name with suffix 'prep' appended - - - - -]] - -local application = logs.application { - name = "mtx-modules", - banner = "ConTeXt Module Documentation Generators 1.00", - helpinfo = helpinfo, -} - -local report = application.report - --- Documentation can be woven into a source file. This script can generates --- a file with the documentation and source fragments properly tagged. The --- documentation is included as comment: --- --- %D ...... some kind of documentation --- %M ...... macros needed for documenation --- %S B begin skipping --- %S E end skipping --- --- The generated file is structured as: --- --- \starttypen --- \startmodule[type=suffix] --- \startdocumentation --- \stopdocumentation --- \startdefinition --- \stopdefinition --- \stopmodule --- \stoptypen --- --- Macro definitions specific to the documentation are not surrounded by --- start-stop commands. The suffix specificaction can be overruled at runtime, --- but defaults to the file extension. This specification can be used for language --- depended verbatim typesetting. --- --- In the mkiv variant we filter the \module settings so that we don't have --- to mess with global document settings. - -local find, format, sub, is_empty, strip, gsub = string.find, string.format, string.sub, string.is_empty, string.strip, string.gsub - -local function source_to_ted(inpname,outname,filetype) - local data = io.loaddata(inpname) - if not data or data == "" then - report("invalid module name '%s'",inpname) - return - end - report("converting '%s' to '%s'",inpname,outname) - local skiplevel, indocument, indefinition = 0, false, false - local started = false - local settings = format("type=%s",filetype or file.suffix(inpname)) - local preamble, n = lpeg.match(lpeg.Cs((1-lpeg.patterns.newline^2)^1) * lpeg.Cp(),data) - if preamble then - preamble = string.match(preamble,"\\module.-%[(.-)%]") - if preamble then - preamble = gsub(preamble,"%%D *","") - preamble = gsub(preamble,"%%(.-)[\n\r]","") - preamble = gsub(preamble,"[\n\r]","") - preamble = strip(preamble) - settings = format("%s,%s",settings,preamble) - data = string.sub(data,n,#data) - end - end - local lines = string.splitlines(data) - local result = { } - result[#result+1] = format("\\startmoduledocumentation[%s]",settings) - for i=1,#lines do - local line = lines[i] - if find(line,"^%%D ") or find(line,"^%%D$") then - if skiplevel == 0 then - local someline = #line < 3 and "" or sub(line,4,#line) - if indocument then - result[#result+1] = someline - else - if indefinition then - result[#result+1] = "\\stopdefinition" - indefinition = false - end - if not indocument then - result[#result+1] = "\\startdocumentation" - end - result[#result+1] = someline - indocument = true - end - end - elseif find(line,"^%%M ") or find(line,"^%%M$") then - if skiplevel == 0 then - local someline = (#line < 3 and "") or sub(line,4,#line) - result[#result+1] = someline - end - elseif find(line,"^%%S B") then - skiplevel = skiplevel + 1 - elseif find(line,"^%%S E") then - skiplevel = skiplevel - 1 - elseif find(line,"^%%") then - -- nothing - elseif skiplevel == 0 then - inlocaldocument = indocument - inlocaldocument = false - local someline = line - if indocument then - result[#result+1] = "\\stopdocumentation" - indocument = false - end - if indefinition then - if is_empty(someline) then - result[#result+1] = "\\stopdefinition" - indefinition = false - else - result[#result+1] = someline - end - elseif not is_empty(someline) then - result[#result+1] = "\n" - result[#result+1] = "\\startdefinition" - indefinition = true - if inlocaldocument then - -- nothing - else - result[#result+1] = someline - end - end - end - end - if indocument then - result[#result+1] = "\\stopdocumentation" - end - if indefinition then - result[#result+1] = "\\stopdefinition" - end - result[#result+1] = "\\stopmoduledocumentation" - io.savedata(outname,table.concat(result,"\n")) - return true -end - -local suffixes = table.tohash { 'tex','mkii','mkiv', 'mkvi', 'mp' } - -function scripts.modules.process(runtex) - local processed = { } - local prep = environment.argument("prep") - local files = environment.files - for i=1,#files do - local shortname = files[i] - local suffix = file.suffix(shortname) - if suffixes[suffix] then - local longname - if prep then - longname = shortname .. ".prep" - else - longname = file.removesuffix(shortname) .. "-" .. suffix .. ".ted" - end - local done = source_to_ted(shortname,longname) - if done and runtex then - os.execute(format("mtxrun --script context --usemodule=mod-01 --purge %s",longname)) - processed[#processed+1] = longname - end - end - end - for i=1,#processed do - local name = processed[i] - report("modules","processed: %s",name) - end -end - --- context --ctx=m-modules.ctx xxx.mkiv - -if environment.argument("process") then - scripts.modules.process(true) -elseif environment.argument("convert") then - scripts.modules.process(false) -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-modules'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +scripts = scripts or { } +scripts.modules = scripts.modules or { } + +local helpinfo = [[ + + + + mtx-modules + ConTeXt Module Documentation Generators + 1.00 + + + + + convert source files (tex, mkii, mkiv, mp) to 'ted' files + process source files (tex, mkii, mkiv, mp) to 'pdf' files + use original name with suffix 'prep' appended + + + + +]] + +local application = logs.application { + name = "mtx-modules", + banner = "ConTeXt Module Documentation Generators 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +-- Documentation can be woven into a source file. This script can generates +-- a file with the documentation and source fragments properly tagged. The +-- documentation is included as comment: +-- +-- %D ...... some kind of documentation +-- %M ...... macros needed for documenation +-- %S B begin skipping +-- %S E end skipping +-- +-- The generated file is structured as: +-- +-- \starttypen +-- \startmodule[type=suffix] +-- \startdocumentation +-- \stopdocumentation +-- \startdefinition +-- \stopdefinition +-- \stopmodule +-- \stoptypen +-- +-- Macro definitions specific to the documentation are not surrounded by +-- start-stop commands. The suffix specificaction can be overruled at runtime, +-- but defaults to the file extension. This specification can be used for language +-- depended verbatim typesetting. +-- +-- In the mkiv variant we filter the \module settings so that we don't have +-- to mess with global document settings. + +local find, format, sub, is_empty, strip, gsub = string.find, string.format, string.sub, string.is_empty, string.strip, string.gsub + +local function source_to_ted(inpname,outname,filetype) + local data = io.loaddata(inpname) + if not data or data == "" then + report("invalid module name '%s'",inpname) + return + end + report("converting '%s' to '%s'",inpname,outname) + local skiplevel, indocument, indefinition = 0, false, false + local started = false + local settings = format("type=%s",filetype or file.suffix(inpname)) + local preamble, n = lpeg.match(lpeg.Cs((1-lpeg.patterns.newline^2)^1) * lpeg.Cp(),data) + if preamble then + preamble = string.match(preamble,"\\module.-%[(.-)%]") + if preamble then + preamble = gsub(preamble,"%%D *","") + preamble = gsub(preamble,"%%(.-)[\n\r]","") + preamble = gsub(preamble,"[\n\r]","") + preamble = strip(preamble) + settings = format("%s,%s",settings,preamble) + data = string.sub(data,n,#data) + end + end + local lines = string.splitlines(data) + local result = { } + result[#result+1] = format("\\startmoduledocumentation[%s]",settings) + for i=1,#lines do + local line = lines[i] + if find(line,"^%%D ") or find(line,"^%%D$") then + if skiplevel == 0 then + local someline = #line < 3 and "" or sub(line,4,#line) + if indocument then + result[#result+1] = someline + else + if indefinition then + result[#result+1] = "\\stopdefinition" + indefinition = false + end + if not indocument then + result[#result+1] = "\\startdocumentation" + end + result[#result+1] = someline + indocument = true + end + end + elseif find(line,"^%%M ") or find(line,"^%%M$") then + if skiplevel == 0 then + local someline = (#line < 3 and "") or sub(line,4,#line) + result[#result+1] = someline + end + elseif find(line,"^%%S B") then + skiplevel = skiplevel + 1 + elseif find(line,"^%%S E") then + skiplevel = skiplevel - 1 + elseif find(line,"^%%") then + -- nothing + elseif skiplevel == 0 then + inlocaldocument = indocument + inlocaldocument = false + local someline = line + if indocument then + result[#result+1] = "\\stopdocumentation" + indocument = false + end + if indefinition then + if is_empty(someline) then + result[#result+1] = "\\stopdefinition" + indefinition = false + else + result[#result+1] = someline + end + elseif not is_empty(someline) then + result[#result+1] = "\n" + result[#result+1] = "\\startdefinition" + indefinition = true + if inlocaldocument then + -- nothing + else + result[#result+1] = someline + end + end + end + end + if indocument then + result[#result+1] = "\\stopdocumentation" + end + if indefinition then + result[#result+1] = "\\stopdefinition" + end + result[#result+1] = "\\stopmoduledocumentation" + io.savedata(outname,table.concat(result,"\n")) + return true +end + +local suffixes = table.tohash { 'tex','mkii','mkiv', 'mkvi', 'mp' } + +function scripts.modules.process(runtex) + local processed = { } + local prep = environment.argument("prep") + local files = environment.files + for i=1,#files do + local shortname = files[i] + local suffix = file.suffix(shortname) + if suffixes[suffix] then + local longname + if prep then + longname = shortname .. ".prep" + else + longname = file.removesuffix(shortname) .. "-" .. suffix .. ".ted" + end + local done = source_to_ted(shortname,longname) + if done and runtex then + os.execute(format("mtxrun --script context --usemodule=mod-01 --purge %s",longname)) + processed[#processed+1] = longname + end + end + end + for i=1,#processed do + local name = processed[i] + report("modules","processed: %s",name) + end +end + +-- context --ctx=m-modules.ctx xxx.mkiv + +if environment.argument("process") then + scripts.modules.process(true) +elseif environment.argument("convert") then + scripts.modules.process(false) +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-mtxworks.lua b/scripts/context/lua/mtx-mtxworks.lua index 1239ae4c5..e6517dd95 100644 --- a/scripts/context/lua/mtx-mtxworks.lua +++ b/scripts/context/lua/mtx-mtxworks.lua @@ -1,14 +1,14 @@ -if not modules then modules = { } end modules ['mtx-mtxworks'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- this is a shortcut to "mtxrun --script texworks --start" - -environment.setargument("start",true) - -require "mtx-texworks" - +if not modules then modules = { } end modules ['mtx-mtxworks'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- this is a shortcut to "mtxrun --script texworks --start" + +environment.setargument("start",true) + +require "mtx-texworks" + diff --git a/scripts/context/lua/mtx-package.lua b/scripts/context/lua/mtx-package.lua index 8c9e6b9fc..a5792ec4f 100644 --- a/scripts/context/lua/mtx-package.lua +++ b/scripts/context/lua/mtx-package.lua @@ -1,84 +1,84 @@ -if not modules then modules = { } end modules ['mtx-package'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local format, gsub, gmatch = string.format, string.gsub, string.gmatch - -local helpinfo = [[ - - - - mtx-package - Distribution Related Goodies - 0.10 - - - - - merge 'loadmodule' into merge file - - - - -]] - -local application = logs.application { - name = "mtx-package", - banner = "Distribution Related Goodies 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -messages = messages or { } -scripts.package = scripts.package or { } - -function scripts.package.merge_luatex_files(name) - local oldname = resolvers.findfile(name) or "" - oldname = file.replacesuffix(oldname,"lua") - if oldname == "" then - report("missing %q",name) - else - local newname = file.removesuffix(oldname) .. "-merged.lua" - local data = io.loaddata(oldname) or "" - if data == "" then - report("missing %q",newname) - else - report("loading %q",oldname) - local collected = { } - collected[#collected+1] = format("-- merged file : %s\n",newname) - collected[#collected+1] = format("-- parent file : %s\n",oldname) - collected[#collected+1] = format("-- merge date : %s\n",os.date()) - -- loadmodule can have extra arguments - for lib in gmatch(data,"loadmodule *%([\'\"](.-)[\'\"]") do - if file.basename(lib) ~= file.basename(newname) then - local fullname = resolvers.findfile(lib) or "" - if fullname == "" then - report("missing %q",lib) - else - report("fetching %q",fullname) - local data = io.loaddata(fullname) - collected[#collected+1] = "\ndo -- begin closure to overcome local limits and interference\n\n" - collected[#collected+1] = utilities.merger.compact(data) - collected[#collected+1] = "\nend -- closure\n" - end - end - end - report("saving %q",newname) - io.savedata(newname,table.concat(collected)) - end - end -end - -if environment.argument("merge") then - scripts.package.merge_luatex_files(environment.files[1] or "") -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-package'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local format, gsub, gmatch = string.format, string.gsub, string.gmatch + +local helpinfo = [[ + + + + mtx-package + Distribution Related Goodies + 0.10 + + + + + merge 'loadmodule' into merge file + + + + +]] + +local application = logs.application { + name = "mtx-package", + banner = "Distribution Related Goodies 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +messages = messages or { } +scripts.package = scripts.package or { } + +function scripts.package.merge_luatex_files(name) + local oldname = resolvers.findfile(name) or "" + oldname = file.replacesuffix(oldname,"lua") + if oldname == "" then + report("missing %q",name) + else + local newname = file.removesuffix(oldname) .. "-merged.lua" + local data = io.loaddata(oldname) or "" + if data == "" then + report("missing %q",newname) + else + report("loading %q",oldname) + local collected = { } + collected[#collected+1] = format("-- merged file : %s\n",newname) + collected[#collected+1] = format("-- parent file : %s\n",oldname) + collected[#collected+1] = format("-- merge date : %s\n",os.date()) + -- loadmodule can have extra arguments + for lib in gmatch(data,"loadmodule *%([\'\"](.-)[\'\"]") do + if file.basename(lib) ~= file.basename(newname) then + local fullname = resolvers.findfile(lib) or "" + if fullname == "" then + report("missing %q",lib) + else + report("fetching %q",fullname) + local data = io.loaddata(fullname) + collected[#collected+1] = "\ndo -- begin closure to overcome local limits and interference\n\n" + collected[#collected+1] = utilities.merger.compact(data) + collected[#collected+1] = "\nend -- closure\n" + end + end + end + report("saving %q",newname) + io.savedata(newname,table.concat(collected)) + end + end +end + +if environment.argument("merge") then + scripts.package.merge_luatex_files(environment.files[1] or "") +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-patterns.lua b/scripts/context/lua/mtx-patterns.lua index 2dcd3db54..1abe90385 100644 --- a/scripts/context/lua/mtx-patterns.lua +++ b/scripts/context/lua/mtx-patterns.lua @@ -27,6 +27,8 @@ local helpinfo = [[ source path where hyph-foo.tex files are stored destination path additional patterns: e.g.: =cy,hyph-cy,welsh + compress data + update words in given file @@ -413,6 +415,8 @@ function scripts.patterns.save(destination,mnemonic,name,patternsnew,hyphenation if not comment or comment == "" then comment = "% no comment" end if not type(destination) == "string" then destination = "." end + local compression = environment.arguments.compress and "zlib" or nil + local lines = string.splitlines(comment) for i=1,#lines do if not find(lines[i],"^%%") then @@ -429,9 +433,12 @@ function scripts.patterns.save(destination,mnemonic,name,patternsnew,hyphenation local patterndata, hyphenationdata if nofpatternsnew > 0 then + local data = concat(patternsnew," ") patterndata = { n = nofpatternsnew, - data = concat(patternsnew," ") or nil, + compression = compression, + length = #data, + data = compression and zlib.compress(data,9) or data, characters = concat(table.sortedkeys(pusednew),""), minhyphenmin = 1, -- determined by pattern author minhyphenmax = 1, -- determined by pattern author @@ -442,10 +449,13 @@ function scripts.patterns.save(destination,mnemonic,name,patternsnew,hyphenation } end if nofhyphenationsnew > 0 then + local data = concat(hyphenationsnew," ") hyphenationdata = { - n = nofhyphenationsnew, - data = concat(hyphenationsnew," "), - characters = concat(table.sortedkeys(husednew),""), + n = nofhyphenationsnew, + compression = compression, + length = #data, + data = compression and zlib.compress(data,9) or data, + characters = concat(table.sortedkeys(husednew),""), } else hyphenationdata = { @@ -543,12 +553,83 @@ function scripts.patterns.convert() end end +local function valid(filename) + local specification = table.load(filename) + if not specification then + return false + end + local lists = specification.lists + if not lists then + return false + end + return specification, lists +end + +function scripts.patterns.words() + if environment.arguments.update then + local compress = environment.arguments.compress + for i=1,#environment.files do + local filename = environment.files[i] + local fullname = resolvers.findfile(filename) + if fullname and fullname ~= "" then + report("checking file %a",fullname) + local specification, lists = valid(fullname) + if specification and #lists> 0 then + report("updating %a of language %a",filename,specification.language) + for i=1,#lists do + local entry = lists[i] + local filename = entry.filename + if filename then + local fullname = resolvers.findfile(filename) + if fullname then + report("adding words from %a",fullname) + local data = io.loaddata(fullname) or "" + data = string.strip(data) + data = string.gsub(data,"%s+"," ") + if compress then + entry.data = zlib.compress(data,9) + entry.compression = "zlib" + entry.length = #data + else + entry.data = data + entry.compression = nil + entry.length = #data + end + else + entry.data = "" + entry.compression = nil + entry.length = 0 + end + else + entry.data = "" + entry.compression = nil + entry.length = 0 + end + end + specification.version = "1.00" + specification.timestamp = os.localtime() + report("updated file %a is saved",filename) + table.save(filename,specification) + else + report("no file %a",filename) + end + else + report("nothing done") + end + end + else + report("provide --update") + end +end + if environment.argument("check") then scripts.patterns.prepare() scripts.patterns.check() elseif environment.argument("convert") then scripts.patterns.prepare() scripts.patterns.convert() +elseif environment.argument("words") then + scripts.patterns.words() -- for the moment here elseif environment.argument("exporthelp") then application.export(environment.argument("exporthelp"),environment.files[1]) else @@ -558,7 +639,7 @@ end -- mtxrun --script pattern --check hyph-*.tex -- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns -- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex --destination=e:/tmp/patterns --- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/txt --destination=e:/tmp/patterns +-- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/txt --destination=e:/tmp/patterns --compress -- copy /Y *.hyp e:\tex-context\tex\texmf-context\tex\context\patterns -- copy /Y *.pat e:\tex-context\tex\texmf-context\tex\context\patterns @@ -569,3 +650,5 @@ end -- move /Y *.pat e:\tex-context\tex\texmf-mine\tex\context\patterns -- move /Y *.rme e:\tex-context\tex\texmf-mine\tex\context\patterns -- move /Y *.lua e:\tex-context\tex\texmf-mine\tex\context\patterns + +-- mtxrun --script pattern --words --update word-th.lua --compress diff --git a/scripts/context/lua/mtx-pdf.lua b/scripts/context/lua/mtx-pdf.lua index 551aa5b37..2ff22e07f 100644 --- a/scripts/context/lua/mtx-pdf.lua +++ b/scripts/context/lua/mtx-pdf.lua @@ -1,299 +1,299 @@ -if not modules then modules = { } end modules ['mtx-pdf'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local tonumber = tonumber -local format, gmatch = string.format, string.gmatch -local utfchar = utf.char -local concat = table.concat -local setmetatableindex, sortedhash, sortedkeys = table.setmetatableindex, table.sortedhash, table.sortedkeys - -local helpinfo = [[ - - - - mtx-pdf - ConTeXt PDF Helpers - 0.10 - - - - - show some info about the given file - show metadata xml blob - show used fonts ( - linearize given file - - - - -]] - -local application = logs.application { - name = "mtx-pdf", - banner = "ConTeXt PDF Helpers 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -dofile(resolvers.findfile("lpdf-epd.lua","tex")) - -scripts = scripts or { } -scripts.pdf = scripts.pdf or { } - -local function loadpdffile(filename) - if not filename or filename == "" then - report("no filename given") - elseif not lfs.isfile(filename) then - report("unknown file '%s'",filename) - else - local pdffile = lpdf.epdf.load(filename) - if pdffile then - return pdffile - else - report("no valid pdf file '%s'",filename) - end - end -end - -function scripts.pdf.info(filename) - local pdffile = loadpdffile(filename) - if pdffile then - local catalog = pdffile.Catalog - local info = pdffile.Info - local pages = pdffile.pages - local nofpages = pages.n -- no # yet. will be in 5.2 - - report("filename > %s",filename) - report("pdf version > %s",catalog.Version) - report("number of pages > %s",nofpages) - report("title > %s",info.Title) - report("creator > %s",info.Creator) - report("producer > %s",info.Producer) - report("creation date > %s",info.CreationDate) - report("modification date > %s",info.ModDate) - - local width, height, start - for i=1, nofpages do - local page = pages[i] - local bbox = page.CropBox or page.MediaBox - local w, h = bbox[4]-bbox[2],bbox[3]-bbox[1] - if w ~= width or h ~= height then - if start then - report("cropbox > pages: %s-%s, width: %s, height: %s",start,i-1,width,height) - end - width, height, start = w, h, i - end - end - report("cropbox > pages: %s-%s, width: %s, height: %s",start,nofpages,width,height) - end -end - -function scripts.pdf.metadata(filename) - local pdffile = loadpdffile(filename) - if pdffile then - local catalog = pdffile.Catalog - local metadata = catalog.Metadata - if metadata then - report("metadata > \n\n%s\n",metadata()) - else - report("no metadata") - end - end -end - -local function getfonts(pdffile) - local usedfonts = { } - for i=1,pdffile.pages.n do - local page = pdffile.pages[i] - local fontlist = page.Resources.Font - for k, v in next, lpdf.epdf.expand(fontlist) do - usedfonts[k] = lpdf.epdf.expand(v) - end - end - return usedfonts -end - -local function getunicodes(font) - local cid = font.ToUnicode - if cid then - cid = cid() - local counts = { } - -- for s in gmatch(cid,"begincodespacerange%s*(.-)%s*endcodespacerange") do - -- for a, b in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do - -- print(a,b) - -- end - -- end - setmetatableindex(counts, function(t,k) t[k] = 0 return 0 end) - for s in gmatch(cid,"beginbfrange%s*(.-)%s*endbfrange") do - for first, last, offset in gmatch(s,"<([^>]+)>%s+<([^>]+)>%s+<([^>]+)>") do - first = tonumber(first,16) - last = tonumber(last,16) - offset = tonumber(offset,16) - offset = offset - first - for i=first,last do - local c = i + offset - counts[c] = counts[c] + 1 - end - end - end - for s in gmatch(cid,"beginbfchar%s*(.-)%s*endbfchar") do - for old, new in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do - for n in gmatch(new,"....") do - local c = tonumber(n,16) - counts[c] = counts[c] + 1 - end - end - end - return counts - end -end - -function scripts.pdf.fonts(filename) - local pdffile = loadpdffile(filename) - if pdffile then - local usedfonts = getfonts(pdffile) - local found = { } - for k, v in table.sortedhash(usedfonts) do - local counts = getunicodes(v) - local codes = { } - local chars = { } - local freqs = { } - if counts then - codes = sortedkeys(counts) - for i=1,#codes do - local k = codes[i] - local c = utfchar(k) - chars[i] = c - freqs[i] = format("U+%05X %s %s",k,counts[k] > 1 and "+" or " ", c) - end - for i=1,#codes do - codes[i] = format("U+%05X",codes[i]) - end - end - found[k] = { - basefont = v.BaseFont or "no basefont", - encoding = v.Encoding or "no encoding", - subtype = v.Subtype or "no subtype", - unicode = v.ToUnicode and "unicode" or "no unicode", - chars = chars, - codes = codes, - freqs = freqs, - } - end - - if environment.argument("detail") then - for k, v in sortedhash(found) do - report("id : %s",k) - report("basefont : %s",v.basefont) - report("encoding : %s",v.encoding) - report("subtype : %s",v.subtype) - report("unicode : %s",v.unicode) - report("characters : %s", concat(v.chars," ")) - report("codepoints : %s", concat(v.codes," ")) - report("") - end - else - local results = { { "id", "basefont", "encoding", "subtype", "unicode", "characters" } } - for k, v in sortedhash(found) do - results[#results+1] = { k, v.basefont, v.encoding, v.subtype, v.unicode, concat(v.chars," ") } - end - utilities.formatters.formatcolumns(results) - report(results[1]) - report("") - for i=2,#results do - report(results[i]) - end - report("") - end - end -end - --- this is a quick hack ... proof of concept .. will change (derived from luigi's example) ... --- i will make a ctx wrapper - -local qpdf - -function scripts.pdf.linearize(filename) - qpdf = qpdf or swiglib("qpdf.core") - local oldfile = filename or environment.files[1] - if not oldfile then - return - end - file.addsuffix(oldfile,"pdf") - if not lfs.isfile(oldfile) then - return - end - local newfile = environment.files[2] - if not newfile or file.removesuffix(oldfile) == file.removesuffix(newfile)then - newfile = file.addsuffix(file.removesuffix(oldfile) .. "-linearized","pdf") - end - local password = environment.arguments.password - local instance = qpdf.qpdf_init() - if bit32.band(qpdf.qpdf_read(instance,oldfile,password),qpdf.QPDF_ERRORS) ~= 0 then - report("unable to open input file") - elseif bit32.band(qpdf.qpdf_init_write(instance,newfile),qpdf.QPDF_ERRORS) ~= 0 then - report("unable to open output file") - else - report("linearizing %a into %a",oldfile,newfile) - qpdf.qpdf_set_static_ID(instance,qpdf.QPDF_TRUE) - qpdf.qpdf_set_linearization(instance,qpdf.QPDF_TRUE) - qpdf.qpdf_write(instance) - end - while qpdf.qpdf_more_warnings(instance) ~= 0 do - report("warning: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_next_warning(qpdf))) - end - if qpdf.qpdf_has_error(instance) ~= 0 then - report("error: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_get_error(qpdf))) - end - qpdf.qpdf_cleanup_p(instance) -end - --- scripts.pdf.info("e:/tmp/oeps.pdf") --- scripts.pdf.metadata("e:/tmp/oeps.pdf") --- scripts.pdf.fonts("e:/tmp/oeps.pdf") --- scripts.pdf.linearize("e:/tmp/oeps.pdf") - -local filename = environment.files[1] or "" - -if filename == "" then - application.help() -elseif environment.argument("info") then - scripts.pdf.info(filename) -elseif environment.argument("metadata") then - scripts.pdf.metadata(filename) -elseif environment.argument("fonts") then - scripts.pdf.fonts(filename) -elseif environment.argument("linearize") then - scripts.pdf.linearize(filename) -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),filename) -else - application.help() -end - --- a variant on an experiment by hartmut - ---~ function downloadlinks(filename) ---~ local document = lpdf.epdf.load(filename) ---~ if document then ---~ local pages = document.pages ---~ for p = 1,#pages do ---~ local annotations = pages[p].Annots ---~ if annotations then ---~ for a=1,#annotations do ---~ local annotation = annotations[a] ---~ local uri = annotation.Subtype == "Link" and annotation.A and annotation.A.URI ---~ if uri and string.find(uri,"^http") then ---~ os.execute("wget " .. uri) ---~ end ---~ end ---~ end ---~ end ---~ end ---~ end +if not modules then modules = { } end modules ['mtx-pdf'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local tonumber = tonumber +local format, gmatch = string.format, string.gmatch +local utfchar = utf.char +local concat = table.concat +local setmetatableindex, sortedhash, sortedkeys = table.setmetatableindex, table.sortedhash, table.sortedkeys + +local helpinfo = [[ + + + + mtx-pdf + ConTeXt PDF Helpers + 0.10 + + + + + show some info about the given file + show metadata xml blob + show used fonts ( + linearize given file + + + + +]] + +local application = logs.application { + name = "mtx-pdf", + banner = "ConTeXt PDF Helpers 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +dofile(resolvers.findfile("lpdf-epd.lua","tex")) + +scripts = scripts or { } +scripts.pdf = scripts.pdf or { } + +local function loadpdffile(filename) + if not filename or filename == "" then + report("no filename given") + elseif not lfs.isfile(filename) then + report("unknown file '%s'",filename) + else + local pdffile = lpdf.epdf.load(filename) + if pdffile then + return pdffile + else + report("no valid pdf file '%s'",filename) + end + end +end + +function scripts.pdf.info(filename) + local pdffile = loadpdffile(filename) + if pdffile then + local catalog = pdffile.Catalog + local info = pdffile.Info + local pages = pdffile.pages + local nofpages = pages.n -- no # yet. will be in 5.2 + + report("filename > %s",filename) + report("pdf version > %s",catalog.Version) + report("number of pages > %s",nofpages) + report("title > %s",info.Title) + report("creator > %s",info.Creator) + report("producer > %s",info.Producer) + report("creation date > %s",info.CreationDate) + report("modification date > %s",info.ModDate) + + local width, height, start + for i=1, nofpages do + local page = pages[i] + local bbox = page.CropBox or page.MediaBox + local w, h = bbox[4]-bbox[2],bbox[3]-bbox[1] + if w ~= width or h ~= height then + if start then + report("cropbox > pages: %s-%s, width: %s, height: %s",start,i-1,width,height) + end + width, height, start = w, h, i + end + end + report("cropbox > pages: %s-%s, width: %s, height: %s",start,nofpages,width,height) + end +end + +function scripts.pdf.metadata(filename) + local pdffile = loadpdffile(filename) + if pdffile then + local catalog = pdffile.Catalog + local metadata = catalog.Metadata + if metadata then + report("metadata > \n\n%s\n",metadata()) + else + report("no metadata") + end + end +end + +local function getfonts(pdffile) + local usedfonts = { } + for i=1,pdffile.pages.n do + local page = pdffile.pages[i] + local fontlist = page.Resources.Font + for k, v in next, lpdf.epdf.expand(fontlist) do + usedfonts[k] = lpdf.epdf.expand(v) + end + end + return usedfonts +end + +local function getunicodes(font) + local cid = font.ToUnicode + if cid then + cid = cid() + local counts = { } + -- for s in gmatch(cid,"begincodespacerange%s*(.-)%s*endcodespacerange") do + -- for a, b in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do + -- print(a,b) + -- end + -- end + setmetatableindex(counts, function(t,k) t[k] = 0 return 0 end) + for s in gmatch(cid,"beginbfrange%s*(.-)%s*endbfrange") do + for first, last, offset in gmatch(s,"<([^>]+)>%s+<([^>]+)>%s+<([^>]+)>") do + first = tonumber(first,16) + last = tonumber(last,16) + offset = tonumber(offset,16) + offset = offset - first + for i=first,last do + local c = i + offset + counts[c] = counts[c] + 1 + end + end + end + for s in gmatch(cid,"beginbfchar%s*(.-)%s*endbfchar") do + for old, new in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do + for n in gmatch(new,"....") do + local c = tonumber(n,16) + counts[c] = counts[c] + 1 + end + end + end + return counts + end +end + +function scripts.pdf.fonts(filename) + local pdffile = loadpdffile(filename) + if pdffile then + local usedfonts = getfonts(pdffile) + local found = { } + for k, v in table.sortedhash(usedfonts) do + local counts = getunicodes(v) + local codes = { } + local chars = { } + local freqs = { } + if counts then + codes = sortedkeys(counts) + for i=1,#codes do + local k = codes[i] + local c = utfchar(k) + chars[i] = c + freqs[i] = format("U+%05X %s %s",k,counts[k] > 1 and "+" or " ", c) + end + for i=1,#codes do + codes[i] = format("U+%05X",codes[i]) + end + end + found[k] = { + basefont = v.BaseFont or "no basefont", + encoding = v.Encoding or "no encoding", + subtype = v.Subtype or "no subtype", + unicode = v.ToUnicode and "unicode" or "no unicode", + chars = chars, + codes = codes, + freqs = freqs, + } + end + + if environment.argument("detail") then + for k, v in sortedhash(found) do + report("id : %s",k) + report("basefont : %s",v.basefont) + report("encoding : %s",v.encoding) + report("subtype : %s",v.subtype) + report("unicode : %s",v.unicode) + report("characters : %s", concat(v.chars," ")) + report("codepoints : %s", concat(v.codes," ")) + report("") + end + else + local results = { { "id", "basefont", "encoding", "subtype", "unicode", "characters" } } + for k, v in sortedhash(found) do + results[#results+1] = { k, v.basefont, v.encoding, v.subtype, v.unicode, concat(v.chars," ") } + end + utilities.formatters.formatcolumns(results) + report(results[1]) + report("") + for i=2,#results do + report(results[i]) + end + report("") + end + end +end + +-- this is a quick hack ... proof of concept .. will change (derived from luigi's example) ... +-- i will make a ctx wrapper + +local qpdf + +function scripts.pdf.linearize(filename) + qpdf = qpdf or swiglib("qpdf.core") + local oldfile = filename or environment.files[1] + if not oldfile then + return + end + file.addsuffix(oldfile,"pdf") + if not lfs.isfile(oldfile) then + return + end + local newfile = environment.files[2] + if not newfile or file.removesuffix(oldfile) == file.removesuffix(newfile)then + newfile = file.addsuffix(file.removesuffix(oldfile) .. "-linearized","pdf") + end + local password = environment.arguments.password + local instance = qpdf.qpdf_init() + if bit32.band(qpdf.qpdf_read(instance,oldfile,password),qpdf.QPDF_ERRORS) ~= 0 then + report("unable to open input file") + elseif bit32.band(qpdf.qpdf_init_write(instance,newfile),qpdf.QPDF_ERRORS) ~= 0 then + report("unable to open output file") + else + report("linearizing %a into %a",oldfile,newfile) + qpdf.qpdf_set_static_ID(instance,qpdf.QPDF_TRUE) + qpdf.qpdf_set_linearization(instance,qpdf.QPDF_TRUE) + qpdf.qpdf_write(instance) + end + while qpdf.qpdf_more_warnings(instance) ~= 0 do + report("warning: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_next_warning(qpdf))) + end + if qpdf.qpdf_has_error(instance) ~= 0 then + report("error: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_get_error(qpdf))) + end + qpdf.qpdf_cleanup_p(instance) +end + +-- scripts.pdf.info("e:/tmp/oeps.pdf") +-- scripts.pdf.metadata("e:/tmp/oeps.pdf") +-- scripts.pdf.fonts("e:/tmp/oeps.pdf") +-- scripts.pdf.linearize("e:/tmp/oeps.pdf") + +local filename = environment.files[1] or "" + +if filename == "" then + application.help() +elseif environment.argument("info") then + scripts.pdf.info(filename) +elseif environment.argument("metadata") then + scripts.pdf.metadata(filename) +elseif environment.argument("fonts") then + scripts.pdf.fonts(filename) +elseif environment.argument("linearize") then + scripts.pdf.linearize(filename) +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),filename) +else + application.help() +end + +-- a variant on an experiment by hartmut + +--~ function downloadlinks(filename) +--~ local document = lpdf.epdf.load(filename) +--~ if document then +--~ local pages = document.pages +--~ for p = 1,#pages do +--~ local annotations = pages[p].Annots +--~ if annotations then +--~ for a=1,#annotations do +--~ local annotation = annotations[a] +--~ local uri = annotation.Subtype == "Link" and annotation.A and annotation.A.URI +--~ if uri and string.find(uri,"^http") then +--~ os.execute("wget " .. uri) +--~ end +--~ end +--~ end +--~ end +--~ end +--~ end diff --git a/scripts/context/lua/mtx-plain.lua b/scripts/context/lua/mtx-plain.lua index f43dcdeaf..975c91ee7 100644 --- a/scripts/context/lua/mtx-plain.lua +++ b/scripts/context/lua/mtx-plain.lua @@ -1,129 +1,129 @@ -if not modules then modules = { } end modules ['mtx-plain'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- future version will use the texmf-cache/generic/formats/ path --- instead because then we can use some more of the generic context --- initializers ... in that case we will also use the regular database --- instead of kpse here, just like with the font database code (as that --- one also works with kpse runtime) - -local helpinfo = [[ - - - - mtx-plain - Plain TeX Runner - 1.00 - - - - - create format file - process file - format name (default: luatex-plain) - engine to use (default: luatex) - use luajittex - - - - -]] - -local application = logs.application { - name = "mtx-plain", - banner = "Plain TeX Runner 1.00", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.plain = scripts.plain or { } - -local function execute(...) - local command = string.format(...) - report("running command %a\n",command) - os.execute(command) -end - -local function resultof(...) - local command = string.format(...) - report("running command %a",command) - return string.strip(os.resultof(command) or "") -end - -function scripts.plain.make(texengine,texformat) - report("generating kpse file database") - execute("mktexlsr") -- better play safe and use this one - local fmtpathspec = resultof("kpsewhich --var-value=TEXFORMATS --engine=%s",texengine) - if fmtpathspec ~= "" then - report("using path specification %a",fmtpathspec) - fmtpathspec = resultof('kpsewhich -expand-braces="%s"',fmtpathspec) - end - if fmtpathspec ~= "" then - report("using path expansion %a",fmtpathspec) - else - report("no valid path reported, trying alternative") - fmtpathspec = resultof("kpsewhich --show-path=fmt --engine=%s",texengine) - if fmtpathspec ~= "" then - report("using path expansion %a",fmtpathspec) - else - report("no valid path reported, falling back to current path") - fmtpathspec = "." - end - end - fmtpathspec = string.splitlines(fmtpathspec)[1] or fmtpathspec - fmtpathspec = file.splitpath(fmtpathspec) - local fmtpath = nil - for i=1,#fmtpathspec do - local path = fmtpathspec[i] - if path ~= "." then - dir.makedirs(path) - if lfs.isdir(path) and file.is_writable(path) then - fmtpath = path - break - end - end - end - if not fmtpath or fmtpath == "" then - fmtpath = "." - else - lfs.chdir(fmtpath) - end - execute('%s --ini %s \\dump',texengine,file.addsuffix(texformat,"tex")) - report("generating kpse file database") - execute("mktexlsr") - report("format %a saved on path %a",texformat,fmtpath) -end - -function scripts.plain.run(texengine,texformat,filename) - execute('%s --fmt=%s "%s"',texengine,file.removesuffix(texformat),filename) -end - -local texformat = environment.arguments.texformat or environment.arguments.format -local texengine = environment.arguments.texengine or environment.arguments.engine - -if type(texengine) ~= "string" or texengine == "" then - texengine = environment.arguments.jit and "luajittex" or"luatex" -end - -if type(texformat) ~= "string" or texformat == "" then - texformat = "luatex-plain" -end - -local filename = environment.files[1] - -if environment.arguments.exporthelp then - application.export(environment.arguments.exporthelp,filename) -elseif environment.arguments.make then - scripts.plain.make(texengine,texformat) -elseif filename then - scripts.plain.run(texengine,texformat,filename) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-plain'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- future version will use the texmf-cache/generic/formats/ path +-- instead because then we can use some more of the generic context +-- initializers ... in that case we will also use the regular database +-- instead of kpse here, just like with the font database code (as that +-- one also works with kpse runtime) + +local helpinfo = [[ + + + + mtx-plain + Plain TeX Runner + 1.00 + + + + + create format file + process file + format name (default: luatex-plain) + engine to use (default: luatex) + use luajittex + + + + +]] + +local application = logs.application { + name = "mtx-plain", + banner = "Plain TeX Runner 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.plain = scripts.plain or { } + +local function execute(...) + local command = string.format(...) + report("running command %a\n",command) + os.execute(command) +end + +local function resultof(...) + local command = string.format(...) + report("running command %a",command) + return string.strip(os.resultof(command) or "") +end + +function scripts.plain.make(texengine,texformat) + report("generating kpse file database") + execute("mktexlsr") -- better play safe and use this one + local fmtpathspec = resultof("kpsewhich --var-value=TEXFORMATS --engine=%s",texengine) + if fmtpathspec ~= "" then + report("using path specification %a",fmtpathspec) + fmtpathspec = resultof('kpsewhich -expand-braces="%s"',fmtpathspec) + end + if fmtpathspec ~= "" then + report("using path expansion %a",fmtpathspec) + else + report("no valid path reported, trying alternative") + fmtpathspec = resultof("kpsewhich --show-path=fmt --engine=%s",texengine) + if fmtpathspec ~= "" then + report("using path expansion %a",fmtpathspec) + else + report("no valid path reported, falling back to current path") + fmtpathspec = "." + end + end + fmtpathspec = string.splitlines(fmtpathspec)[1] or fmtpathspec + fmtpathspec = file.splitpath(fmtpathspec) + local fmtpath = nil + for i=1,#fmtpathspec do + local path = fmtpathspec[i] + if path ~= "." then + dir.makedirs(path) + if lfs.isdir(path) and file.is_writable(path) then + fmtpath = path + break + end + end + end + if not fmtpath or fmtpath == "" then + fmtpath = "." + else + lfs.chdir(fmtpath) + end + execute('%s --ini %s \\dump',texengine,file.addsuffix(texformat,"tex")) + report("generating kpse file database") + execute("mktexlsr") + report("format %a saved on path %a",texformat,fmtpath) +end + +function scripts.plain.run(texengine,texformat,filename) + execute('%s --fmt=%s "%s"',texengine,file.removesuffix(texformat),filename) +end + +local texformat = environment.arguments.texformat or environment.arguments.format +local texengine = environment.arguments.texengine or environment.arguments.engine + +if type(texengine) ~= "string" or texengine == "" then + texengine = environment.arguments.jit and "luajittex" or"luatex" +end + +if type(texformat) ~= "string" or texformat == "" then + texformat = "luatex-plain" +end + +local filename = environment.files[1] + +if environment.arguments.exporthelp then + application.export(environment.arguments.exporthelp,filename) +elseif environment.arguments.make then + scripts.plain.make(texengine,texformat) +elseif filename then + scripts.plain.run(texengine,texformat,filename) +else + application.help() +end diff --git a/scripts/context/lua/mtx-profile.lua b/scripts/context/lua/mtx-profile.lua index 3550474f3..15ff595d2 100644 --- a/scripts/context/lua/mtx-profile.lua +++ b/scripts/context/lua/mtx-profile.lua @@ -1,187 +1,187 @@ -if not modules then modules = { } end modules ['mtx-profile'] = { - version = 1.000, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo: also line number --- todo: sort runtime as option - -local match, format, find = string.match, string.format, string.find - -local helpinfo = [[ - - - - mtx-profile - ConTeXt MkIV LuaTeX Profiler - 1.00 - - - - - analyze lua calls - analyze tex calls - - - - -]] - -local application = logs.application { - name = "mtx-cache", - banner = "ConTeXt MkIV LuaTeX Profiler 1.00", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.profiler = scripts.profiler or { } - -local timethreshold = 0 -local callthreshold = 2500 -local countthreshold = 2500 - -local functiontemplate = "%12s %03.4f %9i %s" -local calltemplate = "%9i %s" -local totaltemplate = "%i internal calls, %i function calls taking %3.4f seconds" -local thresholdtemplate = "thresholds: %i internal calls, %i function calls, %i seconds" - -function scripts.profiler.analyze(filename) - local f = io.open(filename) - if f then - local times, counts, calls = { }, { }, { } - local totalruntime, totalcount, totalcalls = 0, 0, 0 - for line in f:lines() do - local stacklevel, filename, functionname, linenumber, currentline, localtime, totaltime = line:match("^(%d+)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)") - if not filename then - -- next - elseif filename == "=[C]" then - if not functionname:find("^%(") then - calls[functionname] = (calls[functionname] or 0) + 1 - end - else - local filename = filename:match("^@(.*)$") - if filename then - local fi = times[filename] - if not fi then fi = { } times[filename] = fi end - fi[functionname] = (fi[functionname] or 0) + tonumber(localtime) - counts[functionname] = (counts[functionname] or 0) + 1 - end - end - end - f:close() - print("") - local loaded = { } - local sorted = table.sortedkeys(times) - for i=1,#sorted do - local filename = sorted[i] - local functions = times[filename] - local sorted = table.sortedkeys(functions) - for i=1,#sorted do - local functionname = sorted[i] - local totaltime = functions[functionname] - local count = counts[functionname] - totalcount = totalcount + count - if totaltime > timethreshold or count > countthreshold then - totalruntime = totalruntime + totaltime - local functionfile, somenumber = functionname:match("^@(.+):(.-)$") - if functionfile then - local number = tonumber(somenumber) - if number then - if not loaded[functionfile] then - loaded[functionfile] = string.splitlines(io.loaddata(functionfile) or "") - end - functionname = loaded[functionfile][number] or functionname - functionname = functionname:gsub("^%s*","") - functionname = functionname:gsub("%s*%-%-.*$","") - functionname = number .. ": " .. functionname - end - end - filename = file.basename(filename) - print(functiontemplate:format(filename,totaltime,count,functionname)) - end - end - end - print("") - local sorted = table.sortedkeys(calls) - for i=1,#sorted do - local call = sorted[i] - local n = calls[call] - totalcalls = totalcalls + n - if n > callthreshold then - print(calltemplate:format(n,call)) - end - end - print("") - print(totaltemplate:format(totalcalls,totalcount,totalruntime)) - print("") - print(thresholdtemplate:format(callthreshold,countthreshold,timethreshold)) - end -end - -function scripts.profiler.x_analyze(filename) - local f = io.open(filename) - local calls = { } - local lines = 0 - if f then - while true do - local line = f:read() - if line then - lines = lines + 1 - local c = match(line,"\\([a-zA-Z%!%?@]+) *%->") - if c then - local cc = calls[c] - if not cc then - calls[c] = 1 - else - calls[c] = cc + 1 - end - end - else - break - end - end - f:close() - local noc = 0 -local criterium = 100 - for name, n in next, calls do - if n > criterium then - if find(name,"^@@[a-z][a-z]") then - -- parameter - elseif find(name,"^[cvserft]%!") then - -- variables and constants - elseif find(name,"^%?%?[a-z][a-z]$") then - -- prefix - elseif find(name,"^%!%!") then - -- reserved - elseif find(name,"^@.+@$") then - -- weird - else - noc = noc + n - print(format("%6i: %s",n,name)) - end - end - end - print("") - print(format("number of lines: %s",lines)) - print(format("number of calls: %s",noc)) - print(format("criterium calls: %s",criterium)) - end -end - ---~ scripts.profiler.analyze("t:/manuals/mk/mk-fonts-profile.lua") ---~ scripts.profiler.analyze("t:/manuals/mk/mk-introduction-profile.lua") - -if environment.argument("analyze") then - scripts.profiler.analyze(environment.files[1] or "luatex-profile.log") -elseif environment.argument("trace") then - scripts.profiler.analyze(environment.files[1] or "temp.log") -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-profile'] = { + version = 1.000, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo: also line number +-- todo: sort runtime as option + +local match, format, find = string.match, string.format, string.find + +local helpinfo = [[ + + + + mtx-profile + ConTeXt MkIV LuaTeX Profiler + 1.00 + + + + + analyze lua calls + analyze tex calls + + + + +]] + +local application = logs.application { + name = "mtx-cache", + banner = "ConTeXt MkIV LuaTeX Profiler 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.profiler = scripts.profiler or { } + +local timethreshold = 0 +local callthreshold = 2500 +local countthreshold = 2500 + +local functiontemplate = "%12s %03.4f %9i %s" +local calltemplate = "%9i %s" +local totaltemplate = "%i internal calls, %i function calls taking %3.4f seconds" +local thresholdtemplate = "thresholds: %i internal calls, %i function calls, %i seconds" + +function scripts.profiler.analyze(filename) + local f = io.open(filename) + if f then + local times, counts, calls = { }, { }, { } + local totalruntime, totalcount, totalcalls = 0, 0, 0 + for line in f:lines() do + local stacklevel, filename, functionname, linenumber, currentline, localtime, totaltime = line:match("^(%d+)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)") + if not filename then + -- next + elseif filename == "=[C]" then + if not functionname:find("^%(") then + calls[functionname] = (calls[functionname] or 0) + 1 + end + else + local filename = filename:match("^@(.*)$") + if filename then + local fi = times[filename] + if not fi then fi = { } times[filename] = fi end + fi[functionname] = (fi[functionname] or 0) + tonumber(localtime) + counts[functionname] = (counts[functionname] or 0) + 1 + end + end + end + f:close() + print("") + local loaded = { } + local sorted = table.sortedkeys(times) + for i=1,#sorted do + local filename = sorted[i] + local functions = times[filename] + local sorted = table.sortedkeys(functions) + for i=1,#sorted do + local functionname = sorted[i] + local totaltime = functions[functionname] + local count = counts[functionname] + totalcount = totalcount + count + if totaltime > timethreshold or count > countthreshold then + totalruntime = totalruntime + totaltime + local functionfile, somenumber = functionname:match("^@(.+):(.-)$") + if functionfile then + local number = tonumber(somenumber) + if number then + if not loaded[functionfile] then + loaded[functionfile] = string.splitlines(io.loaddata(functionfile) or "") + end + functionname = loaded[functionfile][number] or functionname + functionname = functionname:gsub("^%s*","") + functionname = functionname:gsub("%s*%-%-.*$","") + functionname = number .. ": " .. functionname + end + end + filename = file.basename(filename) + print(functiontemplate:format(filename,totaltime,count,functionname)) + end + end + end + print("") + local sorted = table.sortedkeys(calls) + for i=1,#sorted do + local call = sorted[i] + local n = calls[call] + totalcalls = totalcalls + n + if n > callthreshold then + print(calltemplate:format(n,call)) + end + end + print("") + print(totaltemplate:format(totalcalls,totalcount,totalruntime)) + print("") + print(thresholdtemplate:format(callthreshold,countthreshold,timethreshold)) + end +end + +function scripts.profiler.x_analyze(filename) + local f = io.open(filename) + local calls = { } + local lines = 0 + if f then + while true do + local line = f:read() + if line then + lines = lines + 1 + local c = match(line,"\\([a-zA-Z%!%?@]+) *%->") + if c then + local cc = calls[c] + if not cc then + calls[c] = 1 + else + calls[c] = cc + 1 + end + end + else + break + end + end + f:close() + local noc = 0 +local criterium = 100 + for name, n in next, calls do + if n > criterium then + if find(name,"^@@[a-z][a-z]") then + -- parameter + elseif find(name,"^[cvserft]%!") then + -- variables and constants + elseif find(name,"^%?%?[a-z][a-z]$") then + -- prefix + elseif find(name,"^%!%!") then + -- reserved + elseif find(name,"^@.+@$") then + -- weird + else + noc = noc + n + print(format("%6i: %s",n,name)) + end + end + end + print("") + print(format("number of lines: %s",lines)) + print(format("number of calls: %s",noc)) + print(format("criterium calls: %s",criterium)) + end +end + +--~ scripts.profiler.analyze("t:/manuals/mk/mk-fonts-profile.lua") +--~ scripts.profiler.analyze("t:/manuals/mk/mk-introduction-profile.lua") + +if environment.argument("analyze") then + scripts.profiler.analyze(environment.files[1] or "luatex-profile.log") +elseif environment.argument("trace") then + scripts.profiler.analyze(environment.files[1] or "temp.log") +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-rsync.lua b/scripts/context/lua/mtx-rsync.lua index 65f795ee5..1095f2d05 100644 --- a/scripts/context/lua/mtx-rsync.lua +++ b/scripts/context/lua/mtx-rsync.lua @@ -1,189 +1,189 @@ -if not modules then modules = { } end modules ['mtx-rsync'] = { - version = 1.000, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- This is an experimental script that will be extended over time and --- is used by myself. An example or a copy spec: --- --- --- local devdir = "m:/develop/services" --- local orgdir = "m:/pod/m4all" --- --- return { --- { --- origin = { devdir, "framework/scripts/d-dispatchers.lua"}, --- target = { orgdir, "framework/scripts" }, --- }, --- { --- origin = { devdir, "framework/scripts/common/*"}, --- target = { orgdir, "framework/scripts/common" }, --- }, --- { --- origin = { devdir, "framework/scripts/d-buildtool.lua" }, --- target = { orgdir, "framework/scripts" } --- }, --- { --- origin = { devdir, "framework/scripts/buildtool/*"}, --- target = { orgdir, "framework/scripts/buildtool" }, --- }, --- { --- origin = { devdir, "framework/m4all*" }, --- target = { orgdir, "framework" }, --- }, --- { --- origin = { devdir, "framework/configurations/*m4all*"}, --- target = { orgdir, "framework/configurations" }, --- }, --- { --- recurse = true, --- origin = { devdir, "context/tex/texmf-project/tex/context/user/m4all/*" }, --- target = { orgdir, "context/tex/texmf-project/tex/context/user/m4all" }, --- }, --- } - -local helpinfo = [[ - - - - mtx-rsync - Rsync Helpers - 0.10 - - - - - use given file as specification - show what would happen - force run - - - - -]] - -local application = logs.application { - name = "mtx-rsync", - banner = "Rsync Helpers 0.10", - helpinfo = helpinfo, -} - -local format, gsub = string.format, string.gsub -local concat = table.concat - -local report_message = logs.new("rsync message") -local report_dryrun = logs.new("rsync dryrun") -local report_normal = logs.new("rsync normal") -local report_command = logs.new("rsync command") - -local cleanup - -if os.platform == "mswin" then - os.setenv("CYGWIN","nontsec") - cleanup = function(name) - return (gsub(name,"([a-zA-Z]):/", "/cygdrive/%1/")) - end -else - cleanup = function(name) - return name - end -end - -function rsynccommand(dryrun,recurse,origin,target) - local command = "rsync -ptlva " - if dryrun then - command = command .. "-n " - end - if recurse then - command = command .. "-r " - end - return format('%s %s %s',command,origin,target) -end - -scripts = scripts or { } -scripts.rsync = scripts.rsync or { } -local rsync = scripts.rsync - -rsync.mode = "command" - -function rsync.run(origin,target,message,recurse) - if type(origin) == "table" then - origin = concat(origin,"/") - end - if type(target) == "table" then - target = concat(target,"/") - end - origin = cleanup(origin) - target = cleanup(target) - local path = gsub(target,"^/cygdrive/(.)","%1:") - if not lfs.isdir(path) then - report_message("creating target dir %s",path) - dir.makedirs(path) -- as rsync only creates them when --recursive - end - if message then - report_message(message) - end - if rsync.mode == "dryrun" then - local command = rsynccommand(true,recurse,origin,target) - report_dryrun(command.."\n") - os.execute(command) - elseif rsync.mode == "force" then - local command = rsynccommand(false,recurse,origin,target) - report_normal(command.."\n") - os.execute(command) - else - local command = rsynccommand(true,recurse,origin,target) - report_command(command) - end -end - -function rsync.job(list) - if type(list) == "string" and lfs.isfile(list) then - list = dofile(list) - end - if type(list) ~= "table" then - report_message("invalid job specification") - return - end - for i=1,#list do - local li = list[i] - local origin = li.origin - local target = li.target - local message = li.message - local recurse = li.recurse - if origin and #origin > 0 and target and #target > 0 then -- string or table - rsync.run(origin,target,message,recurse) - else - report_message("invalid job specification at index %s",i) - end - end -end - -if environment.ownscript then - -- stand alone -else - report(application.banner) - return rsync -end - -local arguments = environment.arguments -local files = environment.files - -if arguments.dryrun then - rsync.mode = "dryrun" -elseif arguments.force then - rsync.mode = "force" -end - -if arguments.exporthelp then - application.export(arguments.exporthelp,environment.files[1]) -elseif arguments.job then - rsync.job(files[1]) -elseif files[1] and files[2] then - rsync.run(files[1],files[2]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-rsync'] = { + version = 1.000, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This is an experimental script that will be extended over time and +-- is used by myself. An example or a copy spec: +-- +-- +-- local devdir = "m:/develop/services" +-- local orgdir = "m:/pod/m4all" +-- +-- return { +-- { +-- origin = { devdir, "framework/scripts/d-dispatchers.lua"}, +-- target = { orgdir, "framework/scripts" }, +-- }, +-- { +-- origin = { devdir, "framework/scripts/common/*"}, +-- target = { orgdir, "framework/scripts/common" }, +-- }, +-- { +-- origin = { devdir, "framework/scripts/d-buildtool.lua" }, +-- target = { orgdir, "framework/scripts" } +-- }, +-- { +-- origin = { devdir, "framework/scripts/buildtool/*"}, +-- target = { orgdir, "framework/scripts/buildtool" }, +-- }, +-- { +-- origin = { devdir, "framework/m4all*" }, +-- target = { orgdir, "framework" }, +-- }, +-- { +-- origin = { devdir, "framework/configurations/*m4all*"}, +-- target = { orgdir, "framework/configurations" }, +-- }, +-- { +-- recurse = true, +-- origin = { devdir, "context/tex/texmf-project/tex/context/user/m4all/*" }, +-- target = { orgdir, "context/tex/texmf-project/tex/context/user/m4all" }, +-- }, +-- } + +local helpinfo = [[ + + + + mtx-rsync + Rsync Helpers + 0.10 + + + + + use given file as specification + show what would happen + force run + + + + +]] + +local application = logs.application { + name = "mtx-rsync", + banner = "Rsync Helpers 0.10", + helpinfo = helpinfo, +} + +local format, gsub = string.format, string.gsub +local concat = table.concat + +local report_message = logs.new("rsync message") +local report_dryrun = logs.new("rsync dryrun") +local report_normal = logs.new("rsync normal") +local report_command = logs.new("rsync command") + +local cleanup + +if os.platform == "mswin" then + os.setenv("CYGWIN","nontsec") + cleanup = function(name) + return (gsub(name,"([a-zA-Z]):/", "/cygdrive/%1/")) + end +else + cleanup = function(name) + return name + end +end + +function rsynccommand(dryrun,recurse,origin,target) + local command = "rsync -ptlva " + if dryrun then + command = command .. "-n " + end + if recurse then + command = command .. "-r " + end + return format('%s %s %s',command,origin,target) +end + +scripts = scripts or { } +scripts.rsync = scripts.rsync or { } +local rsync = scripts.rsync + +rsync.mode = "command" + +function rsync.run(origin,target,message,recurse) + if type(origin) == "table" then + origin = concat(origin,"/") + end + if type(target) == "table" then + target = concat(target,"/") + end + origin = cleanup(origin) + target = cleanup(target) + local path = gsub(target,"^/cygdrive/(.)","%1:") + if not lfs.isdir(path) then + report_message("creating target dir %s",path) + dir.makedirs(path) -- as rsync only creates them when --recursive + end + if message then + report_message(message) + end + if rsync.mode == "dryrun" then + local command = rsynccommand(true,recurse,origin,target) + report_dryrun(command.."\n") + os.execute(command) + elseif rsync.mode == "force" then + local command = rsynccommand(false,recurse,origin,target) + report_normal(command.."\n") + os.execute(command) + else + local command = rsynccommand(true,recurse,origin,target) + report_command(command) + end +end + +function rsync.job(list) + if type(list) == "string" and lfs.isfile(list) then + list = dofile(list) + end + if type(list) ~= "table" then + report_message("invalid job specification") + return + end + for i=1,#list do + local li = list[i] + local origin = li.origin + local target = li.target + local message = li.message + local recurse = li.recurse + if origin and #origin > 0 and target and #target > 0 then -- string or table + rsync.run(origin,target,message,recurse) + else + report_message("invalid job specification at index %s",i) + end + end +end + +if environment.ownscript then + -- stand alone +else + report(application.banner) + return rsync +end + +local arguments = environment.arguments +local files = environment.files + +if arguments.dryrun then + rsync.mode = "dryrun" +elseif arguments.force then + rsync.mode = "force" +end + +if arguments.exporthelp then + application.export(arguments.exporthelp,environment.files[1]) +elseif arguments.job then + rsync.job(files[1]) +elseif files[1] and files[2] then + rsync.run(files[1],files[2]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-scite.lua b/scripts/context/lua/mtx-scite.lua index 972edbfe6..47aa3d009 100644 --- a/scripts/context/lua/mtx-scite.lua +++ b/scripts/context/lua/mtx-scite.lua @@ -1,259 +1,259 @@ -if not modules then modules = { } end modules ['mtx-scite'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local P, R, S, C, Ct, Cf, Cc, Cg = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cf, lpeg.Cc, lpeg.Cg -local lpegmatch = lpeg.match -local format, lower, gmatch = string.format, string.lower, string.gmatch - -local helpinfo = [[ - - - - mtx-scite - Scite Helper Script - 1.00 - - - - - convert spell-*.txt into spell-*.lua - - - - -]] - -local application = logs.application { - name = "mtx-scite", - banner = "Scite Helper Script 1.00", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.scite = scripts.scite or { } - --- todo: append to global properties else order of loading problem --- linux problem ... files are under root protection so we need --install --- --- local scitesignals = { "scite-context.rme", "context.properties" } --- local screenfont = "lmtypewriter10-regular.ttf" - --- function scripts.scite.start(indeed) --- local usedsignal, datapath, fullname, workname, userpath, fontpath --- if os.type == "windows" then --- workname = "scite.exe" --- userpath = os.getenv("USERPROFILE") or "" --- fontpath = os.getenv("SYSTEMROOT") --- fontpath = (fontpath and file.join(fontpath,"fonts")) or "" --- else --- workname = "scite" --- userpath = os.getenv("HOME") or "" --- fontpath = "" --- end --- local binpaths = file.split_path(os.getenv("PATH")) or file.split_path(os.getenv("path")) --- for i=1,#scitesignals do --- local scitesignal = scitesignals[i] --- local scitepath = resolvers.findfile(scitesignal,"other text files") or "" --- if scitepath ~= "" then --- scitepath = file.dirname(scitepath) -- data --- if scitepath == "" then --- scitepath = resolvers.cleanpath(lfs.currentdir()) --- else --- usedsignal, datapath = scitesignal, scitepath --- break --- end --- end --- end --- if not datapath or datapath == "" then --- report("invalid datapath, maybe you need to regenerate the file database") --- return false --- end --- if not binpaths or #binpaths == 0 then --- report("invalid binpath") --- return false --- end --- for i=1,#binpaths do --- local p = file.join(binpaths[i],workname) --- if lfs.isfile(p) and lfs.attributes(p,"size") > 10000 then -- avoind stub --- fullname = p --- break --- end --- end --- if not fullname then --- report("unable to locate %s",workname) --- return false --- end --- local properties = dir.glob(file.join(datapath,"*.properties")) --- local luafiles = dir.glob(file.join(datapath,"*.lua")) --- local extrafont = resolvers.findfile(screenfont,"truetype font") or "" --- local pragmafound = dir.glob(file.join(datapath,"pragma.properties")) --- if userpath == "" then --- report("unable to figure out userpath") --- return false --- end --- local verbose = environment.argument("verbose") --- local tobecopied, logdata = { }, { } --- local function check_state(fullname,newpath) --- local basename = file.basename(fullname) --- local destination = file.join(newpath,basename) --- local pa, da = lfs.attributes(fullname), lfs.attributes(destination) --- if not da then --- logdata[#logdata+1] = { "new : %s", basename } --- tobecopied[#tobecopied+1] = { fullname, destination } --- elseif pa.modification > da.modification then --- logdata[#logdata+1] = { "outdated : %s", basename } --- tobecopied[#tobecopied+1] = { fullname, destination } --- else --- logdata[#logdata+1] = { "up to date : %s", basename } --- end --- end --- for i=1,#properties do --- check_state(properties[i],userpath) --- end --- for i=1,#luafiles do --- check_state(luafiles[i],userpath) --- end --- if fontpath ~= "" then --- check_state(extrafont,fontpath) --- end --- local userpropfile = "SciTEUser.properties" --- if os.name ~= "windows" then --- userpropfile = "." .. userpropfile --- end --- local fullpropfile = file.join(userpath,userpropfile) --- local userpropdata = io.loaddata(fullpropfile) or "" --- local propfiledone = false --- if pragmafound then --- if userpropdata == "" then --- logdata[#logdata+1] = { "error : no user properties found on '%s'", fullpropfile } --- elseif string.find(userpropdata,"import *pragma") then --- logdata[#logdata+1] = { "up to date : 'import pragma' in '%s'", userpropfile } --- else --- logdata[#logdata+1] = { "yet unset : 'import pragma' in '%s'", userpropfile } --- userproperties = userpropdata .. "\n\nimport pragma\n\n" --- propfiledone = true --- end --- else --- if string.find(userpropdata,"import *context") then --- logdata[#logdata+1] = { "up to date : 'import context' in '%s'", userpropfile } --- else --- logdata[#logdata+1] = { "yet unset : 'import context' in '%s'", userpropfile } --- userproperties = userpropdata .. "\n\nimport context\n\n" --- propfiledone = true --- end --- end --- if not indeed or verbose then --- report("used signal: %s", usedsignal) --- report("data path : %s", datapath) --- report("full name : %s", fullname) --- report("user path : %s", userpath) --- report("extra font : %s", extrafont) --- end --- if #logdata > 0 then --- report("") --- for k=1,#logdata do --- local v = logdata[k] --- report(v[1],v[2]) --- end --- end --- if indeed then --- if #tobecopied > 0 then --- report("warning : copying updated files") --- for i=1,#tobecopied do --- local what = tobecopied[i] --- report("copying : '%s' => '%s'",what[1],what[2]) --- file.copy(what[1],what[2]) --- end --- end --- if propfiledone then --- report("saving : '%s'",userpropfile) --- io.savedata(fullpropfile,userpropdata) --- end --- os.launch(fullname) --- end --- end - --- local splitter = (Cf(Ct("") * (Cg(C(R("az","AZ","\127\255")^1) * Cc(true)) + P(1))^1,rawset) )^0 --- --- local function splitwords(words) --- return lpegmatch(splitter,words) -- or just split and tohash --- end - -local function splitwords(words) - local w = { } - for s in string.gmatch(words,"[a-zA-Z\127-255]+") do - if #s > 2 then -- will become option - w[lower(s)] = s - end - end - return w -end - --- maybe: lowerkey = UpperWhatever - -function scripts.scite.words() - for i=1,#environment.files do - local tag = environment.files[i] - local tag = string.match(tag,"spell%-(..)%.") or tag - local txtname = format("spell-%s.txt",tag) - local luaname = format("spell-%s.lua",tag) - local lucname = format("spell-%s.luc",tag) - if lfs.isfile(txtname) then - report("loading %s",txtname) - local olddata = io.loaddata(txtname) or "" - local words = splitwords(olddata) - local min, max, n = 100, 1, 0 - for k, v in next, words do - local l = #k - if l < min then - min = l - end - if l > max then - max = l - end - n = n + 1 - end - if min > max then - min = max - end - local newdata = { - words = words, - source = oldname, - min = min, - max = max, - n = n, - } - report("saving %q, %s words, %s shortest, %s longest",luaname,n,min,max) - io.savedata(luaname,table.serialize(newdata,true)) - report("compiling %q",lucname) - os.execute(format("luac -s -o %s %s",lucname,luaname)) - else - report("no data file %s",txtname) - end - end - report("you need to move the lua files to lexers/data") -end - --- if environment.argument("start") then --- scripts.scite.start(true) --- elseif environment.argument("test") then --- scripts.scite.start() --- else --- application.help() --- end - -if environment.argument("words") then - scripts.scite.words() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end - +if not modules then modules = { } end modules ['mtx-scite'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local P, R, S, C, Ct, Cf, Cc, Cg = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cf, lpeg.Cc, lpeg.Cg +local lpegmatch = lpeg.match +local format, lower, gmatch = string.format, string.lower, string.gmatch + +local helpinfo = [[ + + + + mtx-scite + Scite Helper Script + 1.00 + + + + + convert spell-*.txt into spell-*.lua + + + + +]] + +local application = logs.application { + name = "mtx-scite", + banner = "Scite Helper Script 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.scite = scripts.scite or { } + +-- todo: append to global properties else order of loading problem +-- linux problem ... files are under root protection so we need --install +-- +-- local scitesignals = { "scite-context.rme", "context.properties" } +-- local screenfont = "lmtypewriter10-regular.ttf" + +-- function scripts.scite.start(indeed) +-- local usedsignal, datapath, fullname, workname, userpath, fontpath +-- if os.type == "windows" then +-- workname = "scite.exe" +-- userpath = os.getenv("USERPROFILE") or "" +-- fontpath = os.getenv("SYSTEMROOT") +-- fontpath = (fontpath and file.join(fontpath,"fonts")) or "" +-- else +-- workname = "scite" +-- userpath = os.getenv("HOME") or "" +-- fontpath = "" +-- end +-- local binpaths = file.split_path(os.getenv("PATH")) or file.split_path(os.getenv("path")) +-- for i=1,#scitesignals do +-- local scitesignal = scitesignals[i] +-- local scitepath = resolvers.findfile(scitesignal,"other text files") or "" +-- if scitepath ~= "" then +-- scitepath = file.dirname(scitepath) -- data +-- if scitepath == "" then +-- scitepath = resolvers.cleanpath(lfs.currentdir()) +-- else +-- usedsignal, datapath = scitesignal, scitepath +-- break +-- end +-- end +-- end +-- if not datapath or datapath == "" then +-- report("invalid datapath, maybe you need to regenerate the file database") +-- return false +-- end +-- if not binpaths or #binpaths == 0 then +-- report("invalid binpath") +-- return false +-- end +-- for i=1,#binpaths do +-- local p = file.join(binpaths[i],workname) +-- if lfs.isfile(p) and lfs.attributes(p,"size") > 10000 then -- avoind stub +-- fullname = p +-- break +-- end +-- end +-- if not fullname then +-- report("unable to locate %s",workname) +-- return false +-- end +-- local properties = dir.glob(file.join(datapath,"*.properties")) +-- local luafiles = dir.glob(file.join(datapath,"*.lua")) +-- local extrafont = resolvers.findfile(screenfont,"truetype font") or "" +-- local pragmafound = dir.glob(file.join(datapath,"pragma.properties")) +-- if userpath == "" then +-- report("unable to figure out userpath") +-- return false +-- end +-- local verbose = environment.argument("verbose") +-- local tobecopied, logdata = { }, { } +-- local function check_state(fullname,newpath) +-- local basename = file.basename(fullname) +-- local destination = file.join(newpath,basename) +-- local pa, da = lfs.attributes(fullname), lfs.attributes(destination) +-- if not da then +-- logdata[#logdata+1] = { "new : %s", basename } +-- tobecopied[#tobecopied+1] = { fullname, destination } +-- elseif pa.modification > da.modification then +-- logdata[#logdata+1] = { "outdated : %s", basename } +-- tobecopied[#tobecopied+1] = { fullname, destination } +-- else +-- logdata[#logdata+1] = { "up to date : %s", basename } +-- end +-- end +-- for i=1,#properties do +-- check_state(properties[i],userpath) +-- end +-- for i=1,#luafiles do +-- check_state(luafiles[i],userpath) +-- end +-- if fontpath ~= "" then +-- check_state(extrafont,fontpath) +-- end +-- local userpropfile = "SciTEUser.properties" +-- if os.name ~= "windows" then +-- userpropfile = "." .. userpropfile +-- end +-- local fullpropfile = file.join(userpath,userpropfile) +-- local userpropdata = io.loaddata(fullpropfile) or "" +-- local propfiledone = false +-- if pragmafound then +-- if userpropdata == "" then +-- logdata[#logdata+1] = { "error : no user properties found on '%s'", fullpropfile } +-- elseif string.find(userpropdata,"import *pragma") then +-- logdata[#logdata+1] = { "up to date : 'import pragma' in '%s'", userpropfile } +-- else +-- logdata[#logdata+1] = { "yet unset : 'import pragma' in '%s'", userpropfile } +-- userproperties = userpropdata .. "\n\nimport pragma\n\n" +-- propfiledone = true +-- end +-- else +-- if string.find(userpropdata,"import *context") then +-- logdata[#logdata+1] = { "up to date : 'import context' in '%s'", userpropfile } +-- else +-- logdata[#logdata+1] = { "yet unset : 'import context' in '%s'", userpropfile } +-- userproperties = userpropdata .. "\n\nimport context\n\n" +-- propfiledone = true +-- end +-- end +-- if not indeed or verbose then +-- report("used signal: %s", usedsignal) +-- report("data path : %s", datapath) +-- report("full name : %s", fullname) +-- report("user path : %s", userpath) +-- report("extra font : %s", extrafont) +-- end +-- if #logdata > 0 then +-- report("") +-- for k=1,#logdata do +-- local v = logdata[k] +-- report(v[1],v[2]) +-- end +-- end +-- if indeed then +-- if #tobecopied > 0 then +-- report("warning : copying updated files") +-- for i=1,#tobecopied do +-- local what = tobecopied[i] +-- report("copying : '%s' => '%s'",what[1],what[2]) +-- file.copy(what[1],what[2]) +-- end +-- end +-- if propfiledone then +-- report("saving : '%s'",userpropfile) +-- io.savedata(fullpropfile,userpropdata) +-- end +-- os.launch(fullname) +-- end +-- end + +-- local splitter = (Cf(Ct("") * (Cg(C(R("az","AZ","\127\255")^1) * Cc(true)) + P(1))^1,rawset) )^0 +-- +-- local function splitwords(words) +-- return lpegmatch(splitter,words) -- or just split and tohash +-- end + +local function splitwords(words) + local w = { } + for s in string.gmatch(words,"[a-zA-Z\127-255]+") do + if #s > 2 then -- will become option + w[lower(s)] = s + end + end + return w +end + +-- maybe: lowerkey = UpperWhatever + +function scripts.scite.words() + for i=1,#environment.files do + local tag = environment.files[i] + local tag = string.match(tag,"spell%-(..)%.") or tag + local txtname = format("spell-%s.txt",tag) + local luaname = format("spell-%s.lua",tag) + local lucname = format("spell-%s.luc",tag) + if lfs.isfile(txtname) then + report("loading %s",txtname) + local olddata = io.loaddata(txtname) or "" + local words = splitwords(olddata) + local min, max, n = 100, 1, 0 + for k, v in next, words do + local l = #k + if l < min then + min = l + end + if l > max then + max = l + end + n = n + 1 + end + if min > max then + min = max + end + local newdata = { + words = words, + source = oldname, + min = min, + max = max, + n = n, + } + report("saving %q, %s words, %s shortest, %s longest",luaname,n,min,max) + io.savedata(luaname,table.serialize(newdata,true)) + report("compiling %q",lucname) + os.execute(format("luac -s -o %s %s",lucname,luaname)) + else + report("no data file %s",txtname) + end + end + report("you need to move the lua files to lexers/data") +end + +-- if environment.argument("start") then +-- scripts.scite.start(true) +-- elseif environment.argument("test") then +-- scripts.scite.start() +-- else +-- application.help() +-- end + +if environment.argument("words") then + scripts.scite.words() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end + diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua index a8d7edf41..cbfc91559 100644 --- a/scripts/context/lua/mtx-server-ctx-fonttest.lua +++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua @@ -1,749 +1,749 @@ -if not modules then modules = { } end modules ['mtx-server-ctx-fonttest'] = { - version = 1.001, - comment = "Font Feature Tester", - author = "Hans Hagen", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- probably too much but who cares - -dofile(resolvers.findfile("trac-lmx.lua","tex")) -dofile(resolvers.findfile("font-ini.lua","tex")) -dofile(resolvers.findfile("font-con.lua","tex")) -dofile(resolvers.findfile("font-oti.lua","tex")) -dofile(resolvers.findfile("font-otf.lua","tex")) -dofile(resolvers.findfile("font-otp.lua","tex")) -dofile(resolvers.findfile("font-ott.lua","tex")) -dofile(resolvers.findfile("font-syn.lua","tex")) -dofile(resolvers.findfile("font-mis.lua","tex")) - -local format, gsub, concat, match, find = string.format, string.gsub, table.concat, string.match, string.find - -local report = logs.reporter("ctx-fonttest") - -local sample_line = "This is a sample line!" -local tempname = "mtx-server-ctx-fonttest-temp" -local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") -local basename = "mtx-server-ctx-fonttest-data.lua" -local basepath = temppath - -local remove_suffixes = { "tex", "pdf", "log" } -local what_options = { "trace", "basemode" } - -for i=1,#remove_suffixes do - os.remove(file.join(temppath,file.addsuffix(tempname,remove_suffixes[i]))) -end - -local process_templates = { } - -process_templates.default = [[ -\starttext - \setupdirections[bidi=global] - \definefontfeature[sample][analyze=yes,%s] - \definedfont[name:%s*sample] - \startTEXpage[offset=3pt] - \detokenize{%s} - \stopTEXpage -\stoptext -]] - -process_templates.cache = [[ -\starttext - \definedfont[name:%s] - \startTEXpage[offset=3pt] - cached: \detokenize{%s} - \stopTEXpage -\stoptext -]] - -process_templates.trace = [[ -\usemodule[fnt-20] - -\definefontfeature[sample][%s] - -\setupcolors[state=start] - -\setupdirections[bidi=global] - -\setvariables - [otftracker] - [title=Test Run, - font=name:%s, - direction=0, - features=sample, - sample={‍\detokenize{%s}}] -]] - -local javascripts = [[ -function selected_radio(name) { - var form = document.forms["main-form"] ; - var script = form.elements[name] ; - if (script) { - var n = script.length ; - if (n) { - for (var i=0; i - safe name     - family name     - style-variant-weight-width     - font name     - weight     - filename -]] - -local template_d = [[ - - %s     - %s     - %s-%s-%s-%s     - %s     - %s     - %s -]] - -local function select_font() - local t = fonts.names.list(".*",false,true) - if t then - local listoffonts = { } - listoffonts[#listoffonts+1] = "" - listoffonts[#listoffonts+1] = template_h - for k, v in table.sortedhash(t) do - local kind = v.format - if kind == "otf" or kind == "ttf" or kind == "ttc" then - local fontname = v.fontname - listoffonts[#listoffonts+1] = format(template_d, fontname, fontname, - v.familyname or "", - t.variant or "normal", - t.weight or "normal", - t.width or "normal", - t.style or "normal", - v.rawname or fontname, - v.fontweight or "", - v.filename or "" - ) - end - end - listoffonts[#listoffonts+1] = "
" - return concat(listoffonts,"\n") - end - return "no fonts" -end - -local edit_template = [[ - -

name:    title:  -

scripts: %s -

languages: %s -

features: %s -

options: %s -]] - --- - -local result_template = [[ -

- -

results: - tex file - pdf file -

-]] - -scripts.webserver.registerpath(temppath) - -local function get_specification(name) - return fonts.names.resolvedspecification(name or "") -end - -local function edit_font(currentfont,detail,tempname) - report("entering edit mode for '%s'",currentfont) - local specification = get_specification(currentfont) - if specification then - local htmldata = showfeatures(specification.filename) - if htmldata then - local features, languages, scripts, options = { }, { }, { }, { } - local sorted = table.sortedkeys(htmldata.scripts) - for k=1,#sorted do - local v = sorted[k] - local s = fonts.handlers.otf.tables.scripts[v] or v - if detail and v == detail.script then - scripts[#scripts+1] = format(" %s",s,v,v,v,v) - else - scripts[#scripts+1] = format(" %s",s,v,v,v,v) - end - end - local sorted = table.sortedkeys(htmldata.languages) - for k=1,#sorted do - local v = sorted[k] - local l = fonts.handlers.otf.tables.languages[v] or v - if detail and v == detail.language then - languages[#languages+1] = format(" %s",l,v,v,v,v) - else - languages[#languages+1] = format(" %s",l,v,v,v,v) - end - end - local sorted = table.sortedkeys(htmldata.features) - for k=1,#sorted do - local v = sorted[k] - local f = fonts.handlers.otf.tables.features[v] or v - if detail and detail["f-"..v] then - features[#features+1] = format(" %s",f,v,v,v,v) - else - features[#features+1] = format(" %s",f,v,v,v,v) - end - end - for k=1,#what_options do - local v = what_options[k] - if detail and detail["o-"..v] then - options[#options+1] = format(" %s",v,v,v) - else - options[#options+1] = format(" %s",v,v,v) - end - end - local e = format(edit_template, - (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "", - concat(scripts," "),concat(languages," "),concat(features," "),concat(options," ")) - if tempname then - local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex") - local r = format(result_template,pdffile,texfile,pdffile) - return e .. r, htmldata.javascript or "" - else - return e, htmldata.javascript or "" - end - else - return "error, nothing set up yet" - end - else - return "error, no info about font" - end -end - -local function process_font(currentfont,detail) -- maybe just fontname - local features = { - "mode=node", - format("language=%s",detail.language or "dflt"), - format("script=%s",detail.script or "dflt"), - } - for k,v in next, detail do - local f = match(k,"^f%-(.*)$") - if f then - features[#features+1] = format("%s=yes",f) - end - end - local variant = process_templates.default - if detail["o-trace"] then - variant = process_templates.trace - end - local sample = string.strip(detail.sampletext or "") - if sample == "" then sample = sample_line end - report("sample text: %s",sample) - dir.mkdirs(temppath) - local fullname = file.join(temppath,file.addsuffix(tempname,"tex")) - local data = format(variant,concat(features,","),currentfont,sample) - local command = format("mtxrun --path=%q --script context --once --batchmode %q",temppath,tempname) - report("filename: %s",fullname) - report("command: %s",command) - io.savedata(fullname,data) - os.execute(command) - return edit_font(currentfont,detail,tempname) -end - -local tex_template = [[ -

-%s
-
-]] - -local function show_source(currentfont,detail) - if tempname and tempname ~= "" then - local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,"tex"))) or "no source yet" - return format(tex_template,data) - else - return "no source file" - end -end - -local function show_log(currentfont,detail) - if tempname and tempname ~= "" then - local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,'log'))) or "no log file yet" - data = gsub(data,"[%s%%]*begin of optionfile.-end of optionfile[%s%%]*","\n") - return format(tex_template,data) - else - return "no log file" - end -end - -local function show_font(currentfont,detail) - local specification = get_specification(currentfont) - local features = fonts.helpers.getfeatures(specification.filename) - local result = { } - result[#result+1] = format("

names

",what) - result[#result+1] = "" - result[#result+1] = format("",currentfont) - result[#result+1] = format("",specification.fontname or "-") - result[#result+1] = format("",specification.fontfile or "-") - result[#result+1] = format("",specification.familyname or "-") - result[#result+1] = format("",specification.fontweight or "-") - result[#result+1] = format("",specification.format or "-") - result[#result+1] = format("",specification.fullname or "-") - result[#result+1] = format("",specification.subfamily or "-") - result[#result+1] = format("",specification.rawname or "-") - result[#result+1] = format("",specification.designsize or "-") - result[#result+1] = format("",specification.minsize or "-") - result[#result+1] = format("",specification.maxsize or "-") - result[#result+1] = format("",specification.style ~= "" and specification.style or "normal") - result[#result+1] = format("",specification.variant ~= "" and specification.variant or "normal") - result[#result+1] = format("",specification.weight ~= "" and specification.weight or "normal") - result[#result+1] = format("",specification.width ~= "" and specification.width or "normal") - result[#result+1] = "
fontname: %s
fullname: %s
filename: %s
familyname: %s
fontweight: %s
format: %s
fullname: %s
subfamily: %s
rawname: %s
designsize: %s
minimumsize:%s
maximumsize:%s
style: %s
variant: %s
weight: %s
width: %s
" - if features then - for what, v in table.sortedhash(features) do - local data = features[what] - if data and next(data) then - result[#result+1] = format("

%s features

",what) - result[#result+1] = "" - result[#result+1] = "" - for f,ff in table.sortedhash(data) do - local done = false - for s, ss in table.sortedhash(ff) do - if s == "*" then s = "all" end - if ss ["*"] then ss["*"] = nil ss.all = true end - if done then - f = "" - else - done = true - end - local title = fonts.handlers.otf.tables.features[f] or "" - result[#result+1] = format("",title,f,s,concat(table.sortedkeys(ss)," ")) - end - end - result[#result+1] = "
featuretag script languages 
%s  %s  %s  %s  
" - end - end - else - result[#result+1] = "

This font has no features." - end - return concat(result,"\n") -end - - -local info_template = [[ -

-version   : %s
-comment   : %s
-author    : %s
-copyright : %s
-
-maillist  : ntg-context at ntg.nl
-webpage   : www.pragma-ade.nl
-wiki      : contextgarden.net
-
-]] - -local function info_about() - local m = modules ['mtx-server-ctx-fonttest'] - return format(info_template,m.version,m.comment,m.author,m.copyright) -end - -local save_template = [[ - the current setup has been saved: -

- - - - - - - - - -
name  %s
title  %s
font  %s
script  %s
language  %s
features  %s
options  %s
sampletext %s
-]] - -local function loadbase() - local datafile = file.join(basepath,basename) - local storage = io.loaddata(datafile) or "" - if storage == "" then - storage = { } - else - report("loading '%s'",datafile) - storage = loadstring(storage) - storage = (storage and storage()) or { } - end - return storage -end - -local function loadstored(detail,currentfont,name) - local storage = loadbase() - storage = storage and storage[name] - if storage then - currentfont = storage.font - detail.script = storage.script or detail.script - detail.language = storage.language or detail.language - detail.title = storage.title or detail.title - detail.sampletext = storage.text or detail.sampletext - detail.name = name or "no name" - for k,v in next, storage.features do - detail["f-"..k] = v - end - for k,v in next, storage.options do - detail["o-"..k] = v - end - end - detail.loadname = nil - return detail, currentfont -end - -local function savebase(storage,name) - local datafile = file.join(basepath,basename) - report("saving '%s' in '%s'",name or "data",datafile) - io.savedata(datafile,table.serialize(storage,true)) -end - -local function deletestored(detail,currentfont,name) - local storage = loadbase() - if storage and name and storage[name] then - report("deleting '%s' from base",name) - storage[name] = nil - savebase(storage) - end - detail.deletename = nil - return detail, "" -end - -local function save_font(currentfont,detail) - local specification = get_specification(currentfont) - local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, "" - if detail then - local htmldata = showfeatures(specification.filename) - script = detail.script or script - language = detail.language or language - text = string.strip(detail.sampletext or text) - name = string.strip(detail.name or name) - title = string.strip(detail.title or title) - for k,v in next, htmldata.features do - if detail["f-"..k] then features[k] = true end - end - for k=1,#what_options do - local v = what_options[k] - if detail["o-"..v] then options[k] = true end - end - end - if name == "" then - name = "no name" - end - local storage = loadbase() - storage[name] = { - font = currentfont, title = title, script = script, language = language, features = features, options = options, text = text, - } - savebase(storage,name) - return format(save_template,name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text) -end - -local function load_font(currentfont) - local datafile = file.join(basepath,basename) - local storage = loadbase(datafile) - local result = {} - result[#result+1] = format("del name font fontname script language features title sampletext ") - for k,v in table.sortedhash(storage) do - local fontname, fontfile = get_specification(v.font) - result[#result+1] = format("x %s %s %s %s %s %s %s %s ", - k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "") - end - if #result == 1 then - return "nothing saved yet" - else - return format("%s
",concat(result,"\n")) - end -end - -local function reset_font(currentfont) - return edit_font(currentfont) -end - -local extras_template = [[ - remake font database (take some time)

-]] - -local function do_extras(detail,currentfont,extra) - return extras_template -end - -local extras = { } - -local function do_extra(detail,currentfont,extra) - local e = extras[extra] - if e then e(detail,currentfont,extra) end - return do_extras(detail,currentfont,extra) -end - -function extras.reload() - local command = "mtxrun --script font --reload" - report("run command: %s",command) - os.execute(command) - return do_extras() -end - - -local status_template = [[ - -]] - -local variables = { - ['color-background-one'] = lmx.get('color-background-green'), - ['color-background-two'] = lmx.get('color-background-blue'), - ['title'] = 'ConTeXt Font Tester', - ['formaction'] = "mtx-server-ctx-fonttest.lua", -} - -function doit(configuration,filename,hashed) - - local start = os.clock() - - local detail = url.query(hashed.query or "") - - local currentfont = detail.currentfont - local action = detail.action - local selection = detail.selection - - local loadname = detail.loadname - local deletename = detail.deletename - local extra = detail.extra - - if loadname and loadname ~= "" then - detail, currentfont = loadstored(detail,currentfont,loadname) - action = "process" - elseif deletename and deletename ~= "" then - detail, currentfont = deletestored(detail,currentfont,deletename) - action = "load" - elseif selection and selection ~= "" then - currentfont = selection - elseif extra and extra ~= "" then - do_extra(detail,currentfont,extra) - action = "extras" - end - - local fontname, fontfile = get_specification(currentfont) - - if fontfile then - variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) - else - variables.title = 'ConTeXt Font Tester' - end - - -- lua table and adapt - - local buttons = { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} - local menu = { } - - for i=1,#buttons do - local button = buttons[i] - menu[#menu+1] = format("",button,button) - end - - variables.menu = concat(menu," ") - variables.status = format(status_template,currentfont or "") - variables.maintext = "" - variables.javascriptdata = "" - variables.javascripts = "" - variables.javascriptinit = "" - - report("action: %s",action or "no action") - - local result - - if action == "select" then - variables.maintext = select_font() - elseif action == "info" then - variables.maintext = info_about() - elseif action == "extras" then - variables.maintext = do_extras() - elseif currentfont and currentfont ~= "" then - if action == "save" then - variables.maintext = save_font(currentfont,detail) - elseif action == "load" then - variables.maintext = load_font(currentfont,detail) - elseif action == "source" then - variables.maintext = show_source(currentfont,detail) - elseif action == "log" then - variables.maintext = show_log(currentfont,detail) - elseif action == "features" then - variables.maintext = show_font(currentfont,detail) - else - local e, s - if action == "process" then - e, s = process_font(currentfont,detail) - elseif action == "reset" then - e, s = reset_font(currentfont) - elseif action == "edit" then - e, s = edit_font(currentfont,detail) - else - e, s = process_font(currentfont,detail) - end - variables.maintext = e - variables.javascriptdata = s - variables.javascripts = javascripts - variables.javascriptinit = "check_form()" - end - else - variables.maintext = select_font() - end - - result = { content = lmx.convert('context-fonttest.lmx',false,variables) } - - report("time spent on page: %0.03f seconds",os.clock()-start) - - return result - -end - -return doit, true - ---~ make_lmx_page("test") +if not modules then modules = { } end modules ['mtx-server-ctx-fonttest'] = { + version = 1.001, + comment = "Font Feature Tester", + author = "Hans Hagen", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- probably too much but who cares + +dofile(resolvers.findfile("trac-lmx.lua","tex")) +dofile(resolvers.findfile("font-ini.lua","tex")) +dofile(resolvers.findfile("font-con.lua","tex")) +dofile(resolvers.findfile("font-oti.lua","tex")) +dofile(resolvers.findfile("font-otf.lua","tex")) +dofile(resolvers.findfile("font-otp.lua","tex")) +dofile(resolvers.findfile("font-ott.lua","tex")) +dofile(resolvers.findfile("font-syn.lua","tex")) +dofile(resolvers.findfile("font-mis.lua","tex")) + +local format, gsub, concat, match, find = string.format, string.gsub, table.concat, string.match, string.find + +local report = logs.reporter("ctx-fonttest") + +local sample_line = "This is a sample line!" +local tempname = "mtx-server-ctx-fonttest-temp" +local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") +local basename = "mtx-server-ctx-fonttest-data.lua" +local basepath = temppath + +local remove_suffixes = { "tex", "pdf", "log" } +local what_options = { "trace", "basemode" } + +for i=1,#remove_suffixes do + os.remove(file.join(temppath,file.addsuffix(tempname,remove_suffixes[i]))) +end + +local process_templates = { } + +process_templates.default = [[ +\starttext + \setupdirections[bidi=global] + \definefontfeature[sample][analyze=yes,%s] + \definedfont[name:%s*sample] + \startTEXpage[offset=3pt] + \detokenize{%s} + \stopTEXpage +\stoptext +]] + +process_templates.cache = [[ +\starttext + \definedfont[name:%s] + \startTEXpage[offset=3pt] + cached: \detokenize{%s} + \stopTEXpage +\stoptext +]] + +process_templates.trace = [[ +\usemodule[fnt-20] + +\definefontfeature[sample][%s] + +\setupcolors[state=start] + +\setupdirections[bidi=global] + +\setvariables + [otftracker] + [title=Test Run, + font=name:%s, + direction=0, + features=sample, + sample={‍\detokenize{%s}}] +]] + +local javascripts = [[ +function selected_radio(name) { + var form = document.forms["main-form"] ; + var script = form.elements[name] ; + if (script) { + var n = script.length ; + if (n) { + for (var i=0; i + safe name     + family name     + style-variant-weight-width     + font name     + weight     + filename +]] + +local template_d = [[ + + %s     + %s     + %s-%s-%s-%s     + %s     + %s     + %s +]] + +local function select_font() + local t = fonts.names.list(".*",false,true) + if t then + local listoffonts = { } + listoffonts[#listoffonts+1] = "" + listoffonts[#listoffonts+1] = template_h + for k, v in table.sortedhash(t) do + local kind = v.format + if kind == "otf" or kind == "ttf" or kind == "ttc" then + local fontname = v.fontname + listoffonts[#listoffonts+1] = format(template_d, fontname, fontname, + v.familyname or "", + t.variant or "normal", + t.weight or "normal", + t.width or "normal", + t.style or "normal", + v.rawname or fontname, + v.fontweight or "", + v.filename or "" + ) + end + end + listoffonts[#listoffonts+1] = "
" + return concat(listoffonts,"\n") + end + return "no fonts" +end + +local edit_template = [[ + +

name:    title:  +

scripts: %s +

languages: %s +

features: %s +

options: %s +]] + +-- + +local result_template = [[ +

+ +

results: + tex file + pdf file +

+]] + +scripts.webserver.registerpath(temppath) + +local function get_specification(name) + return fonts.names.resolvedspecification(name or "") +end + +local function edit_font(currentfont,detail,tempname) + report("entering edit mode for '%s'",currentfont) + local specification = get_specification(currentfont) + if specification then + local htmldata = showfeatures(specification.filename) + if htmldata then + local features, languages, scripts, options = { }, { }, { }, { } + local sorted = table.sortedkeys(htmldata.scripts) + for k=1,#sorted do + local v = sorted[k] + local s = fonts.handlers.otf.tables.scripts[v] or v + if detail and v == detail.script then + scripts[#scripts+1] = format(" %s",s,v,v,v,v) + else + scripts[#scripts+1] = format(" %s",s,v,v,v,v) + end + end + local sorted = table.sortedkeys(htmldata.languages) + for k=1,#sorted do + local v = sorted[k] + local l = fonts.handlers.otf.tables.languages[v] or v + if detail and v == detail.language then + languages[#languages+1] = format(" %s",l,v,v,v,v) + else + languages[#languages+1] = format(" %s",l,v,v,v,v) + end + end + local sorted = table.sortedkeys(htmldata.features) + for k=1,#sorted do + local v = sorted[k] + local f = fonts.handlers.otf.tables.features[v] or v + if detail and detail["f-"..v] then + features[#features+1] = format(" %s",f,v,v,v,v) + else + features[#features+1] = format(" %s",f,v,v,v,v) + end + end + for k=1,#what_options do + local v = what_options[k] + if detail and detail["o-"..v] then + options[#options+1] = format(" %s",v,v,v) + else + options[#options+1] = format(" %s",v,v,v) + end + end + local e = format(edit_template, + (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "", + concat(scripts," "),concat(languages," "),concat(features," "),concat(options," ")) + if tempname then + local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex") + local r = format(result_template,pdffile,texfile,pdffile) + return e .. r, htmldata.javascript or "" + else + return e, htmldata.javascript or "" + end + else + return "error, nothing set up yet" + end + else + return "error, no info about font" + end +end + +local function process_font(currentfont,detail) -- maybe just fontname + local features = { + "mode=node", + format("language=%s",detail.language or "dflt"), + format("script=%s",detail.script or "dflt"), + } + for k,v in next, detail do + local f = match(k,"^f%-(.*)$") + if f then + features[#features+1] = format("%s=yes",f) + end + end + local variant = process_templates.default + if detail["o-trace"] then + variant = process_templates.trace + end + local sample = string.strip(detail.sampletext or "") + if sample == "" then sample = sample_line end + report("sample text: %s",sample) + dir.mkdirs(temppath) + local fullname = file.join(temppath,file.addsuffix(tempname,"tex")) + local data = format(variant,concat(features,","),currentfont,sample) + local command = format("mtxrun --path=%q --script context --once --batchmode %q",temppath,tempname) + report("filename: %s",fullname) + report("command: %s",command) + io.savedata(fullname,data) + os.execute(command) + return edit_font(currentfont,detail,tempname) +end + +local tex_template = [[ +

+%s
+
+]] + +local function show_source(currentfont,detail) + if tempname and tempname ~= "" then + local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,"tex"))) or "no source yet" + return format(tex_template,data) + else + return "no source file" + end +end + +local function show_log(currentfont,detail) + if tempname and tempname ~= "" then + local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,'log'))) or "no log file yet" + data = gsub(data,"[%s%%]*begin of optionfile.-end of optionfile[%s%%]*","\n") + return format(tex_template,data) + else + return "no log file" + end +end + +local function show_font(currentfont,detail) + local specification = get_specification(currentfont) + local features = fonts.helpers.getfeatures(specification.filename) + local result = { } + result[#result+1] = format("

names

",what) + result[#result+1] = "" + result[#result+1] = format("",currentfont) + result[#result+1] = format("",specification.fontname or "-") + result[#result+1] = format("",specification.fontfile or "-") + result[#result+1] = format("",specification.familyname or "-") + result[#result+1] = format("",specification.fontweight or "-") + result[#result+1] = format("",specification.format or "-") + result[#result+1] = format("",specification.fullname or "-") + result[#result+1] = format("",specification.subfamily or "-") + result[#result+1] = format("",specification.rawname or "-") + result[#result+1] = format("",specification.designsize or "-") + result[#result+1] = format("",specification.minsize or "-") + result[#result+1] = format("",specification.maxsize or "-") + result[#result+1] = format("",specification.style ~= "" and specification.style or "normal") + result[#result+1] = format("",specification.variant ~= "" and specification.variant or "normal") + result[#result+1] = format("",specification.weight ~= "" and specification.weight or "normal") + result[#result+1] = format("",specification.width ~= "" and specification.width or "normal") + result[#result+1] = "
fontname: %s
fullname: %s
filename: %s
familyname: %s
fontweight: %s
format: %s
fullname: %s
subfamily: %s
rawname: %s
designsize: %s
minimumsize:%s
maximumsize:%s
style: %s
variant: %s
weight: %s
width: %s
" + if features then + for what, v in table.sortedhash(features) do + local data = features[what] + if data and next(data) then + result[#result+1] = format("

%s features

",what) + result[#result+1] = "" + result[#result+1] = "" + for f,ff in table.sortedhash(data) do + local done = false + for s, ss in table.sortedhash(ff) do + if s == "*" then s = "all" end + if ss ["*"] then ss["*"] = nil ss.all = true end + if done then + f = "" + else + done = true + end + local title = fonts.handlers.otf.tables.features[f] or "" + result[#result+1] = format("",title,f,s,concat(table.sortedkeys(ss)," ")) + end + end + result[#result+1] = "
featuretag script languages 
%s  %s  %s  %s  
" + end + end + else + result[#result+1] = "

This font has no features." + end + return concat(result,"\n") +end + + +local info_template = [[ +

+version   : %s
+comment   : %s
+author    : %s
+copyright : %s
+
+maillist  : ntg-context at ntg.nl
+webpage   : www.pragma-ade.nl
+wiki      : contextgarden.net
+
+]] + +local function info_about() + local m = modules ['mtx-server-ctx-fonttest'] + return format(info_template,m.version,m.comment,m.author,m.copyright) +end + +local save_template = [[ + the current setup has been saved: +

+ + + + + + + + + +
name  %s
title  %s
font  %s
script  %s
language  %s
features  %s
options  %s
sampletext %s
+]] + +local function loadbase() + local datafile = file.join(basepath,basename) + local storage = io.loaddata(datafile) or "" + if storage == "" then + storage = { } + else + report("loading '%s'",datafile) + storage = loadstring(storage) + storage = (storage and storage()) or { } + end + return storage +end + +local function loadstored(detail,currentfont,name) + local storage = loadbase() + storage = storage and storage[name] + if storage then + currentfont = storage.font + detail.script = storage.script or detail.script + detail.language = storage.language or detail.language + detail.title = storage.title or detail.title + detail.sampletext = storage.text or detail.sampletext + detail.name = name or "no name" + for k,v in next, storage.features do + detail["f-"..k] = v + end + for k,v in next, storage.options do + detail["o-"..k] = v + end + end + detail.loadname = nil + return detail, currentfont +end + +local function savebase(storage,name) + local datafile = file.join(basepath,basename) + report("saving '%s' in '%s'",name or "data",datafile) + io.savedata(datafile,table.serialize(storage,true)) +end + +local function deletestored(detail,currentfont,name) + local storage = loadbase() + if storage and name and storage[name] then + report("deleting '%s' from base",name) + storage[name] = nil + savebase(storage) + end + detail.deletename = nil + return detail, "" +end + +local function save_font(currentfont,detail) + local specification = get_specification(currentfont) + local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, "" + if detail then + local htmldata = showfeatures(specification.filename) + script = detail.script or script + language = detail.language or language + text = string.strip(detail.sampletext or text) + name = string.strip(detail.name or name) + title = string.strip(detail.title or title) + for k,v in next, htmldata.features do + if detail["f-"..k] then features[k] = true end + end + for k=1,#what_options do + local v = what_options[k] + if detail["o-"..v] then options[k] = true end + end + end + if name == "" then + name = "no name" + end + local storage = loadbase() + storage[name] = { + font = currentfont, title = title, script = script, language = language, features = features, options = options, text = text, + } + savebase(storage,name) + return format(save_template,name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text) +end + +local function load_font(currentfont) + local datafile = file.join(basepath,basename) + local storage = loadbase(datafile) + local result = {} + result[#result+1] = format("del name font fontname script language features title sampletext ") + for k,v in table.sortedhash(storage) do + local fontname, fontfile = get_specification(v.font) + result[#result+1] = format("x %s %s %s %s %s %s %s %s ", + k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "") + end + if #result == 1 then + return "nothing saved yet" + else + return format("%s
",concat(result,"\n")) + end +end + +local function reset_font(currentfont) + return edit_font(currentfont) +end + +local extras_template = [[ + remake font database (take some time)

+]] + +local function do_extras(detail,currentfont,extra) + return extras_template +end + +local extras = { } + +local function do_extra(detail,currentfont,extra) + local e = extras[extra] + if e then e(detail,currentfont,extra) end + return do_extras(detail,currentfont,extra) +end + +function extras.reload() + local command = "mtxrun --script font --reload" + report("run command: %s",command) + os.execute(command) + return do_extras() +end + + +local status_template = [[ + +]] + +local variables = { + ['color-background-one'] = lmx.get('color-background-green'), + ['color-background-two'] = lmx.get('color-background-blue'), + ['title'] = 'ConTeXt Font Tester', + ['formaction'] = "mtx-server-ctx-fonttest.lua", +} + +function doit(configuration,filename,hashed) + + local start = os.clock() + + local detail = url.query(hashed.query or "") + + local currentfont = detail.currentfont + local action = detail.action + local selection = detail.selection + + local loadname = detail.loadname + local deletename = detail.deletename + local extra = detail.extra + + if loadname and loadname ~= "" then + detail, currentfont = loadstored(detail,currentfont,loadname) + action = "process" + elseif deletename and deletename ~= "" then + detail, currentfont = deletestored(detail,currentfont,deletename) + action = "load" + elseif selection and selection ~= "" then + currentfont = selection + elseif extra and extra ~= "" then + do_extra(detail,currentfont,extra) + action = "extras" + end + + local fontname, fontfile = get_specification(currentfont) + + if fontfile then + variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) + else + variables.title = 'ConTeXt Font Tester' + end + + -- lua table and adapt + + local buttons = { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} + local menu = { } + + for i=1,#buttons do + local button = buttons[i] + menu[#menu+1] = format("",button,button) + end + + variables.menu = concat(menu," ") + variables.status = format(status_template,currentfont or "") + variables.maintext = "" + variables.javascriptdata = "" + variables.javascripts = "" + variables.javascriptinit = "" + + report("action: %s",action or "no action") + + local result + + if action == "select" then + variables.maintext = select_font() + elseif action == "info" then + variables.maintext = info_about() + elseif action == "extras" then + variables.maintext = do_extras() + elseif currentfont and currentfont ~= "" then + if action == "save" then + variables.maintext = save_font(currentfont,detail) + elseif action == "load" then + variables.maintext = load_font(currentfont,detail) + elseif action == "source" then + variables.maintext = show_source(currentfont,detail) + elseif action == "log" then + variables.maintext = show_log(currentfont,detail) + elseif action == "features" then + variables.maintext = show_font(currentfont,detail) + else + local e, s + if action == "process" then + e, s = process_font(currentfont,detail) + elseif action == "reset" then + e, s = reset_font(currentfont) + elseif action == "edit" then + e, s = edit_font(currentfont,detail) + else + e, s = process_font(currentfont,detail) + end + variables.maintext = e + variables.javascriptdata = s + variables.javascripts = javascripts + variables.javascriptinit = "check_form()" + end + else + variables.maintext = select_font() + end + + result = { content = lmx.convert('context-fonttest.lmx',false,variables) } + + report("time spent on page: %0.03f seconds",os.clock()-start) + + return result + +end + +return doit, true + +--~ make_lmx_page("test") diff --git a/scripts/context/lua/mtx-server-ctx-help.lua b/scripts/context/lua/mtx-server-ctx-help.lua index b8dc0dfb2..f0901150a 100644 --- a/scripts/context/lua/mtx-server-ctx-help.lua +++ b/scripts/context/lua/mtx-server-ctx-help.lua @@ -1,705 +1,705 @@ -if not modules then modules = { } end modules ['mtx-server-ctx-help'] = { - version = 1.001, - comment = "Basic Definition Browser", - author = "Hans Hagen", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo in lua interface: noargument, oneargument, twoarguments, threearguments --- todo: pickup translations from mult file - -dofile(resolvers.findfile("trac-lmx.lua","tex")) - --- problem ... serialize parent stack - -local format, match, gsub, find = string.format, string.match, string.gsub, string.find -local concat = table.concat - -local report = logs.reporter("ctx-help") - --- -- -- make this a module: cont-xx.lua - -document = document or { } -document.setups = document.setups or { } - -document.setups.div = { - pe = "
%s
" -} - -document.setups.span = { - pe = "%s" -} - -document.setups.translations = document.setups.translations or { - - nl = { - ["title"] = "setup", - ["formula"] = "formule", - ["number"] = "getal", - ["list"] = "lijst", - ["dimension"] = "maat", - ["mark"] = "markering", - ["reference"] = "verwijzing", - ["command"] = "commando", - ["file"] = "file", - ["name"] = "naam", - ["identifier"] = "naam", - ["text"] = "tekst", - ["section"] = "sectie", - ["singular"] = "naam enkelvoud", - ["plural"] = "naam meervoud", - ["matrix"] = "n*m", - ["see"] = "zie", - ["inherits"] = "erft van", - ["optional"] = "optioneel", - ["displaymath"] = "formule", - ["index"] = "ingang", - ["math"] = "formule", - ["nothing"] = "leeg", - ["file"] = "file", - ["position"] = "positie", - ["reference"] = "verwijzing", - ["csname"] = "naam", - ["destination"] = "bestemming", - ["triplet"] = "triplet", - ["word"] = "woord", - ["content"] = "tekst", - }, - - en = { - ["title"] = "setup", - ["formula"] = "formula", - ["number"] = "number", - ["list"] = "list", - ["dimension"] = "dimension", - ["mark"] = "mark", - ["reference"] = "reference", - ["command"] = "command", - ["file"] = "file", - ["name"] = "name", - ["identifier"] = "identifier", - ["text"] = "text", - ["section"] = "section", - ["singular"] = "singular name", - ["plural"] = "plural name", - ["matrix"] = "n*m", - ["see"] = "see", - ["inherits"] = "inherits from", - ["optional"] = "optional", - ["displaymath"] = "formula", - ["index"] = "entry", - ["math"] = "formula", - ["nothing"] = "empty", - ["file"] = "file", - ["position"] = "position", - ["reference"] = "reference", - ["csname"] = "name", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "word", - ["content"] = "text", - - ["noargument"] = "\\cs", - ["oneargument"] = "\\cs#1{..}", - ["twoarguments"] = "\\cs#1#2{..}{..}", - ["threearguments"] = "\\cs#1#2#3{..}{..}{..}", - - }, - - de = { - ["title"] = "Setup", - ["formula"] = "Formel", - ["number"] = "Nummer", - ["list"] = "Liste", - ["dimension"] = "Dimension", - ["mark"] = "Beschriftung", - ["reference"] = "Referenz", - ["command"] = "Befehl", - ["file"] = "Datei", - ["name"] = "Name", - ["identifier"] = "Name", - ["text"] = "Text", - ["section"] = "Abschnitt", - ["singular"] = "singular", - ["plural"] = "plural", - ["matrix"] = "n*m", - ["see"] = "siehe", - ["inherits"] = "inherits from", - ["optional"] = "optioneel", - ["displaymath"] = "formula", - ["index"] = "entry", - ["math"] = "formula", - ["nothing"] = "empty", - ["file"] = "file", - ["position"] = "position", - ["reference"] = "reference", - ["csname"] = "name", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "word", - ["content"] = "text", - }, - - cz = { - ["title"] = "setup", - ["formula"] = "rovnice", - ["number"] = "cislo", - ["list"] = "seznam", - ["dimension"] = "dimenze", - ["mark"] = "znacka", - ["reference"] = "reference", - ["command"] = "prikaz", - ["file"] = "soubor", - ["name"] = "jmeno", - ["identifier"] = "jmeno", - ["text"] = "text", - ["section"] = "sekce", - ["singular"] = "jmeno v singularu", - ["plural"] = "jmeno v pluralu", - ["matrix"] = "n*m", - ["see"] = "viz", - ["inherits"] = "inherits from", - ["optional"] = "optioneel", - ["displaymath"] = "formula", - ["index"] = "entry", - ["math"] = "formula", - ["nothing"] = "empty", - ["file"] = "file", - ["position"] = "position", - ["reference"] = "reference", - ["csname"] = "name", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "word", - ["content"] = "text", - }, - - it = { - ["title"] = "setup", - ["formula"] = "formula", - ["number"] = "number", - ["list"] = "list", - ["dimension"] = "dimension", - ["mark"] = "mark", - ["reference"] = "reference", - ["command"] = "command", - ["file"] = "file", - ["name"] = "name", - ["identifier"] = "name", - ["text"] = "text", - ["section"] = "section", - ["singular"] = "singular name", - ["plural"] = "plural name", - ["matrix"] = "n*m", - ["see"] = "see", - ["inherits"] = "inherits from", - ["optional"] = "optioneel", - ["displaymath"] = "formula", - ["index"] = "entry", - ["math"] = "formula", - ["nothing"] = "empty", - ["file"] = "file", - ["position"] = "position", - ["reference"] = "reference", - ["csname"] = "name", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "word", - ["content"] = "text", - }, - - ro = { - ["title"] = "setari", - ["formula"] = "formula", - ["number"] = "numar", - ["list"] = "lista", - ["dimension"] = "dimensiune", - ["mark"] = "marcaj", - ["reference"] = "referinta", - ["command"] = "comanda", - ["file"] = "fisier", - ["name"] = "nume", - ["identifier"] = "nume", - ["text"] = "text", - ["section"] = "sectiune", - ["singular"] = "nume singular", - ["plural"] = "nume pluram", - ["matrix"] = "n*m", - ["see"] = "vezi", - ["inherits"] = "inherits from", - ["optional"] = "optioneel", - ["displaymath"] = "formula", - ["index"] = "entry", - ["math"] = "formula", - ["nothing"] = "empty", - ["file"] = "file", - ["position"] = "position", - ["reference"] = "reference", - ["csname"] = "name", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "word", - ["content"] = "text", - }, - - fr = { - ["title"] = "réglage", - ["formula"] = "formule", - ["number"] = "numéro", - ["list"] = "liste", - ["dimension"] = "dimension", - ["mark"] = "marquage", - ["reference"] = "reference", - ["command"] = "commande", - ["file"] = "fichier", - ["name"] = "nom", - ["identifier"] = "identificateur", - ["text"] = "texte", - ["section"] = "section", - ["singular"] = "nom singulier", - ["plural"] = "nom pluriel", - ["matrix"] = "n*m", - ["see"] = "vois", - ["inherits"] = "herite de", - ["optional"] = "optionel", - ["displaymath"] = "formule", - ["index"] = "entrée", - ["math"] = "formule", - ["nothing"] = "vide", - ["file"] = "fichier", - ["position"] = "position", - ["reference"] = "réference", - ["csname"] = "nom", - ["destination"] = "destination", - ["triplet"] = "triplet", - ["word"] = "mot", - ["content"] = "texte", - } - -} - -document.setups.formats = { - open_command = { - tex = [[\%s]], - lua = [[context.%s (]], - }, - close_command = { - tex = [[]], - lua = [[ )]], - }, - connector = { - tex = [[]], - lua = [[, ]], - }, - href_in_list = { - tex = [[%s]], - lua = [[%s]], - }, - href_as_command = { - tex = [[\%s]], - lua = [[context.%s]], - }, - modes = { - tex = [[lua mode]], - lua = [[tex mode]], - }, - optional_single = { - tex = "[optional string %s]", - lua = "{optional string %s}", - }, - optional_list = { - tex = "[optional list %s]", - lua = "{optional table %s}" , - } , - mandate_single = { - tex = "[mandate string %s]", - lua = "{mandate string %s}", - }, - mandate_list = { - tex = "[mandate list %s]", - lua = "{mandate list %s}", - }, - interface = [[%s]], - source = [[%s]], - parameter = [[%s%s%s]], - parameters = [[%s
]], - listing = [[
%s]],
-    special         = [[%s]],
-    default         = [[%s]],
-}
-
-local function translate(tag,int,noformat)
-    local t = document.setups.translations
-    local te = t["en"]
-    local ti = t[int] or te
-    if noformat then
-        return ti[tag] or te[tag] or tag
-    else
-        return format(document.setups.formats.special,ti[tag] or te[tag] or tag)
-    end
-end
-
-local function translated(e,int)
-    local attributes = e.at
-    local s = attributes.type or "?"
-    local tag = match(s,"^cd:(.*)$")
-    if attributes.default == "yes" then
-        return format(document.setups.formats.default,tag or "?")
-    elseif tag then
-        return translate(tag,int)
-    else
-        return s
-    end
-end
-
-document.setups.loaded = document.setups.loaded or { }
-
-document.setups.current = { }
-document.setups.showsources = true
-document.setups.mode = "tex"
-
-function document.setups.load(filename)
-    filename = resolvers.findfile(filename) or ""
-    if filename ~= "" then
-        local current = document.setups.loaded[filename]
-        if not current then
-            local loaded = xml.load(filename)
-            if loaded then
-                -- xml.inject(document.setups.root,"/",loaded)
-                current = {
-                    file = filename,
-                    root = loaded,
-                    names = { },
-                    used = { },
-                }
-                document.setups.loaded[filename] = current
-            end
-        end
-        document.setups.current = current or { }
-    end
-end
-
-function document.setups.name(ek)
-    local at = ek.at
-    local name = at.name
-    if at.type == 'environment' then
-        name = "start" .. name
-    end
-    if at.variant then
-        name = name .. ":" .. at.variant
-    end
-    if at.generated == "yes" then
-        name = name .. "*"
-    end
-    return name:lower()
-end
-
-function document.setups.csname(ek,int)
-    local cs = ""
-    local at = ek.at or { }
-    if at.type == 'environment' then
-        cs = translate("start",int,true) .. cs
-    end
-    for e in xml.collected(ek,'cd:sequence/(cd:string|variable)') do
-        if e.tg == "string" then
-            cs = cs .. e.at.value
-        else
-            cs = cs .. e.at.value -- to be translated
-        end
-    end
-    return cs
-end
-
-function document.setups.names()
-    local current = document.setups.current
-    local names = current.names
-    if not names or #names == 0 then
-        names = { }
-        local name = document.setups.name
-        local csname = document.setups.csname
-        for e in xml.collected(current.root,'cd:command') do
-            names[#names+1] = { e.at.name, csname(e,int) }
-        end
-        table.sort(names, function(a,b) return a[2]:lower() < b[2]:lower() end)
-        current.names = names
-    end
-    return names
-end
-
-function document.setups.show(name)
-    local current = document.setups.current
-    if current.root then
-        local name = gsub(name,"[<>]","")
-        local setup = xml.first(current.root,"cd:command[@name='" .. name .. "']")
-        current.used[#current.used+1] = setup
-        xml.sprint(setup)
-    end
-end
-
-function document.setups.showused()
-    local current = document.setups.current
-    if current.root and next(current.used) then
-        local sorted = table.sortedkeys(current.used)
-        for i=1,#sorted do
-            xml.sprint(current.used[sorted[i]])
-        end
-    end
-end
-function document.setups.showall()
-    local current = document.setups.current
-    if current.root then
-        local list = { }
-        for e in xml.collected(current.root,"cd:command") do
-            list[document.setups.name(e)] = e
-        end
-        local sorted = table.sortedkeys(list)
-        for i=1,#sorted do
-            xml.sprint(list[sorted[i]])
-        end
-    end
-end
-function document.setups.resolve(name)
-    local current = document.setups.current
-    if current.root then
-        local e = xml.filter(current.root,format("cd:define[@name='%s']/text()",name))
-        if e then
-            xml.sprint(e)
-        end
-    end
-end
-
-function document.setups.collect(name,int,lastmode)
-    local current = document.setups.current
-    local formats = document.setups.formats
-    local command = xml.filter(current.root,format("cd:command[@name='%s']/first()",name))
-    if command then
-        local attributes = command.at or { }
-        local data = {
-            command = command,
-            category = attributes.category or "",
-        }
-        if document.setups.showsources then
-            data.source = (attributes.file and format(formats.source,attributes.file,lastmode,attributes.file)) or ""
-        else
-            data.source = attributes.file or ""
-        end
-        local n, sequence, tags = 0, { }, { }
-        sequence[#sequence+1] = format(formats.open_command[lastmode],document.setups.csname(command,int))
-        local arguments, tag = { }, ""
-        for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
-            n = n + 1
-            local attributes = d[k].at
-            if #sequence > 1 then
-                local c = formats.connector[lastmode]
-                if c ~= "" then
-                    sequence[#sequence+1] = c
-                end
-            end
-            if attributes.optional == 'yes' then
-                if attributes.list == 'yes' then
-                    tag = format(formats.optional_list[lastmode],n)
-                else
-                    tag = format(formats.optional_single[lastmode],n)
-                end
-            else
-                if attributes.list == 'yes' then
-                    tag = format(formats.mandate_list[lastmode],n)
-                else
-                    tag = format(formats.mandate_single[lastmode],n)
-                end
-            end
-            sequence[#sequence+1] = tag
-            tags[#tags+1] = tag
-        end
-        sequence[#sequence+1] = formats.close_command[lastmode]
-        data.sequence = concat(sequence, " ")
-        local parameters, n = { }, 0
-        for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
-            n = n + 1
-            if d[k].tg == "keywords" then
-                local left = tags[n]
-                local right = { }
-                for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do
-                    local tag = d[k].tg
-                    if tag == "resolve" then
-                        local name = d[k].at.name or ""
-                        if name ~= "" then
-                            local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name))
-                            for r, d, k in xml.elements(resolved,"cd:constant") do
-                                right[#right+1] = translated(d[k],int)
-                            end
-                        end
-                    else
-                        right[#right+1] = translated(d[k],int)
-                    end
-                end
-                parameters[#parameters+1] = format(formats.parameter,left,"",concat(right, ", "))
-            else
-                local what = tags[n]
-                for r, d, k in xml.elements(d[k],"(cd:parameter|cd:inherit)") do
-                    local tag = d[k].tg
-                    local left, right = d[k].at.name or "?", { }
-                    if tag == "inherit" then
-                        local name = d[k].at.name or "?"
-                        local goto = format(document.setups.formats.href_as_command[lastmode],name,lastmode,name)
-                        if #parameters > 0 and not find(parameters[#parameters],"
") then - parameters[#parameters+1] = format(formats.parameter,"
","","") - end - parameters[#parameters+1] = format(formats.parameter,what,format(formats.special,translate("inherits",int)),goto) - else - for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do - local tag = d[k].tg - if tag == "resolve" then - local name = d[k].at.name or "" - if name ~= "" then - local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name)) - for r, d, k in xml.elements(resolved,"cd:constant") do - right[#right+1] = translated(d[k],int) - end - end - else - right[#right+1] = translated(d[k],int) - end - end - parameters[#parameters+1] = format(formats.parameter,what,left,concat(right, ", ")) - end - what = "" - end - end - parameters[#parameters+1] = format(formats.parameter,"
","","") - end - data.parameters = parameters or { } - data.mode = formats.modes[lastmode or "tex"] - return data - else - return nil - end -end - --- -- -- - -tex = tex or { } - --- -- -- - -local interfaces = { - czech = 'cz', - dutch = 'nl', - english = 'en', - french = 'fr', - german = 'de', - italian = 'it', - persian = 'pe', - romanian = 'ro', -} - -local lastinterface, lastcommand, lastsource, lastmode = "en", "", "", "tex" - -local variables = { - ['color-background-main-left'] = '#3F3F3F', - ['color-background-main-right'] = '#5F5F5F', - ['color-background-one'] = lmx.get('color-background-green'), - ['color-background-two'] = lmx.get('color-background-blue'), - ['title'] = 'ConTeXt Help Information', -} - ---~ function lmx.loadedfile(filename) ---~ return io.loaddata(resolvers.findfile(filename)) -- return resolvers.texdatablob(filename) ---~ end - -local function doit(configuration,filename,hashed) - - local formats = document.setups.formats - - local start = os.clock() - local detail = hashed.queries or { } - - if detail then - - lastinterface = detail.interface or lastinterface - lastcommand = detail.command or lastcommand - lastsource = detail.source or lastsource - lastmode = detail.mode or lastmode or "tex" - - lastcommand = gsub(lastcommand,"%s*^\\*(.+)%s*","%1") - - if lastinterface then - report("checking interface: %s",lastinterface) - document.setups.load(format("cont-%s.xml",lastinterface)) - end - - local div = document.setups.div [lastinterface] - local span = document.setups.span[lastinterface] - - local names, refs, ints = document.setups.names(lastinterface), { }, { } - for k=1,#names do - local v = names[k] - refs[k] = format(formats.href_in_list[lastmode],v[1],lastmode,v[2]) - end - if lastmode ~= "lua" then - local sorted = table.sortedkeys(interfaces) - for k=1,#sorted do - local v = sorted[k] - ints[k] = format(formats.interface,interfaces[v],lastmode,v) - end - end - - local n = concat(refs,"
") - local i = concat(ints,"

") - - if div then - variables.names = format(div,n) - variables.interfaces = format(div,i) - else - variables.names = n - variables.interfaces = i - end - - -- first we need to add information about mkii/mkiv - - variables.maintitle = "no definition" - variables.maintext = "" - variables.extra = "" - - if document.setups.showsources and lastsource and lastsource ~= "" then - -- todo: mkii, mkiv, tex (can be different) - local data = io.loaddata(resolvers.findfile(lastsource)) - variables.maintitle = lastsource - variables.maintext = format(formats.listing,data) - lastsource = "" - elseif lastcommand and lastcommand ~= "" then - local data = document.setups.collect(lastcommand,lastinterface,lastmode) - if data then - local what, extra = { "environment", "category", "source", "mode" }, { } - for k=1,#what do - local v = what[k] - if data[v] and data[v] ~= "" then - lmx.set(v, data[v]) - extra[#extra+1] = v .. ": " .. data[v] - end - end - variables.maintitle = data.sequence - variables.maintext = format(formats.parameters,concat(data.parameters)) - variables.extra = concat(extra,"   ") - else - variables.maintext = "select command" - end - end - - else - - variables.maintitle = "no definition" - variables.maintext = "some error" - variables.extra = "" - - end - - local content = lmx.convert('context-help.lmx',false,variables) - - report("time spent on page: %0.03f seconds",os.clock()-start) - - return { content = content } -end - -return doit, true +if not modules then modules = { } end modules ['mtx-server-ctx-help'] = { + version = 1.001, + comment = "Basic Definition Browser", + author = "Hans Hagen", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- todo in lua interface: noargument, oneargument, twoarguments, threearguments +-- todo: pickup translations from mult file + +dofile(resolvers.findfile("trac-lmx.lua","tex")) + +-- problem ... serialize parent stack + +local format, match, gsub, find = string.format, string.match, string.gsub, string.find +local concat = table.concat + +local report = logs.reporter("ctx-help") + +-- -- -- make this a module: cont-xx.lua + +document = document or { } +document.setups = document.setups or { } + +document.setups.div = { + pe = "
%s
" +} + +document.setups.span = { + pe = "%s" +} + +document.setups.translations = document.setups.translations or { + + nl = { + ["title"] = "setup", + ["formula"] = "formule", + ["number"] = "getal", + ["list"] = "lijst", + ["dimension"] = "maat", + ["mark"] = "markering", + ["reference"] = "verwijzing", + ["command"] = "commando", + ["file"] = "file", + ["name"] = "naam", + ["identifier"] = "naam", + ["text"] = "tekst", + ["section"] = "sectie", + ["singular"] = "naam enkelvoud", + ["plural"] = "naam meervoud", + ["matrix"] = "n*m", + ["see"] = "zie", + ["inherits"] = "erft van", + ["optional"] = "optioneel", + ["displaymath"] = "formule", + ["index"] = "ingang", + ["math"] = "formule", + ["nothing"] = "leeg", + ["file"] = "file", + ["position"] = "positie", + ["reference"] = "verwijzing", + ["csname"] = "naam", + ["destination"] = "bestemming", + ["triplet"] = "triplet", + ["word"] = "woord", + ["content"] = "tekst", + }, + + en = { + ["title"] = "setup", + ["formula"] = "formula", + ["number"] = "number", + ["list"] = "list", + ["dimension"] = "dimension", + ["mark"] = "mark", + ["reference"] = "reference", + ["command"] = "command", + ["file"] = "file", + ["name"] = "name", + ["identifier"] = "identifier", + ["text"] = "text", + ["section"] = "section", + ["singular"] = "singular name", + ["plural"] = "plural name", + ["matrix"] = "n*m", + ["see"] = "see", + ["inherits"] = "inherits from", + ["optional"] = "optional", + ["displaymath"] = "formula", + ["index"] = "entry", + ["math"] = "formula", + ["nothing"] = "empty", + ["file"] = "file", + ["position"] = "position", + ["reference"] = "reference", + ["csname"] = "name", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "word", + ["content"] = "text", + + ["noargument"] = "\\cs", + ["oneargument"] = "\\cs#1{..}", + ["twoarguments"] = "\\cs#1#2{..}{..}", + ["threearguments"] = "\\cs#1#2#3{..}{..}{..}", + + }, + + de = { + ["title"] = "Setup", + ["formula"] = "Formel", + ["number"] = "Nummer", + ["list"] = "Liste", + ["dimension"] = "Dimension", + ["mark"] = "Beschriftung", + ["reference"] = "Referenz", + ["command"] = "Befehl", + ["file"] = "Datei", + ["name"] = "Name", + ["identifier"] = "Name", + ["text"] = "Text", + ["section"] = "Abschnitt", + ["singular"] = "singular", + ["plural"] = "plural", + ["matrix"] = "n*m", + ["see"] = "siehe", + ["inherits"] = "inherits from", + ["optional"] = "optioneel", + ["displaymath"] = "formula", + ["index"] = "entry", + ["math"] = "formula", + ["nothing"] = "empty", + ["file"] = "file", + ["position"] = "position", + ["reference"] = "reference", + ["csname"] = "name", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "word", + ["content"] = "text", + }, + + cz = { + ["title"] = "setup", + ["formula"] = "rovnice", + ["number"] = "cislo", + ["list"] = "seznam", + ["dimension"] = "dimenze", + ["mark"] = "znacka", + ["reference"] = "reference", + ["command"] = "prikaz", + ["file"] = "soubor", + ["name"] = "jmeno", + ["identifier"] = "jmeno", + ["text"] = "text", + ["section"] = "sekce", + ["singular"] = "jmeno v singularu", + ["plural"] = "jmeno v pluralu", + ["matrix"] = "n*m", + ["see"] = "viz", + ["inherits"] = "inherits from", + ["optional"] = "optioneel", + ["displaymath"] = "formula", + ["index"] = "entry", + ["math"] = "formula", + ["nothing"] = "empty", + ["file"] = "file", + ["position"] = "position", + ["reference"] = "reference", + ["csname"] = "name", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "word", + ["content"] = "text", + }, + + it = { + ["title"] = "setup", + ["formula"] = "formula", + ["number"] = "number", + ["list"] = "list", + ["dimension"] = "dimension", + ["mark"] = "mark", + ["reference"] = "reference", + ["command"] = "command", + ["file"] = "file", + ["name"] = "name", + ["identifier"] = "name", + ["text"] = "text", + ["section"] = "section", + ["singular"] = "singular name", + ["plural"] = "plural name", + ["matrix"] = "n*m", + ["see"] = "see", + ["inherits"] = "inherits from", + ["optional"] = "optioneel", + ["displaymath"] = "formula", + ["index"] = "entry", + ["math"] = "formula", + ["nothing"] = "empty", + ["file"] = "file", + ["position"] = "position", + ["reference"] = "reference", + ["csname"] = "name", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "word", + ["content"] = "text", + }, + + ro = { + ["title"] = "setari", + ["formula"] = "formula", + ["number"] = "numar", + ["list"] = "lista", + ["dimension"] = "dimensiune", + ["mark"] = "marcaj", + ["reference"] = "referinta", + ["command"] = "comanda", + ["file"] = "fisier", + ["name"] = "nume", + ["identifier"] = "nume", + ["text"] = "text", + ["section"] = "sectiune", + ["singular"] = "nume singular", + ["plural"] = "nume pluram", + ["matrix"] = "n*m", + ["see"] = "vezi", + ["inherits"] = "inherits from", + ["optional"] = "optioneel", + ["displaymath"] = "formula", + ["index"] = "entry", + ["math"] = "formula", + ["nothing"] = "empty", + ["file"] = "file", + ["position"] = "position", + ["reference"] = "reference", + ["csname"] = "name", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "word", + ["content"] = "text", + }, + + fr = { + ["title"] = "réglage", + ["formula"] = "formule", + ["number"] = "numéro", + ["list"] = "liste", + ["dimension"] = "dimension", + ["mark"] = "marquage", + ["reference"] = "reference", + ["command"] = "commande", + ["file"] = "fichier", + ["name"] = "nom", + ["identifier"] = "identificateur", + ["text"] = "texte", + ["section"] = "section", + ["singular"] = "nom singulier", + ["plural"] = "nom pluriel", + ["matrix"] = "n*m", + ["see"] = "vois", + ["inherits"] = "herite de", + ["optional"] = "optionel", + ["displaymath"] = "formule", + ["index"] = "entrée", + ["math"] = "formule", + ["nothing"] = "vide", + ["file"] = "fichier", + ["position"] = "position", + ["reference"] = "réference", + ["csname"] = "nom", + ["destination"] = "destination", + ["triplet"] = "triplet", + ["word"] = "mot", + ["content"] = "texte", + } + +} + +document.setups.formats = { + open_command = { + tex = [[\%s]], + lua = [[context.%s (]], + }, + close_command = { + tex = [[]], + lua = [[ )]], + }, + connector = { + tex = [[]], + lua = [[, ]], + }, + href_in_list = { + tex = [[%s]], + lua = [[%s]], + }, + href_as_command = { + tex = [[\%s]], + lua = [[context.%s]], + }, + modes = { + tex = [[lua mode]], + lua = [[tex mode]], + }, + optional_single = { + tex = "[optional string %s]", + lua = "{optional string %s}", + }, + optional_list = { + tex = "[optional list %s]", + lua = "{optional table %s}" , + } , + mandate_single = { + tex = "[mandate string %s]", + lua = "{mandate string %s}", + }, + mandate_list = { + tex = "[mandate list %s]", + lua = "{mandate list %s}", + }, + interface = [[%s]], + source = [[%s]], + parameter = [[%s%s%s]], + parameters = [[%s
]], + listing = [[
%s]],
+    special         = [[%s]],
+    default         = [[%s]],
+}
+
+local function translate(tag,int,noformat)
+    local t = document.setups.translations
+    local te = t["en"]
+    local ti = t[int] or te
+    if noformat then
+        return ti[tag] or te[tag] or tag
+    else
+        return format(document.setups.formats.special,ti[tag] or te[tag] or tag)
+    end
+end
+
+local function translated(e,int)
+    local attributes = e.at
+    local s = attributes.type or "?"
+    local tag = match(s,"^cd:(.*)$")
+    if attributes.default == "yes" then
+        return format(document.setups.formats.default,tag or "?")
+    elseif tag then
+        return translate(tag,int)
+    else
+        return s
+    end
+end
+
+document.setups.loaded = document.setups.loaded or { }
+
+document.setups.current = { }
+document.setups.showsources = true
+document.setups.mode = "tex"
+
+function document.setups.load(filename)
+    filename = resolvers.findfile(filename) or ""
+    if filename ~= "" then
+        local current = document.setups.loaded[filename]
+        if not current then
+            local loaded = xml.load(filename)
+            if loaded then
+                -- xml.inject(document.setups.root,"/",loaded)
+                current = {
+                    file = filename,
+                    root = loaded,
+                    names = { },
+                    used = { },
+                }
+                document.setups.loaded[filename] = current
+            end
+        end
+        document.setups.current = current or { }
+    end
+end
+
+function document.setups.name(ek)
+    local at = ek.at
+    local name = at.name
+    if at.type == 'environment' then
+        name = "start" .. name
+    end
+    if at.variant then
+        name = name .. ":" .. at.variant
+    end
+    if at.generated == "yes" then
+        name = name .. "*"
+    end
+    return name:lower()
+end
+
+function document.setups.csname(ek,int)
+    local cs = ""
+    local at = ek.at or { }
+    if at.type == 'environment' then
+        cs = translate("start",int,true) .. cs
+    end
+    for e in xml.collected(ek,'cd:sequence/(cd:string|variable)') do
+        if e.tg == "string" then
+            cs = cs .. e.at.value
+        else
+            cs = cs .. e.at.value -- to be translated
+        end
+    end
+    return cs
+end
+
+function document.setups.names()
+    local current = document.setups.current
+    local names = current.names
+    if not names or #names == 0 then
+        names = { }
+        local name = document.setups.name
+        local csname = document.setups.csname
+        for e in xml.collected(current.root,'cd:command') do
+            names[#names+1] = { e.at.name, csname(e,int) }
+        end
+        table.sort(names, function(a,b) return a[2]:lower() < b[2]:lower() end)
+        current.names = names
+    end
+    return names
+end
+
+function document.setups.show(name)
+    local current = document.setups.current
+    if current.root then
+        local name = gsub(name,"[<>]","")
+        local setup = xml.first(current.root,"cd:command[@name='" .. name .. "']")
+        current.used[#current.used+1] = setup
+        xml.sprint(setup)
+    end
+end
+
+function document.setups.showused()
+    local current = document.setups.current
+    if current.root and next(current.used) then
+        local sorted = table.sortedkeys(current.used)
+        for i=1,#sorted do
+            xml.sprint(current.used[sorted[i]])
+        end
+    end
+end
+function document.setups.showall()
+    local current = document.setups.current
+    if current.root then
+        local list = { }
+        for e in xml.collected(current.root,"cd:command") do
+            list[document.setups.name(e)] = e
+        end
+        local sorted = table.sortedkeys(list)
+        for i=1,#sorted do
+            xml.sprint(list[sorted[i]])
+        end
+    end
+end
+function document.setups.resolve(name)
+    local current = document.setups.current
+    if current.root then
+        local e = xml.filter(current.root,format("cd:define[@name='%s']/text()",name))
+        if e then
+            xml.sprint(e)
+        end
+    end
+end
+
+function document.setups.collect(name,int,lastmode)
+    local current = document.setups.current
+    local formats = document.setups.formats
+    local command = xml.filter(current.root,format("cd:command[@name='%s']/first()",name))
+    if command then
+        local attributes = command.at or { }
+        local data = {
+            command = command,
+            category = attributes.category or "",
+        }
+        if document.setups.showsources then
+            data.source = (attributes.file and format(formats.source,attributes.file,lastmode,attributes.file)) or ""
+        else
+            data.source = attributes.file or ""
+        end
+        local n, sequence, tags = 0, { }, { }
+        sequence[#sequence+1] = format(formats.open_command[lastmode],document.setups.csname(command,int))
+        local arguments, tag = { }, ""
+        for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
+            n = n + 1
+            local attributes = d[k].at
+            if #sequence > 1 then
+                local c = formats.connector[lastmode]
+                if c ~= "" then
+                    sequence[#sequence+1] = c
+                end
+            end
+            if attributes.optional == 'yes' then
+                if attributes.list == 'yes' then
+                    tag = format(formats.optional_list[lastmode],n)
+                else
+                    tag = format(formats.optional_single[lastmode],n)
+                end
+            else
+                if attributes.list == 'yes' then
+                    tag = format(formats.mandate_list[lastmode],n)
+                else
+                    tag = format(formats.mandate_single[lastmode],n)
+                end
+            end
+            sequence[#sequence+1] = tag
+            tags[#tags+1] = tag
+        end
+        sequence[#sequence+1] = formats.close_command[lastmode]
+        data.sequence = concat(sequence, " ")
+        local parameters, n = { }, 0
+        for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
+            n = n + 1
+            if d[k].tg == "keywords" then
+                local left = tags[n]
+                local right = { }
+                for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do
+                    local tag = d[k].tg
+                    if tag == "resolve" then
+                        local name = d[k].at.name or ""
+                        if name ~= "" then
+                            local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name))
+                            for r, d, k in xml.elements(resolved,"cd:constant") do
+                                right[#right+1] = translated(d[k],int)
+                            end
+                        end
+                    else
+                        right[#right+1] = translated(d[k],int)
+                    end
+                end
+                parameters[#parameters+1] = format(formats.parameter,left,"",concat(right, ", "))
+            else
+                local what = tags[n]
+                for r, d, k in xml.elements(d[k],"(cd:parameter|cd:inherit)") do
+                    local tag = d[k].tg
+                    local left, right = d[k].at.name or "?", { }
+                    if tag == "inherit" then
+                        local name = d[k].at.name or "?"
+                        local goto = format(document.setups.formats.href_as_command[lastmode],name,lastmode,name)
+                        if #parameters > 0 and not find(parameters[#parameters],"
") then + parameters[#parameters+1] = format(formats.parameter,"
","","") + end + parameters[#parameters+1] = format(formats.parameter,what,format(formats.special,translate("inherits",int)),goto) + else + for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do + local tag = d[k].tg + if tag == "resolve" then + local name = d[k].at.name or "" + if name ~= "" then + local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name)) + for r, d, k in xml.elements(resolved,"cd:constant") do + right[#right+1] = translated(d[k],int) + end + end + else + right[#right+1] = translated(d[k],int) + end + end + parameters[#parameters+1] = format(formats.parameter,what,left,concat(right, ", ")) + end + what = "" + end + end + parameters[#parameters+1] = format(formats.parameter,"
","","") + end + data.parameters = parameters or { } + data.mode = formats.modes[lastmode or "tex"] + return data + else + return nil + end +end + +-- -- -- + +tex = tex or { } + +-- -- -- + +local interfaces = { + czech = 'cz', + dutch = 'nl', + english = 'en', + french = 'fr', + german = 'de', + italian = 'it', + persian = 'pe', + romanian = 'ro', +} + +local lastinterface, lastcommand, lastsource, lastmode = "en", "", "", "tex" + +local variables = { + ['color-background-main-left'] = '#3F3F3F', + ['color-background-main-right'] = '#5F5F5F', + ['color-background-one'] = lmx.get('color-background-green'), + ['color-background-two'] = lmx.get('color-background-blue'), + ['title'] = 'ConTeXt Help Information', +} + +--~ function lmx.loadedfile(filename) +--~ return io.loaddata(resolvers.findfile(filename)) -- return resolvers.texdatablob(filename) +--~ end + +local function doit(configuration,filename,hashed) + + local formats = document.setups.formats + + local start = os.clock() + local detail = hashed.queries or { } + + if detail then + + lastinterface = detail.interface or lastinterface + lastcommand = detail.command or lastcommand + lastsource = detail.source or lastsource + lastmode = detail.mode or lastmode or "tex" + + lastcommand = gsub(lastcommand,"%s*^\\*(.+)%s*","%1") + + if lastinterface then + report("checking interface: %s",lastinterface) + document.setups.load(format("cont-%s.xml",lastinterface)) + end + + local div = document.setups.div [lastinterface] + local span = document.setups.span[lastinterface] + + local names, refs, ints = document.setups.names(lastinterface), { }, { } + for k=1,#names do + local v = names[k] + refs[k] = format(formats.href_in_list[lastmode],v[1],lastmode,v[2]) + end + if lastmode ~= "lua" then + local sorted = table.sortedkeys(interfaces) + for k=1,#sorted do + local v = sorted[k] + ints[k] = format(formats.interface,interfaces[v],lastmode,v) + end + end + + local n = concat(refs,"
") + local i = concat(ints,"

") + + if div then + variables.names = format(div,n) + variables.interfaces = format(div,i) + else + variables.names = n + variables.interfaces = i + end + + -- first we need to add information about mkii/mkiv + + variables.maintitle = "no definition" + variables.maintext = "" + variables.extra = "" + + if document.setups.showsources and lastsource and lastsource ~= "" then + -- todo: mkii, mkiv, tex (can be different) + local data = io.loaddata(resolvers.findfile(lastsource)) + variables.maintitle = lastsource + variables.maintext = format(formats.listing,data) + lastsource = "" + elseif lastcommand and lastcommand ~= "" then + local data = document.setups.collect(lastcommand,lastinterface,lastmode) + if data then + local what, extra = { "environment", "category", "source", "mode" }, { } + for k=1,#what do + local v = what[k] + if data[v] and data[v] ~= "" then + lmx.set(v, data[v]) + extra[#extra+1] = v .. ": " .. data[v] + end + end + variables.maintitle = data.sequence + variables.maintext = format(formats.parameters,concat(data.parameters)) + variables.extra = concat(extra,"   ") + else + variables.maintext = "select command" + end + end + + else + + variables.maintitle = "no definition" + variables.maintext = "some error" + variables.extra = "" + + end + + local content = lmx.convert('context-help.lmx',false,variables) + + report("time spent on page: %0.03f seconds",os.clock()-start) + + return { content = content } +end + +return doit, true diff --git a/scripts/context/lua/mtx-server-ctx-startup.lua b/scripts/context/lua/mtx-server-ctx-startup.lua index 556805113..8e99e6371 100644 --- a/scripts/context/lua/mtx-server-ctx-startup.lua +++ b/scripts/context/lua/mtx-server-ctx-startup.lua @@ -1,39 +1,39 @@ -if not modules then modules = { } end modules ['mtx-server-ctx-startup'] = { - version = 1.001, - comment = "Overview Of Goodies", - author = "Hans Hagen", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -dofile(resolvers.findfile("trac-lmx.lua","tex")) - -function doit(configuration,filename,hashed) - - local list = { } - local root = file.dirname(resolvers.findfile("mtx-server.lua") or ".") - if root == "" then root = "." end - local pattern = root .. "/mtx-server-ctx-*.lua" - local files = dir.glob(pattern) - for i=1,#files do - local filename = file.basename(files[i]) - local name = string.match(filename,"mtx%-server%-ctx%-(.-)%.lua$") - if name and name ~= "startup" then - list[#list+1] = string.format("%s

",filename,name,name) - end - end - - local variables = { - ['color-background-one'] = lmx.get('color-background-green'), - ['color-background-two'] = lmx.get('color-background-blue'), - ['title'] = "Overview Of Goodies", - ['color-background-one'] = lmx.get('color-background-green'), - ['color-background-two'] = lmx.get('color-background-blue'), - ['maintext'] = table.concat(list,"\n"), - } - - return { content = lmx.convert('context-base.lmx',false,variables) } - -end - -return doit, true +if not modules then modules = { } end modules ['mtx-server-ctx-startup'] = { + version = 1.001, + comment = "Overview Of Goodies", + author = "Hans Hagen", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +dofile(resolvers.findfile("trac-lmx.lua","tex")) + +function doit(configuration,filename,hashed) + + local list = { } + local root = file.dirname(resolvers.findfile("mtx-server.lua") or ".") + if root == "" then root = "." end + local pattern = root .. "/mtx-server-ctx-*.lua" + local files = dir.glob(pattern) + for i=1,#files do + local filename = file.basename(files[i]) + local name = string.match(filename,"mtx%-server%-ctx%-(.-)%.lua$") + if name and name ~= "startup" then + list[#list+1] = string.format("%s

",filename,name,name) + end + end + + local variables = { + ['color-background-one'] = lmx.get('color-background-green'), + ['color-background-two'] = lmx.get('color-background-blue'), + ['title'] = "Overview Of Goodies", + ['color-background-one'] = lmx.get('color-background-green'), + ['color-background-two'] = lmx.get('color-background-blue'), + ['maintext'] = table.concat(list,"\n"), + } + + return { content = lmx.convert('context-base.lmx',false,variables) } + +end + +return doit, true diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua index 5ec15de70..675ab2c62 100644 --- a/scripts/context/lua/mtx-server.lua +++ b/scripts/context/lua/mtx-server.lua @@ -1,402 +1,402 @@ -if not modules then modules = { } end modules ['mtx-server'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen & Taco Hoekwater", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-server - Simple Webserver For Helpers - 0.10 - - - - - start server - port to listen to - server root - scripts sub path - index file - start on own path - - - - -]] - -local application = logs.application { - name = "mtx-server", - banner = "Simple Webserver For Helpers 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.webserver = scripts.webserver or { } - -dofile(resolvers.findfile("luat-soc.lua","tex")) - -local socket = socket or require("socket") -local http = http or require("socket.http") -- not needed -local format = string.format - --- The following two lists are taken from webrick (ruby) and --- extended with a few extra suffixes. - -local mimetypes = { - ai = 'application/postscript', - asc = 'text/plain', - avi = 'video/x-msvideo', - bin = 'application/octet-stream', - bmp = 'image/bmp', - bz2 = 'application/x-bzip2', - cer = 'application/pkix-cert', - class = 'application/octet-stream', - crl = 'application/pkix-crl', - crt = 'application/x-x509-ca-cert', - css = 'text/css', - dms = 'application/octet-stream', - doc = 'application/msword', - dvi = 'application/x-dvi', - eps = 'application/postscript', - etx = 'text/x-setext', - exe = 'application/octet-stream', - gif = 'image/gif', - gz = 'application/x-tar', - hqx = 'application/mac-binhex40', - htm = 'text/html', - html = 'text/html', - jpe = 'image/jpeg', - jpeg = 'image/jpeg', - jpg = 'image/jpeg', - lha = 'application/octet-stream', - lzh = 'application/octet-stream', - mov = 'video/quicktime', - mpe = 'video/mpeg', - mpeg = 'video/mpeg', - mpg = 'video/mpeg', - pbm = 'image/x-portable-bitmap', - pdf = 'application/pdf', - pgm = 'image/x-portable-graymap', - png = 'image/png', - pnm = 'image/x-portable-anymap', - ppm = 'image/x-portable-pixmap', - ppt = 'application/vnd.ms-powerpoint', - ps = 'application/postscript', - qt = 'video/quicktime', - ras = 'image/x-cmu-raster', - rb = 'text/plain', - rd = 'text/plain', - rgb = 'image/x-rgb', - rtf = 'application/rtf', - sgm = 'text/sgml', - sgml = 'text/sgml', - snd = 'audio/basic', - tar = 'application/x-tar', - tgz = 'application/x-tar', - tif = 'image/tiff', - tiff = 'image/tiff', - txt = 'text/plain', - xbm = 'image/x-xbitmap', - xls = 'application/vnd.ms-excel', - xml = 'text/xml', - xpm = 'image/x-xpixmap', - xwd = 'image/x-xwindowdump', - zip = 'application/zip', -} - -local messages = { - [100] = 'Continue', - [101] = 'Switching Protocols', - [200] = 'OK', - [201] = 'Created', - [202] = 'Accepted', - [203] = 'Non-Authoritative Information', - [204] = 'No Content', - [205] = 'Reset Content', - [206] = 'Partial Content', - [300] = 'Multiple Choices', - [301] = 'Moved Permanently', - [302] = 'Found', - [303] = 'See Other', - [304] = 'Not Modified', - [305] = 'Use Proxy', - [307] = 'Temporary Redirect', - [400] = 'Bad Request', - [401] = 'Unauthorized', - [402] = 'Payment Required', - [403] = 'Forbidden', - [404] = 'Not Found', - [405] = 'Method Not Allowed', - [406] = 'Not Acceptable', - [407] = 'Proxy Authentication Required', - [408] = 'Request Timeout', - [409] = 'Conflict', - [410] = 'Gone', - [411] = 'Length Required', - [412] = 'Precondition Failed', - [413] = 'Request Entity Too Large', - [414] = 'Request-URI Too Large', - [415] = 'Unsupported Media Type', - [416] = 'Request Range Not Satisfiable', - [417] = 'Expectation Failed', - [500] = 'Internal Server Error', - [501] = 'Not Implemented', - [502] = 'Bad Gateway', - [503] = 'Service Unavailable', - [504] = 'Gateway Timeout', - [505] = 'HTTP Version Not Supported', -} - -local handlers = { } - -local function errormessage(client,configuration,n) - local data = format("%s %s

%s %s

",n,messages[n],n,messages[n]) - report("handling error %s: %s",n,messages[n]) - handlers.generic(client,configuration,data,nil,true) -end - -local validpaths, registered = { }, { } - -function scripts.webserver.registerpath(name) - if not registered[name] then - local cleanname = string.gsub(name,"%.%.","deleted-parent") - report("registering path '%s'",cleanname) - validpaths[#validpaths+1] = cleanname - registered[name] = true - end -end - -function handlers.generic(client,configuration,data,suffix,iscontent) - if not iscontent then - local name = data - report("requested file '%s'",name) - local fullname = file.join(configuration.root,name) - data = io.loaddata(fullname) or "" - if data == "" then - for n=1,#validpaths do - local fullname = file.join(validpaths[n],name) - data = io.loaddata(fullname) or "" - if data ~= "" then - report("sending generic file '%s'",fullname) - break - end - end - else - report("sending generic file '%s'",fullname) - end - end - if data and data ~= "" then - client:send("HTTP/1.1 200 OK\r\n") - client:send("Connection: close\r\n") - client:send(format("Content-Length: %s\r\n",#data)) - client:send(format("Content-Type: %s\r\n",(suffix and mimetypes[suffix]) or "text/html")) - client:send("\r\n") - client:send(data) - client:send("\r\n") - else - errormessage(client,configuration,404) - end -end - --- return os.date() - --- return { content = "crap" } - --- return function(configuration,filename) --- return { content = filename } --- end - -local loaded = { } - -function handlers.lua(client,configuration,filename,suffix,iscontent,hashed) -- filename will disappear, and become hashed.filename - local filename = file.join(configuration.scripts,filename) - if not file.is_qualified_path(filename) then - filename = file.join(configuration.root,filename) - end - -- todo: split url in components, see l-url; rather trivial - local result, keep = loaded[filename], false - if result then - report("reusing script: %s",filename) - else - report("locating script: %s",filename) - if lfs.isfile(filename) then - report("loading script: %s",filename) - result = loadfile(filename) - report("return type: %s",type(result)) - if result and type(result) == "function" then - -- result() should return a table { [type=,] [length=,] content= }, function or string - result, keep = result() - if keep then - report("saving script: %s",type(result)) - loaded[filename] = result - end - end - else - report("problematic script: %s",filename) - errormessage(client,configuration,404) - end - end - if result then - if type(result) == "function" then - report("running script: %s",filename) - result = result(configuration,filename,hashed) -- second argument will become query - end - if result and type(result) == "string" then - result = { content = result } - end - if result and type(result) == "table" then - if result.content then - local suffix = result.type or "text/html" - local action = handlers[suffix] or handlers.generic - action(client,configuration,result.content,suffix,true) -- content - elseif result.filename then - local suffix = file.suffix(result.filename) or "text/html" - local action = handlers[suffix] or handlers.generic - action(client,configuration,result.filename,suffix,false) -- filename - else - errormessage(client,configuration,404) - end - else - errormessage(client,configuration,500) - end - else - errormessage(client,configuration,404) - end -end - -handlers.luc = handlers.lua -handlers.html = handlers.htm - -local indices = { "index.htm", "index.html" } -local portnumber = 31415 -- pi suits tex - -function scripts.webserver.run(configuration) - -- check configuration - configuration.port = tonumber(configuration.port or os.getenv("MTX_SERVER_PORT") or portnumber) or portnumber - if not configuration.root or not lfs.isdir(configuration.root) then - configuration.root = os.getenv("MTX_SERVER_ROOT") or "." - end - -- locate root and index file in tex tree - if not lfs.isdir(configuration.root) then - for i=1,#indices do - local name = indices[i] - local root = resolvers.resolve("path:" .. name) or "" - if root ~= "" then - configuration.root = root - configuration.index = configuration.index or name - break - end - end - end - configuration.root = dir.expandname(configuration.root) - if not configuration.index then - for i=1,#indices do - local name = indices[i] - if lfs.isfile(file.join(configuration.root,name)) then - configuration.index = name -- we will prepend the rootpath later - break - end - end - configuration.index = configuration.index or "unknown" - end - if not configuration.scripts or configuration.scripts == "" then - configuration.scripts = dir.expandname(file.join(configuration.root or ".",configuration.scripts or ".")) - end - -- so far for checks - report("running at port: %s",configuration.port) - report("document root: %s",configuration.root or resolvers.ownpath) - report("main index file: %s",configuration.index) - report("scripts subpath: %s",configuration.scripts) - report("context services: http://localhost:%s/mtx-server-ctx-startup.lua",configuration.port) - local server = assert(socket.bind("*", configuration.port)) - local script = configuration.script - while true do -- blocking - local start = os.clock() - local client = server:accept() - client:settimeout(configuration.timeout or 60) - local request, e = client:receive() - if e then - errormessage(client,configuration,404) - else - local from = client:getpeername() - report("request from: %s",tostring(from)) - report("request data: %s",tostring(request)) - local fullurl = string.match(request,"GET (.+) HTTP/.*$") or "" -- todo: more clever / post - if fullurl == "" then - report("no url") - errormessage(client,configuration,404) - else - report("requested url: %s",fullurl) - fullurl = socket.url.unescape(fullurl) -- still needed? - local hashed = url.hashed(fullurl) - local query = url.query(hashed.query) - local filename = hashed.path -- hm, not query? - if script then - filename = script - report("forced script: %s",filename) - local suffix = file.suffix(filename) - local action = handlers[suffix] or handlers.generic - if action then - report("performing action: %s",filename) - action(client,configuration,filename,suffix,false,hashed) -- filename and no content - else - errormessage(client,configuration,404) - end - elseif filename then - filename = socket.url.unescape(filename) - report("requested action: %s",filename) - if string.find(filename,"%.%.") then - filename = nil -- invalid path - end - if filename == nil or filename == "" or filename == "/" then - filename = configuration.index - report("invalid filename, forcing: %s",filename) - end - local suffix = file.suffix(filename) - local action = handlers[suffix] or handlers.generic - if action then - report("performing action: %s",filename) - action(client,configuration,filename,suffix,false,hashed) -- filename and no content - else - errormessage(client,configuration,404) - end - else - errormessage(client,configuration,404) - end - end - end - client:close() - report("time spent with client: %0.03f seconds",os.clock()-start) - end -end - -if environment.argument("auto") then - local path = resolvers.findfile("mtx-server.lua") or "." - scripts.webserver.run { - port = environment.argument("port"), - root = environment.argument("root") or file.dirname(path) or ".", - scripts = environment.argument("scripts") or file.dirname(path) or ".", - script = environment.argument("script"), - } -elseif environment.argument("start") then - scripts.webserver.run { - port = environment.argument("port"), - root = environment.argument("root") or ".", -- "e:/websites/www.pragma-ade.com", - index = environment.argument("index"), - scripts = environment.argument("scripts"), - script = environment.argument("script"), - } -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end - --- mtxrun --script server --start => http://localhost:31415/mtx-server-ctx-startup.lua +if not modules then modules = { } end modules ['mtx-server'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen & Taco Hoekwater", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-server + Simple Webserver For Helpers + 0.10 + + + + + start server + port to listen to + server root + scripts sub path + index file + start on own path + + + + +]] + +local application = logs.application { + name = "mtx-server", + banner = "Simple Webserver For Helpers 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.webserver = scripts.webserver or { } + +dofile(resolvers.findfile("luat-soc.lua","tex")) + +local socket = socket or require("socket") +local http = http or require("socket.http") -- not needed +local format = string.format + +-- The following two lists are taken from webrick (ruby) and +-- extended with a few extra suffixes. + +local mimetypes = { + ai = 'application/postscript', + asc = 'text/plain', + avi = 'video/x-msvideo', + bin = 'application/octet-stream', + bmp = 'image/bmp', + bz2 = 'application/x-bzip2', + cer = 'application/pkix-cert', + class = 'application/octet-stream', + crl = 'application/pkix-crl', + crt = 'application/x-x509-ca-cert', + css = 'text/css', + dms = 'application/octet-stream', + doc = 'application/msword', + dvi = 'application/x-dvi', + eps = 'application/postscript', + etx = 'text/x-setext', + exe = 'application/octet-stream', + gif = 'image/gif', + gz = 'application/x-tar', + hqx = 'application/mac-binhex40', + htm = 'text/html', + html = 'text/html', + jpe = 'image/jpeg', + jpeg = 'image/jpeg', + jpg = 'image/jpeg', + lha = 'application/octet-stream', + lzh = 'application/octet-stream', + mov = 'video/quicktime', + mpe = 'video/mpeg', + mpeg = 'video/mpeg', + mpg = 'video/mpeg', + pbm = 'image/x-portable-bitmap', + pdf = 'application/pdf', + pgm = 'image/x-portable-graymap', + png = 'image/png', + pnm = 'image/x-portable-anymap', + ppm = 'image/x-portable-pixmap', + ppt = 'application/vnd.ms-powerpoint', + ps = 'application/postscript', + qt = 'video/quicktime', + ras = 'image/x-cmu-raster', + rb = 'text/plain', + rd = 'text/plain', + rgb = 'image/x-rgb', + rtf = 'application/rtf', + sgm = 'text/sgml', + sgml = 'text/sgml', + snd = 'audio/basic', + tar = 'application/x-tar', + tgz = 'application/x-tar', + tif = 'image/tiff', + tiff = 'image/tiff', + txt = 'text/plain', + xbm = 'image/x-xbitmap', + xls = 'application/vnd.ms-excel', + xml = 'text/xml', + xpm = 'image/x-xpixmap', + xwd = 'image/x-xwindowdump', + zip = 'application/zip', +} + +local messages = { + [100] = 'Continue', + [101] = 'Switching Protocols', + [200] = 'OK', + [201] = 'Created', + [202] = 'Accepted', + [203] = 'Non-Authoritative Information', + [204] = 'No Content', + [205] = 'Reset Content', + [206] = 'Partial Content', + [300] = 'Multiple Choices', + [301] = 'Moved Permanently', + [302] = 'Found', + [303] = 'See Other', + [304] = 'Not Modified', + [305] = 'Use Proxy', + [307] = 'Temporary Redirect', + [400] = 'Bad Request', + [401] = 'Unauthorized', + [402] = 'Payment Required', + [403] = 'Forbidden', + [404] = 'Not Found', + [405] = 'Method Not Allowed', + [406] = 'Not Acceptable', + [407] = 'Proxy Authentication Required', + [408] = 'Request Timeout', + [409] = 'Conflict', + [410] = 'Gone', + [411] = 'Length Required', + [412] = 'Precondition Failed', + [413] = 'Request Entity Too Large', + [414] = 'Request-URI Too Large', + [415] = 'Unsupported Media Type', + [416] = 'Request Range Not Satisfiable', + [417] = 'Expectation Failed', + [500] = 'Internal Server Error', + [501] = 'Not Implemented', + [502] = 'Bad Gateway', + [503] = 'Service Unavailable', + [504] = 'Gateway Timeout', + [505] = 'HTTP Version Not Supported', +} + +local handlers = { } + +local function errormessage(client,configuration,n) + local data = format("%s %s

%s %s

",n,messages[n],n,messages[n]) + report("handling error %s: %s",n,messages[n]) + handlers.generic(client,configuration,data,nil,true) +end + +local validpaths, registered = { }, { } + +function scripts.webserver.registerpath(name) + if not registered[name] then + local cleanname = string.gsub(name,"%.%.","deleted-parent") + report("registering path '%s'",cleanname) + validpaths[#validpaths+1] = cleanname + registered[name] = true + end +end + +function handlers.generic(client,configuration,data,suffix,iscontent) + if not iscontent then + local name = data + report("requested file '%s'",name) + local fullname = file.join(configuration.root,name) + data = io.loaddata(fullname) or "" + if data == "" then + for n=1,#validpaths do + local fullname = file.join(validpaths[n],name) + data = io.loaddata(fullname) or "" + if data ~= "" then + report("sending generic file '%s'",fullname) + break + end + end + else + report("sending generic file '%s'",fullname) + end + end + if data and data ~= "" then + client:send("HTTP/1.1 200 OK\r\n") + client:send("Connection: close\r\n") + client:send(format("Content-Length: %s\r\n",#data)) + client:send(format("Content-Type: %s\r\n",(suffix and mimetypes[suffix]) or "text/html")) + client:send("\r\n") + client:send(data) + client:send("\r\n") + else + errormessage(client,configuration,404) + end +end + +-- return os.date() + +-- return { content = "crap" } + +-- return function(configuration,filename) +-- return { content = filename } +-- end + +local loaded = { } + +function handlers.lua(client,configuration,filename,suffix,iscontent,hashed) -- filename will disappear, and become hashed.filename + local filename = file.join(configuration.scripts,filename) + if not file.is_qualified_path(filename) then + filename = file.join(configuration.root,filename) + end + -- todo: split url in components, see l-url; rather trivial + local result, keep = loaded[filename], false + if result then + report("reusing script: %s",filename) + else + report("locating script: %s",filename) + if lfs.isfile(filename) then + report("loading script: %s",filename) + result = loadfile(filename) + report("return type: %s",type(result)) + if result and type(result) == "function" then + -- result() should return a table { [type=,] [length=,] content= }, function or string + result, keep = result() + if keep then + report("saving script: %s",type(result)) + loaded[filename] = result + end + end + else + report("problematic script: %s",filename) + errormessage(client,configuration,404) + end + end + if result then + if type(result) == "function" then + report("running script: %s",filename) + result = result(configuration,filename,hashed) -- second argument will become query + end + if result and type(result) == "string" then + result = { content = result } + end + if result and type(result) == "table" then + if result.content then + local suffix = result.type or "text/html" + local action = handlers[suffix] or handlers.generic + action(client,configuration,result.content,suffix,true) -- content + elseif result.filename then + local suffix = file.suffix(result.filename) or "text/html" + local action = handlers[suffix] or handlers.generic + action(client,configuration,result.filename,suffix,false) -- filename + else + errormessage(client,configuration,404) + end + else + errormessage(client,configuration,500) + end + else + errormessage(client,configuration,404) + end +end + +handlers.luc = handlers.lua +handlers.html = handlers.htm + +local indices = { "index.htm", "index.html" } +local portnumber = 31415 -- pi suits tex + +function scripts.webserver.run(configuration) + -- check configuration + configuration.port = tonumber(configuration.port or os.getenv("MTX_SERVER_PORT") or portnumber) or portnumber + if not configuration.root or not lfs.isdir(configuration.root) then + configuration.root = os.getenv("MTX_SERVER_ROOT") or "." + end + -- locate root and index file in tex tree + if not lfs.isdir(configuration.root) then + for i=1,#indices do + local name = indices[i] + local root = resolvers.resolve("path:" .. name) or "" + if root ~= "" then + configuration.root = root + configuration.index = configuration.index or name + break + end + end + end + configuration.root = dir.expandname(configuration.root) + if not configuration.index then + for i=1,#indices do + local name = indices[i] + if lfs.isfile(file.join(configuration.root,name)) then + configuration.index = name -- we will prepend the rootpath later + break + end + end + configuration.index = configuration.index or "unknown" + end + if not configuration.scripts or configuration.scripts == "" then + configuration.scripts = dir.expandname(file.join(configuration.root or ".",configuration.scripts or ".")) + end + -- so far for checks + report("running at port: %s",configuration.port) + report("document root: %s",configuration.root or resolvers.ownpath) + report("main index file: %s",configuration.index) + report("scripts subpath: %s",configuration.scripts) + report("context services: http://localhost:%s/mtx-server-ctx-startup.lua",configuration.port) + local server = assert(socket.bind("*", configuration.port)) + local script = configuration.script + while true do -- blocking + local start = os.clock() + local client = server:accept() + client:settimeout(configuration.timeout or 60) + local request, e = client:receive() + if e then + errormessage(client,configuration,404) + else + local from = client:getpeername() + report("request from: %s",tostring(from)) + report("request data: %s",tostring(request)) + local fullurl = string.match(request,"GET (.+) HTTP/.*$") or "" -- todo: more clever / post + if fullurl == "" then + report("no url") + errormessage(client,configuration,404) + else + report("requested url: %s",fullurl) + fullurl = socket.url.unescape(fullurl) -- still needed? + local hashed = url.hashed(fullurl) + local query = url.query(hashed.query) + local filename = hashed.path -- hm, not query? + if script then + filename = script + report("forced script: %s",filename) + local suffix = file.suffix(filename) + local action = handlers[suffix] or handlers.generic + if action then + report("performing action: %s",filename) + action(client,configuration,filename,suffix,false,hashed) -- filename and no content + else + errormessage(client,configuration,404) + end + elseif filename then + filename = socket.url.unescape(filename) + report("requested action: %s",filename) + if string.find(filename,"%.%.") then + filename = nil -- invalid path + end + if filename == nil or filename == "" or filename == "/" then + filename = configuration.index + report("invalid filename, forcing: %s",filename) + end + local suffix = file.suffix(filename) + local action = handlers[suffix] or handlers.generic + if action then + report("performing action: %s",filename) + action(client,configuration,filename,suffix,false,hashed) -- filename and no content + else + errormessage(client,configuration,404) + end + else + errormessage(client,configuration,404) + end + end + end + client:close() + report("time spent with client: %0.03f seconds",os.clock()-start) + end +end + +if environment.argument("auto") then + local path = resolvers.findfile("mtx-server.lua") or "." + scripts.webserver.run { + port = environment.argument("port"), + root = environment.argument("root") or file.dirname(path) or ".", + scripts = environment.argument("scripts") or file.dirname(path) or ".", + script = environment.argument("script"), + } +elseif environment.argument("start") then + scripts.webserver.run { + port = environment.argument("port"), + root = environment.argument("root") or ".", -- "e:/websites/www.pragma-ade.com", + index = environment.argument("index"), + scripts = environment.argument("scripts"), + script = environment.argument("script"), + } +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end + +-- mtxrun --script server --start => http://localhost:31415/mtx-server-ctx-startup.lua diff --git a/scripts/context/lua/mtx-texworks.lua b/scripts/context/lua/mtx-texworks.lua index ae5f2afa4..8cb7736ac 100644 --- a/scripts/context/lua/mtx-texworks.lua +++ b/scripts/context/lua/mtx-texworks.lua @@ -1,121 +1,121 @@ -if not modules then modules = { } end modules ['mtx-texworks'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-texworks - TeXworks Startup Script - 1.00 - - - - - [ start texworks - report what will happen - - - - -]] - -local application = logs.application { - name = "mtx-texworks", - banner = "TeXworks Startup Script 1.00", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.texworks = scripts.texworks or { } - -local texworkspaths = { - "completion", - "configuration", - "dictionaries", - "translations", - "scripts", - "templates", - "TUG" -} - -local texworkssignal = "texworks-context.rme" -local texworkininame = "texworks.ini" - -function scripts.texworks.start(indeed) - local workname = (os.type == "windows" and "texworks.exe") or "texworks" - local fullname = nil - local binpaths = file.splitpath(os.getenv("PATH")) or file.splitpath(os.getenv("path")) - local usedsignal = texworkssignal - local datapath = resolvers.findfile(usedsignal,"other text files") or "" - if datapath ~= "" then - datapath = file.dirname(datapath) -- data - if datapath == "" then - datapath = resolvers.cleanpath(lfs.currentdir()) - end - else - usedsignal = texworkininame - datapath = resolvers.findfile(usedsignal,"other text files") or "" - if datapath == "" then - usedsignal = string.lower(usedsignal) - datapath = resolvers.findfile(usedsignal,"other text files") or "" - end - if datapath ~= "" and lfs.isfile(datapath) then - datapath = file.dirname(datapath) -- TUG - datapath = file.dirname(datapath) -- data - if datapath == "" then - datapath = resolvers.cleanpath(lfs.currentdir()) - end - end - end - if datapath == "" then - report("invalid datapath, maybe you need to regenerate the file database") - return false - end - if not binpaths or #binpaths == 0 then - report("invalid binpath") - return false - end - for i=1,#binpaths do - local p = file.join(binpaths[i],workname) - if lfs.isfile(p) and lfs.attributes(p,"size") > 10000 then -- avoind stub - fullname = p - break - end - end - if not fullname then - report("unable to locate %s",workname) - return false - end - for i=1,#texworkspaths do - dir.makedirs(file.join(datapath,texworkspaths[i])) - end - os.setenv("TW_INIPATH",datapath) - os.setenv("TW_LIBPATH",datapath) - if not indeed or environment.argument("verbose") then - report("used signal: %s", usedsignal) - report("data path : %s", datapath) - report("full name : %s", fullname) - report("set paths : TW_INIPATH TW_LIBPATH") - end - if indeed then - os.launch(fullname) - end -end - -if environment.argument("start") then - scripts.texworks.start(true) -elseif environment.argument("test") then - scripts.texworks.start() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-texworks'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-texworks + TeXworks Startup Script + 1.00 + + + + + [ start texworks + report what will happen + + + + +]] + +local application = logs.application { + name = "mtx-texworks", + banner = "TeXworks Startup Script 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.texworks = scripts.texworks or { } + +local texworkspaths = { + "completion", + "configuration", + "dictionaries", + "translations", + "scripts", + "templates", + "TUG" +} + +local texworkssignal = "texworks-context.rme" +local texworkininame = "texworks.ini" + +function scripts.texworks.start(indeed) + local workname = (os.type == "windows" and "texworks.exe") or "texworks" + local fullname = nil + local binpaths = file.splitpath(os.getenv("PATH")) or file.splitpath(os.getenv("path")) + local usedsignal = texworkssignal + local datapath = resolvers.findfile(usedsignal,"other text files") or "" + if datapath ~= "" then + datapath = file.dirname(datapath) -- data + if datapath == "" then + datapath = resolvers.cleanpath(lfs.currentdir()) + end + else + usedsignal = texworkininame + datapath = resolvers.findfile(usedsignal,"other text files") or "" + if datapath == "" then + usedsignal = string.lower(usedsignal) + datapath = resolvers.findfile(usedsignal,"other text files") or "" + end + if datapath ~= "" and lfs.isfile(datapath) then + datapath = file.dirname(datapath) -- TUG + datapath = file.dirname(datapath) -- data + if datapath == "" then + datapath = resolvers.cleanpath(lfs.currentdir()) + end + end + end + if datapath == "" then + report("invalid datapath, maybe you need to regenerate the file database") + return false + end + if not binpaths or #binpaths == 0 then + report("invalid binpath") + return false + end + for i=1,#binpaths do + local p = file.join(binpaths[i],workname) + if lfs.isfile(p) and lfs.attributes(p,"size") > 10000 then -- avoind stub + fullname = p + break + end + end + if not fullname then + report("unable to locate %s",workname) + return false + end + for i=1,#texworkspaths do + dir.makedirs(file.join(datapath,texworkspaths[i])) + end + os.setenv("TW_INIPATH",datapath) + os.setenv("TW_LIBPATH",datapath) + if not indeed or environment.argument("verbose") then + report("used signal: %s", usedsignal) + report("data path : %s", datapath) + report("full name : %s", fullname) + report("set paths : TW_INIPATH TW_LIBPATH") + end + if indeed then + os.launch(fullname) + end +end + +if environment.argument("start") then + scripts.texworks.start(true) +elseif environment.argument("test") then + scripts.texworks.start() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-timing.lua b/scripts/context/lua/mtx-timing.lua index 5ba361e5f..391232b0a 100644 --- a/scripts/context/lua/mtx-timing.lua +++ b/scripts/context/lua/mtx-timing.lua @@ -1,218 +1,218 @@ -if not modules then modules = { } end modules ['mtx-timing'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local format, gsub, concat = string.format, string.gsub, table.concat - -local helpinfo = [[ - - - - mtx-timing - ConTeXt Timing Tools - 0.10 - - - - - make xhtml file - launch after conversion - remove after launching - - - - -]] - -local application = logs.application { - name = "mtx-timing", - banner = "ConTeXt Timing Tools 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -dofile(resolvers.findfile("node-snp.lua","tex")) -dofile(resolvers.findfile("trac-tim.lua","tex")) -dofile(resolvers.findfile("trac-lmx.lua","tex")) - -local meta = [[ - beginfig(%s) ; - begingroup ; - save p, q, b, h, w ; - path p, q, b ; numeric h, w ; - linecap := butt ; - h := 100 ; - w := 800pt ; - p := %s ; - q := %s ; - p := p shifted -llcorner p ; - q := q shifted -llcorner q ; - q := q xstretched w ; - p := p xstretched w ; - b := boundingbox (llcorner p -- llcorner p shifted (w,h)) ; - draw b withcolor white withpen pencircle scaled 4pt ; - draw p withcolor red withpen pencircle scaled 4pt ; - draw q withcolor blue withpen pencircle scaled 2pt ; - endgroup ; - endfig ; -]] - -local html_graphic = [[ -

%s (red) %s (blue)

- - - - - -
%s -   min: %s
-   max: %s
-   pages: %s
-   average: %s
-
-
-]] - -local html_menu = [[ - %s -]] - -local directrun = true - -local what = { "parameters", "nodes" } - -plugins = plugins or { progress = { } } -- brrr, will become moduledata as well - -function plugins.progress.make_svg(filename,other) - local metadata, menudata, c = { }, { }, 0 - metadata[#metadata+1] = 'outputformat := "svg" ;' - for i=1,#what do - local kind, mdk = what[i], { } - menudata[kind] = mdk - for n, name in next, plugins.progress[kind](filename) do - local first = plugins.progress.path(filename,name) - local second = plugins.progress.path(filename,other) - c = c + 1 - metadata[#metadata+1] = format(meta,c,first,second) - mdk[#mdk+1] = { name, c } - end - end - metadata[#metadata+1] = "end ." - metadata = concat(metadata,"\n\n") - if directrun then - dofile(resolvers.findfile("mlib-run.lua","tex")) - commands = commands or { } - commands.writestatus = report - local result = metapost.directrun("metafun","timing data","svg",true,metadata) - return menudata, result - else - local mpname = file.replacesuffix(filename,"mp") - io.savedata(mpname,metadata) - os.execute(format("mpost --progname=context --mem=metafun.mem %s",mpname)) - os.remove(mpname) - os.remove(file.removesuffix(filename).."-mpgraph.mpo") -- brr - os.remove(file.removesuffix(filename)..".log") -- brr - return menudata - end -end - -function plugins.progress.makehtml(filename,other,menudata,metadata) - local graphics = { } - local result = { graphics = graphics } - for i=1,#what do - local kind, menu = what[i], { } - local md = menudata[kind] - result[kind] = menu - for k=1,#md do - local v = md[k] - local name, number = v[1], v[2] - local min = plugins.progress.bot(filename,name) - local max = plugins.progress.top(filename,name) - local pages = plugins.progress.pages(filename) - local average = math.round(max/pages) - if directrun then - local data = metadata[number] - menu[#menu+1] = format(html_menu,name,name) - graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average) - else - local mpname = file.replacesuffix(filename,number) - local data = io.loaddata(mpname) or "" - -- data = gsub(data,"[\n\r]*","") - data = gsub(data,"<%?xml.->","") - menu[#menu+1] = format(html_menu,name,name) - graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average) - os.remove(mpname) - end - end - end - return result -end - -function plugins.progress.valid_file(name) - return name and name ~= "" and lfs.isfile(name .. "-luatex-progress.lut") -end - -function plugins.progress.make_lmx_page(name,launch,remove) - - local filename = name .. "-luatex-progress" - local other = "elapsed_time" - local template = 'context-timing.lmx' - - plugins.progress.convert(filename) - - local menudata, metadata = plugins.progress.make_svg(filename,other) - local htmldata = plugins.progress.makehtml(filename,other,menudata,metadata) - - lmx.htmfile = function(name) return name .. "-timing.xhtml" end - lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end - - local variables = { - ['title-default'] = 'ConTeXt Timing Information', - ['title'] = format('ConTeXt Timing Information: %s',file.basename(name)), - ['parametersmenu'] = concat(htmldata.parameters, "  "), - ['nodesmenu'] = concat(htmldata.nodes, "  "), - ['graphics'] = concat(htmldata.graphics, "\n\n"), - ['color-background-one'] = lmx.get('color-background-green'), - ['color-background-two'] = lmx.get('color-background-blue'), - } - - if launch then - local htmfile = lmx.show(template,variables) - if remove then - os.sleep(1) -- give time to launch - os.remove(htmfile) - end - else - lmx.make(template,variables) - end - -end - -scripts = scripts or { } -scripts.timings = scripts.timings or { } - -function scripts.timings.xhtml(filename) - if filename == "" then - report("provide filename") - elseif not plugins.progress.valid_file(filename) then - report("first run context again with the --timing option") - else - local basename = file.removesuffix(filename) - local launch = environment.argument("launch") - local remove = environment.argument("remove") - plugins.progress.make_lmx_page(basename,launch,remove) - end -end - -if environment.argument("xhtml") then - scripts.timings.xhtml(environment.files[1] or "") -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-timing'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local format, gsub, concat = string.format, string.gsub, table.concat + +local helpinfo = [[ + + + + mtx-timing + ConTeXt Timing Tools + 0.10 + + + + + make xhtml file + launch after conversion + remove after launching + + + + +]] + +local application = logs.application { + name = "mtx-timing", + banner = "ConTeXt Timing Tools 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +dofile(resolvers.findfile("node-snp.lua","tex")) +dofile(resolvers.findfile("trac-tim.lua","tex")) +dofile(resolvers.findfile("trac-lmx.lua","tex")) + +local meta = [[ + beginfig(%s) ; + begingroup ; + save p, q, b, h, w ; + path p, q, b ; numeric h, w ; + linecap := butt ; + h := 100 ; + w := 800pt ; + p := %s ; + q := %s ; + p := p shifted -llcorner p ; + q := q shifted -llcorner q ; + q := q xstretched w ; + p := p xstretched w ; + b := boundingbox (llcorner p -- llcorner p shifted (w,h)) ; + draw b withcolor white withpen pencircle scaled 4pt ; + draw p withcolor red withpen pencircle scaled 4pt ; + draw q withcolor blue withpen pencircle scaled 2pt ; + endgroup ; + endfig ; +]] + +local html_graphic = [[ +

%s (red) %s (blue)

+ + + + + +
%s +   min: %s
+   max: %s
+   pages: %s
+   average: %s
+
+
+]] + +local html_menu = [[ + %s +]] + +local directrun = true + +local what = { "parameters", "nodes" } + +plugins = plugins or { progress = { } } -- brrr, will become moduledata as well + +function plugins.progress.make_svg(filename,other) + local metadata, menudata, c = { }, { }, 0 + metadata[#metadata+1] = 'outputformat := "svg" ;' + for i=1,#what do + local kind, mdk = what[i], { } + menudata[kind] = mdk + for n, name in next, plugins.progress[kind](filename) do + local first = plugins.progress.path(filename,name) + local second = plugins.progress.path(filename,other) + c = c + 1 + metadata[#metadata+1] = format(meta,c,first,second) + mdk[#mdk+1] = { name, c } + end + end + metadata[#metadata+1] = "end ." + metadata = concat(metadata,"\n\n") + if directrun then + dofile(resolvers.findfile("mlib-run.lua","tex")) + commands = commands or { } + commands.writestatus = report + local result = metapost.directrun("metafun","timing data","svg",true,metadata) + return menudata, result + else + local mpname = file.replacesuffix(filename,"mp") + io.savedata(mpname,metadata) + os.execute(format("mpost --progname=context --mem=metafun.mem %s",mpname)) + os.remove(mpname) + os.remove(file.removesuffix(filename).."-mpgraph.mpo") -- brr + os.remove(file.removesuffix(filename)..".log") -- brr + return menudata + end +end + +function plugins.progress.makehtml(filename,other,menudata,metadata) + local graphics = { } + local result = { graphics = graphics } + for i=1,#what do + local kind, menu = what[i], { } + local md = menudata[kind] + result[kind] = menu + for k=1,#md do + local v = md[k] + local name, number = v[1], v[2] + local min = plugins.progress.bot(filename,name) + local max = plugins.progress.top(filename,name) + local pages = plugins.progress.pages(filename) + local average = math.round(max/pages) + if directrun then + local data = metadata[number] + menu[#menu+1] = format(html_menu,name,name) + graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average) + else + local mpname = file.replacesuffix(filename,number) + local data = io.loaddata(mpname) or "" + -- data = gsub(data,"[\n\r]*","") + data = gsub(data,"<%?xml.->","") + menu[#menu+1] = format(html_menu,name,name) + graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average) + os.remove(mpname) + end + end + end + return result +end + +function plugins.progress.valid_file(name) + return name and name ~= "" and lfs.isfile(name .. "-luatex-progress.lut") +end + +function plugins.progress.make_lmx_page(name,launch,remove) + + local filename = name .. "-luatex-progress" + local other = "elapsed_time" + local template = 'context-timing.lmx' + + plugins.progress.convert(filename) + + local menudata, metadata = plugins.progress.make_svg(filename,other) + local htmldata = plugins.progress.makehtml(filename,other,menudata,metadata) + + lmx.htmfile = function(name) return name .. "-timing.xhtml" end + lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end + + local variables = { + ['title-default'] = 'ConTeXt Timing Information', + ['title'] = format('ConTeXt Timing Information: %s',file.basename(name)), + ['parametersmenu'] = concat(htmldata.parameters, "  "), + ['nodesmenu'] = concat(htmldata.nodes, "  "), + ['graphics'] = concat(htmldata.graphics, "\n\n"), + ['color-background-one'] = lmx.get('color-background-green'), + ['color-background-two'] = lmx.get('color-background-blue'), + } + + if launch then + local htmfile = lmx.show(template,variables) + if remove then + os.sleep(1) -- give time to launch + os.remove(htmfile) + end + else + lmx.make(template,variables) + end + +end + +scripts = scripts or { } +scripts.timings = scripts.timings or { } + +function scripts.timings.xhtml(filename) + if filename == "" then + report("provide filename") + elseif not plugins.progress.valid_file(filename) then + report("first run context again with the --timing option") + else + local basename = file.removesuffix(filename) + local launch = environment.argument("launch") + local remove = environment.argument("remove") + plugins.progress.make_lmx_page(basename,launch,remove) + end +end + +if environment.argument("xhtml") then + scripts.timings.xhtml(environment.files[1] or "") +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-tools.lua b/scripts/context/lua/mtx-tools.lua index 19b7458a1..0ef194285 100644 --- a/scripts/context/lua/mtx-tools.lua +++ b/scripts/context/lua/mtx-tools.lua @@ -1,199 +1,199 @@ -if not modules then modules = { } end modules ['mtx-tools'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local find, format, sub, rep, gsub, lower = string.find, string.format, string.sub, string.rep, string.gsub, string.lower - -local helpinfo = [[ - - - - mtx-tools - Some File Related Goodies - 1.01 - - - - - remove utf bomb if present - remove indeed - - - glob directory into xml - glob pattern (default: *) - url attribute (no processing) - the root of the globbed path (default: .) - output filename (console by default) - recurse into subdirecories - take pathpart of given pattern - set name attributes to full path name - - - glob pattern (default: *) - recurse into subdirecories - downcase indeed - - - - -]] - -local application = logs.application { - name = "mtx-tools", - banner = "Some File Related Goodies 1.01", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.tools = scripts.tools or { } - -local bomb_1, bomb_2 = "^\254\255", "^\239\187\191" - -function scripts.tools.disarmutfbomb() - local force, done = environment.argument("force"), false - local files = environment.files - for i=1,#files do - local name = files[i] - if lfs.isfile(name) then - local data = io.loaddata(name) - if not data then - -- just skip - elseif find(data,bomb_1) then - report("file '%s' has a 2 character utf bomb",name) - if force then - io.savedata(name,(gsub(data,bomb_1,""))) - end - done = true - elseif find(data,bomb_2) then - report("file '%s' has a 3 character utf bomb",name) - if force then - io.savedata(name,(gsub(data,bomb_2,""))) - end - done = true - else - -- report("file '%s' has no utf bomb",name) - end - end - end - if done and not force then - report("use --force to do a real disarming") - end -end - -function scripts.tools.downcase() - local pattern = environment.argument('pattern') or "*" - local recurse = environment.argument('recurse') - local force = environment.argument('force') - local n = 0 - if recurse and not find(pattern,"^%*%*%/") then - pattern = "**/*" .. pattern - end - dir.glob(pattern,function(name) - local basename = file.basename(name) - if lower(basename) ~= basename then - n = n + 1 - if force then - os.rename(name,lower(name)) - end - end - end) - if n > 0 then - if force then - report("%s files renamed",n) - else - report("use --force to do a real rename (%s files involved)",n) - end - else - report("nothing to do") - end -end - - -function scripts.tools.dirtoxml() - - local join, removesuffix, suffixonly, date = file.join, file.removesuffix, file.suffixonly, os.date - - local xmlns = "http://www.pragma-ade.com/rlg/xmldir.rng" - local timestamp = "%Y-%m-%d %H:%M" - - local pattern = environment.argument('pattern') or ".*" - local url = environment.argument('url') or "no-url" - local root = environment.argument('root') or "." - local outputfile = environment.argument('output') - - local recurse = environment.argument('recurse') or false - local stripname = environment.argument('stripname') - local longname = environment.argument('longname') - - local function flush(list,result,n,path) - n, result = n or 1, result or { } - local d = rep(" ",n) - for name, attr in table.sortedhash(list) do - local mode = attr.mode - if mode == "file" then - result[#result+1] = format("%s",d,(longname and path and join(path,name)) or name) - result[#result+1] = format("%s %s",d,removesuffix(name)) - result[#result+1] = format("%s %s",d,suffixonly(name)) - result[#result+1] = format("%s %s",d,attr.size) - result[#result+1] = format("%s %s",d,sub(attr.permissions,7,9)) - result[#result+1] = format("%s %s",d,date(timestamp,attr.modification)) - result[#result+1] = format("%s",d) - elseif mode == "directory" then - result[#result+1] = format("%s",d,name) - flush(attr.list,result,n+1,(path and join(path,name)) or name) - result[#result+1] = format("%s",d) - end - end - end - - if not pattern or pattern == "" then - report('provide --pattern=') - return - end - - if stripname then - pattern = file.dirname(pattern) - end - - local luapattern = string.topattern(pattern,true) - - lfs.chdir(root) - - local list = dir.collectpattern(root,luapattern,recurse) - - if list[outputfile] then - list[outputfile] = nil - end - - local result = { "" } - result[#result+1] = format("",url,root,pattern,luapattern,xmlns,date(timestamp)) - flush(list,result) - result[#result+1] = "" - - result = table.concat(result,"\n") - - if not outputfile or outputfile == "" then - texio.write_nl(result) - else - io.savedata(outputfile,result) - end - -end - -if environment.argument("disarmutfbomb") then - scripts.tools.disarmutfbomb() -elseif environment.argument("dirtoxml") then - scripts.tools.dirtoxml() -elseif environment.argument("downcase") then - scripts.tools.downcase() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-tools'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local find, format, sub, rep, gsub, lower = string.find, string.format, string.sub, string.rep, string.gsub, string.lower + +local helpinfo = [[ + + + + mtx-tools + Some File Related Goodies + 1.01 + + + + + remove utf bomb if present + remove indeed + + + glob directory into xml + glob pattern (default: *) + url attribute (no processing) + the root of the globbed path (default: .) + output filename (console by default) + recurse into subdirecories + take pathpart of given pattern + set name attributes to full path name + + + glob pattern (default: *) + recurse into subdirecories + downcase indeed + + + + +]] + +local application = logs.application { + name = "mtx-tools", + banner = "Some File Related Goodies 1.01", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.tools = scripts.tools or { } + +local bomb_1, bomb_2 = "^\254\255", "^\239\187\191" + +function scripts.tools.disarmutfbomb() + local force, done = environment.argument("force"), false + local files = environment.files + for i=1,#files do + local name = files[i] + if lfs.isfile(name) then + local data = io.loaddata(name) + if not data then + -- just skip + elseif find(data,bomb_1) then + report("file '%s' has a 2 character utf bomb",name) + if force then + io.savedata(name,(gsub(data,bomb_1,""))) + end + done = true + elseif find(data,bomb_2) then + report("file '%s' has a 3 character utf bomb",name) + if force then + io.savedata(name,(gsub(data,bomb_2,""))) + end + done = true + else + -- report("file '%s' has no utf bomb",name) + end + end + end + if done and not force then + report("use --force to do a real disarming") + end +end + +function scripts.tools.downcase() + local pattern = environment.argument('pattern') or "*" + local recurse = environment.argument('recurse') + local force = environment.argument('force') + local n = 0 + if recurse and not find(pattern,"^%*%*%/") then + pattern = "**/*" .. pattern + end + dir.glob(pattern,function(name) + local basename = file.basename(name) + if lower(basename) ~= basename then + n = n + 1 + if force then + os.rename(name,lower(name)) + end + end + end) + if n > 0 then + if force then + report("%s files renamed",n) + else + report("use --force to do a real rename (%s files involved)",n) + end + else + report("nothing to do") + end +end + + +function scripts.tools.dirtoxml() + + local join, removesuffix, suffixonly, date = file.join, file.removesuffix, file.suffixonly, os.date + + local xmlns = "http://www.pragma-ade.com/rlg/xmldir.rng" + local timestamp = "%Y-%m-%d %H:%M" + + local pattern = environment.argument('pattern') or ".*" + local url = environment.argument('url') or "no-url" + local root = environment.argument('root') or "." + local outputfile = environment.argument('output') + + local recurse = environment.argument('recurse') or false + local stripname = environment.argument('stripname') + local longname = environment.argument('longname') + + local function flush(list,result,n,path) + n, result = n or 1, result or { } + local d = rep(" ",n) + for name, attr in table.sortedhash(list) do + local mode = attr.mode + if mode == "file" then + result[#result+1] = format("%s",d,(longname and path and join(path,name)) or name) + result[#result+1] = format("%s %s",d,removesuffix(name)) + result[#result+1] = format("%s %s",d,suffixonly(name)) + result[#result+1] = format("%s %s",d,attr.size) + result[#result+1] = format("%s %s",d,sub(attr.permissions,7,9)) + result[#result+1] = format("%s %s",d,date(timestamp,attr.modification)) + result[#result+1] = format("%s",d) + elseif mode == "directory" then + result[#result+1] = format("%s",d,name) + flush(attr.list,result,n+1,(path and join(path,name)) or name) + result[#result+1] = format("%s",d) + end + end + end + + if not pattern or pattern == "" then + report('provide --pattern=') + return + end + + if stripname then + pattern = file.dirname(pattern) + end + + local luapattern = string.topattern(pattern,true) + + lfs.chdir(root) + + local list = dir.collectpattern(root,luapattern,recurse) + + if list[outputfile] then + list[outputfile] = nil + end + + local result = { "" } + result[#result+1] = format("",url,root,pattern,luapattern,xmlns,date(timestamp)) + flush(list,result) + result[#result+1] = "" + + result = table.concat(result,"\n") + + if not outputfile or outputfile == "" then + texio.write_nl(result) + else + io.savedata(outputfile,result) + end + +end + +if environment.argument("disarmutfbomb") then + scripts.tools.disarmutfbomb() +elseif environment.argument("dirtoxml") then + scripts.tools.dirtoxml() +elseif environment.argument("downcase") then + scripts.tools.downcase() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/scripts/context/lua/mtx-unzip.lua b/scripts/context/lua/mtx-unzip.lua index 02d9676bc..6514d709a 100644 --- a/scripts/context/lua/mtx-unzip.lua +++ b/scripts/context/lua/mtx-unzip.lua @@ -1,132 +1,132 @@ -if not modules then modules = { } end modules ['mtx-unzip'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- maybe --pattern - -local format = string.format - -local helpinfo = [[ - - - - mtx-unzip - Simple Unzipper - 0.10 - - - - - list files in archive - flatten unzipped directory structure - extract files - - - - -]] - -local application = logs.application { - name = "mtx-unzip", - banner = "Simple Unzipper 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.unzipper = scripts.unzipper or { } - -function scripts.unzipper.opened() - local filename = environment.files[1] - if filename and filename ~= "" then - filename = file.addsuffix(filename,'zip') - local zipfile = zip.open(filename) - if zipfile then - return zipfile - end - end - report("no zip file: %s",filename) - return false -end - -function scripts.unzipper.list() - local zipfile = scripts.unzipper.opened() - if zipfile then - local n = 0 - for k in zipfile:files() do - if #k.filename > n then n = #k.filename end - end - local files, paths, compressed, uncompressed = 0, 0, 0, 0 - local template_a = "%-"..n.."s" - local template_b = "%-"..n.."s % 9i % 9i" - local template_c = "\n%-"..n.."s % 9i % 9i" - for k in zipfile:files() do - if k.filename:find("/$") then - paths = paths + 1 - print(format(template_a, k.filename)) - else - files = files + 1 - local cs, us = k.compressed_size, k.uncompressed_size - if cs > compressed then - compressed = cs - end - if us > uncompressed then - uncompressed = us - end - print(format(template_b,k.filename,cs,us)) - end - end -- check following pattern, n is not enough - print(format(template_c,files .. " files, " .. paths .. " directories",compressed,uncompressed)) - end -end - -function zip.loaddata(zipfile,filename) - local f = zipfile:open(filename) - if f then - local data = f:read("*a") - f:close() - return data - end - return nil -end - -function scripts.unzipper.extract() - local zipfile = scripts.unzipper.opened() - if zipfile then - local junk = environment.arguments["j"] or environment.arguments["junk"] - for k in zipfile:files() do - local filename = k.filename - if filename:find("/$") then - if not junk then - lfs.mkdir(filename) - end - else - local data = zip.loaddata(zipfile,filename) - if data then - if junk then - filename = file.basename(filename) - end - io.savedata(filename,data) - print(filename) - end - end - end - end -end - -if environment.arguments["h"] or environment.arguments["help"] then - application.help() -elseif environment.arguments["l"] or environment.arguments["list"] then - scripts.unzipper.list(zipfile) -elseif environment.arguments["exporthelp"] then - application.export(environment.arguments["exporthelp"],environment.files[1]) -elseif environment.files[1] then -- implicit --extract - scripts.unzipper.extract(zipfile) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-unzip'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- maybe --pattern + +local format = string.format + +local helpinfo = [[ + + + + mtx-unzip + Simple Unzipper + 0.10 + + + + + list files in archive + flatten unzipped directory structure + extract files + + + + +]] + +local application = logs.application { + name = "mtx-unzip", + banner = "Simple Unzipper 0.10", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.unzipper = scripts.unzipper or { } + +function scripts.unzipper.opened() + local filename = environment.files[1] + if filename and filename ~= "" then + filename = file.addsuffix(filename,'zip') + local zipfile = zip.open(filename) + if zipfile then + return zipfile + end + end + report("no zip file: %s",filename) + return false +end + +function scripts.unzipper.list() + local zipfile = scripts.unzipper.opened() + if zipfile then + local n = 0 + for k in zipfile:files() do + if #k.filename > n then n = #k.filename end + end + local files, paths, compressed, uncompressed = 0, 0, 0, 0 + local template_a = "%-"..n.."s" + local template_b = "%-"..n.."s % 9i % 9i" + local template_c = "\n%-"..n.."s % 9i % 9i" + for k in zipfile:files() do + if k.filename:find("/$") then + paths = paths + 1 + print(format(template_a, k.filename)) + else + files = files + 1 + local cs, us = k.compressed_size, k.uncompressed_size + if cs > compressed then + compressed = cs + end + if us > uncompressed then + uncompressed = us + end + print(format(template_b,k.filename,cs,us)) + end + end -- check following pattern, n is not enough + print(format(template_c,files .. " files, " .. paths .. " directories",compressed,uncompressed)) + end +end + +function zip.loaddata(zipfile,filename) + local f = zipfile:open(filename) + if f then + local data = f:read("*a") + f:close() + return data + end + return nil +end + +function scripts.unzipper.extract() + local zipfile = scripts.unzipper.opened() + if zipfile then + local junk = environment.arguments["j"] or environment.arguments["junk"] + for k in zipfile:files() do + local filename = k.filename + if filename:find("/$") then + if not junk then + lfs.mkdir(filename) + end + else + local data = zip.loaddata(zipfile,filename) + if data then + if junk then + filename = file.basename(filename) + end + io.savedata(filename,data) + print(filename) + end + end + end + end +end + +if environment.arguments["h"] or environment.arguments["help"] then + application.help() +elseif environment.arguments["l"] or environment.arguments["list"] then + scripts.unzipper.list(zipfile) +elseif environment.arguments["exporthelp"] then + application.export(environment.arguments["exporthelp"],environment.files[1]) +elseif environment.files[1] then -- implicit --extract + scripts.unzipper.extract(zipfile) +else + application.help() +end diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 64203d3e3..5141bdf7a 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -1,676 +1,676 @@ -if not modules then modules = { } end modules ['mtx-update'] = { - version = 1.002, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- This script is dedicated to Mojca Miklavec, who is the driving force behind --- moving minimal generation from our internal machines to the context garden. --- Together with Arthur Reutenauer she made sure that it worked well on all --- platforms that matter. - -local helpinfo = [[ - - - - mtx-update - ConTeXt Minimals Updater - 0.31 - - - - - platform (windows, linux, linux-64, osx-intel, osx-ppc, linux-ppc) - repository url (rsync://contextgarden.net) - repository url (minimals) - specify version (current, experimental) - specify version (current, latest, beta, yyyy.mm.dd) - rsync binary (rsync) - installation directory (not guessed for the moment) - tex engine (luatex, pdftex, xetex) - extra modules (can be list or 'all') - additional fonts (can be list or 'all') - extra binaries (like scite and texworks) - instead of a dryrun, do the real thing - update minimal tree - also make formats and generate file databases - don't delete unused or obsolete files - update tree using saved state - adapt drive specs to cygwin - assume mingw binaries being used - - - - -]] - -local application = logs.application { - name = "mtx-update", - banner = "ConTeXt Minimals Updater 0.31", - helpinfo = helpinfo, -} - -local report = application.report - -local format, concat, gmatch, gsub, find = string.format, table.concat, string.gmatch, string.gsub, string.find - -scripts = scripts or { } -scripts.update = scripts.update or { } - -minimals = minimals or { } -minimals.config = minimals.config or { } - --- this is needed under windows --- else rsync fails to set the right chmod flags to files - -os.setenv("CYGWIN","nontsec") - -scripts.update.texformats = { - "cont-en", - "cont-nl", - "cont-cz", - "cont-de", - "cont-fa", - "cont-it", - "cont-ro", - "cont-uk", - "cont-pe", - -- "cont-xp", - "mptopdf", - "plain" -} - -scripts.update.mpformats = { - -- "metafun", - -- "mpost", -} - --- experimental is not functional at the moment - -scripts.update.repositories = { - "current", - "experimental" -} - --- more options than just these two are available (no idea why this is here) - -scripts.update.versions = { - "current", - "latest" -} - --- list of basic folders that are needed to make a functional distribution - -scripts.update.base = { - { "base/tex/", "texmf" }, - { "base/metapost/", "texmf" }, - { "fonts/common/", "texmf" }, - { "fonts/other/", "texmf" }, -- not *really* needed, but helpful - { "context//", "texmf-context" }, - { "misc/setuptex/", "." }, - { "misc/web2c", "texmf" }, - { "bin/common//", "texmf-" }, - { "bin/context//", "texmf-" }, - { "bin/metapost//", "texmf-" }, - { "bin/man/", "texmf-" }, -} - --- binaries and font-related files --- for pdftex we don't need OpenType fonts, for LuaTeX/XeTeX we don't need TFM files - -scripts.update.engines = { - ["luatex"] = { - { "fonts/new/", "texmf" }, - { "bin/luatex//", "texmf-" }, - { "bin/luajittex//","texmf-" }, - }, - ["xetex"] = { - { "base/xetex/", "texmf" }, - { "fonts/new/", "texmf" }, - { "bin/luatex//", "texmf-" }, -- tools - { "bin/xetex//", "texmf-" }, - }, - ["pdftex"] = { - { "fonts/old/", "texmf" }, - { "bin/luatex//", "texmf-" }, -- tools - { "bin/pdftex//", "texmf-" }, - }, - ["all"] = { - { "fonts/new/", "texmf" }, - { "fonts/old/", "texmf" }, - { "base/xetex/", "texmf" }, - { "bin/luatex//", "texmf-" }, - { "bin/luajittex//","texmf-" }, - { "bin/xetex//", "texmf-" }, - { "bin/pdftex//", "texmf-" }, - }, -} - -scripts.update.goodies = { - ["scite"] = { - { "bin//scite/", "texmf-" }, - }, - ["texworks"] = { - { "bin//texworks/", "texmf-" }, - }, -} - -scripts.update.platforms = { - ["mswin"] = "mswin", - ["windows"] = "mswin", - ["win32"] = "mswin", - ["win"] = "mswin", - ["linux"] = "linux", - ["freebsd"] = "freebsd", - ["freebsd-amd64"] = "freebsd-amd64", - ["kfreebsd"] = "kfreebsd-i386", - ["kfreebsd-i386"] = "kfreebsd-i386", - ["kfreebsd-amd64"] = "kfreebsd-amd64", - ["linux-32"] = "linux", - ["linux-64"] = "linux-64", - ["linux32"] = "linux", - ["linux64"] = "linux-64", - ["linux-ppc"] = "linux-ppc", - ["ppc"] = "linux-ppc", - ["osx"] = "osx-intel", - ["macosx"] = "osx-intel", - ["osx-intel"] = "osx-intel", - ["osx-ppc"] = "osx-ppc", - ["osx-powerpc"] = "osx-ppc", - ["osx-64"] = "osx-64", - ["osxintel"] = "osx-intel", - ["osxppc"] = "osx-ppc", - ["osxpowerpc"] = "osx-ppc", - ["solaris-intel"] = "solaris-intel", - ["solaris-sparc"] = "solaris-sparc", - ["solaris"] = "solaris-sparc", -} - -scripts.update.selfscripts = { - "mtxrun", - -- "luatools", -} - --- the list is filled up later (when we know what modules to download) - -scripts.update.modules = { -} - -scripts.update.fonts = { -} - -function scripts.update.run(str) - -- important, otherwise formats fly to a weird place - -- (texlua sets luatex as the engine, we need to reset that or to fix texexec :) - os.setenv("engine",nil) - if environment.argument("force") then - report("run, %s",str) - os.execute(str) - else - report("dry run, %s",str) - end -end - -function scripts.update.fullpath(path) - if file.is_rootbased_path(path) then - return path - else - return lfs.currentdir() .. "/" .. path - end -end - -local rsync_variant = "cygwin" -- will be come mingw - -local function drive(d) - if rsync_variant == "cygwin" then - d = gsub(d,[[([a-zA-Z]):/]], "/cygdrive/%1/") - else - d = gsub(d,[[([a-zA-Z]):/]], "/%1/") - end - return d -end - -function scripts.update.synchronize() - - report("update, start") - - local texroot = scripts.update.fullpath(states.get("paths.root")) - local engines = states.get('engines') or { } - local platforms = states.get('platforms') or { } - local repositories = states.get('repositories') -- minimals - local bin = states.get("rsync.program") -- rsync - local url = states.get("rsync.server") -- contextgarden.net - local version = states.get("context.version") -- current (or beta) - local modules = states.get("modules") -- modules (third party) - local fonts = states.get("fonts") -- fonts (experimental or special) - local goodies = states.get("goodies") -- goodies (like editors) - local force = environment.argument("force") - - bin = gsub(bin,"\\","/") - - if not url:find("::$") then url = url .. "::" end - local ok = lfs.attributes(texroot,"mode") == "directory" - if not ok and force then - dir.mkdirs(texroot) - ok = lfs.attributes(texroot,"mode") == "directory" - end - - if force then - dir.mkdirs(format("%s/%s", texroot, "texmf-cache")) - dir.mkdirs(format("%s/%s", texroot, "texmf-local")) - dir.mkdirs(format("%s/%s", texroot, "texmf-project")) - dir.mkdirs(format("%s/%s", texroot, "texmf-fonts")) - dir.mkdirs(format("%s/%s", texroot, "texmf-modules")) - end - - if ok or not force then - - local fetched, individual, osplatform = { }, { }, os.platform - - -- takes a collection as argument and returns a list of folders - - local function collection_to_list_of_folders(collection, platform) - local archives = {} - for i=1,#collection do - local archive = collection[i][1] - archive = gsub(archive,"",platform) - archive = gsub(archive,"",version) - archives[#archives+1] = archive - end - return archives - end - - -- takes a list of folders as argument and returns a string for rsync - -- sample input: - -- {'bin/common', 'bin/context'} - -- output: - -- 'minimals/current/bin/common minimals/current/bin/context' - - local function list_of_folders_to_rsync_string(list_of_folders) - local repository = 'current' - local prefix = format("%s/%s/", states.get('rsync.module'), repository) -- minimals/current/ - - return prefix .. concat(list_of_folders, format(" %s", prefix)) - end - - -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(scripts.update.base, os.platform))) - - -- rename function and add some more functionality: - -- * recursive/non-recursive (default: non-recursive) - -- * filter folders or regular files only (default: no filter) - -- * grep for size of included files (with --stats switch) - - local function get_list_of_files_from_rsync(list_of_folders) - -- temporary file to store the output of rsync (could be a more random name; watch for overwrites) - local temp_file = "rsync.tmp.txt" - -- a set of folders - local folders = {} - local command = format("%s %s'%s' > %s", bin, url, list_of_folders_to_rsync_string(list_of_folders), temp_file) - os.execute(command) - -- read output of rsync - local data = io.loaddata(temp_file) or "" - -- for every line extract the filename - for chmod, s in data:gmatch("([d%-][rwx%-]+).-(%S+)[\n\r]") do - -- skip "current" folder - if s ~= '.' and chmod:len() == 10 then - folders[#folders+1] = s - end - end - -- delete the file to which we have put output of rsync - os.remove(temp_file) - return folders - end - - -- rsync://contextgarden.net/minimals/current/modules/ - - if modules and type(modules) == "table" then - -- fetch the list of available modules from rsync server - local available_modules = get_list_of_files_from_rsync({"modules/"}) - -- hash of requested modules - -- local h = table.tohash(modules:split(",")) - local asked = table.copy(modules) - asked.all = nil - for i=1,#available_modules do - local s = available_modules[i] - if modules.all or modules[s] then - scripts.update.modules[#scripts.update.modules+1] = { format("modules/%s/",s), "texmf-modules" } - end - asked[s] = nil - end - if next(asked) then - report("skipping unknown modules: %s",table.concat(table.sortedkeys(asked),", ")) - end - end - - -- rsync://contextgarden.net/minimals/current/fonts/extra/ - - if fonts and type(fonts) == "table" then - local available_fonts = get_list_of_files_from_rsync({"fonts/extra/"}) - local asked = table.copy(fonts) - asked.all = nil - for i=1,#available_fonts do - local s = available_fonts[i] - if fonts.all or fonts[s] then - scripts.update.fonts[#scripts.update.fonts+1] = { format("fonts/extra/%s/",s), "texmf" } - end - asked[s] = nil - end - if next(asked) then - report("skipping unknown fonts: %s",table.concat(table.sortedkeys(asked),", ")) - end - end - - local function add_collection(collection,platform) - if collection and platform then - platform = scripts.update.platforms[platform] - if platform then - for i=1,#collection do - local c = collection[i] - local archive = gsub(c[1],"",platform) - local destination = format("%s/%s", texroot, gsub(c[2],"", platform)) - destination = gsub(destination,"\\","/") - archive = gsub(archive,"",version) - if osplatform == "windows" or osplatform == "mswin" then - destination = drive(destination) - end - individual[#individual+1] = { archive, destination } - end - end - end - end - - for platform, _ in next, platforms do - add_collection(scripts.update.base,platform) - end - for platform, _ in next, platforms do - add_collection(scripts.update.modules,platform) - end - for platform, _ in next, platforms do - add_collection(scripts.update.fonts,platform) - end - for engine, _ in next, engines do - for platform, _ in next, platforms do - add_collection(scripts.update.engines[engine],platform) - end - end - - if goodies and type(goodies) == "table" then - for goodie, _ in next, goodies do - for platform, _ in next, platforms do - add_collection(scripts.update.goodies[goodie],platform) - end - end - end - - local combined = { } - local update_repositories = scripts.update.repositories - for i=1,#update_repositories do - local repository = update_repositories[i] - if repositories[repository] then - for _, v in next, individual do - local archive, destination = v[1], v[2] - local cd = combined[destination] - if not cd then - cd = { } - combined[destination] = cd - end - cd[#cd+1] = format("%s/%s/%s",states.get('rsync.module'),repository,archive) - end - end - end - for destination, archive in next, combined do - local archives, command = concat(archive," "), "" - local normalflags, deleteflags = states.get("rsync.flags.normal"), "" - if os.name == "windows" then - normalflags = normalflags .. " -L" -- no symlinks - end - local dryrunflags = "" - if not environment.argument("force") then - dryrunflags = "--dry-run" - end - if (destination:find("texmf$") or destination:find("texmf%-context$") or destination:find("texmf%-modules$")) and (not environment.argument("keep")) then - deleteflags = states.get("rsync.flags.delete") - end - command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, destination) - -- report("running command: %s",command) - if not fetched[command] then - scripts.update.run(command,true) - fetched[command] = command - end - end - - local function update_script(script, platform) - local bin = gsub(bin,"\\","/") - local texroot = gsub(texroot,"\\","/") - platform = scripts.update.platforms[platform] - if platform then - local command - if platform == 'mswin' then - bin = drive(bin) - texroot = drive(texroot) - command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-mswin/bin/"]], bin, texroot, script, texroot) - else - command = format([[%s -tgo --chmod=a+x '%s/texmf-context/scripts/context/lua/%s.lua' '%s/texmf-%s/bin/%s']], bin, texroot, script, texroot, platform, script) - end - report("updating %s for %s: %s", script, platform, command) - scripts.update.run(command) - end - end - - for platform, _ in next, platforms do - for i=1, #scripts.update.selfscripts do - update_script(scripts.update.selfscripts[i],platform) - end - end - - else - report("no valid texroot: %s",texroot) - end - if not force then - report("use --force to really update files") - end - - resolvers.load_tree(texroot) -- else we operate in the wrong tree - - -- update filename database for pdftex/xetex - scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) - -- update filename database for luatex - scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) - - report("update, done") -end - -function table.fromhash(t) - local h = { } - for k, v in next, t do -- not indexed - if v then h[#h+1] = k end - end - return h -end - --- make the ConTeXt formats -function scripts.update.make() - - report("make, start") - - local force = environment.argument("force") - local texroot = scripts.update.fullpath(states.get("paths.root")) - local engines = states.get('engines') - local goodies = states.get('goodies') - local platforms = states.get('platforms') - local formats = states.get('formats') - - resolvers.load_tree(texroot) - - scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) - scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) - - local askedformats = formats - local texformats = table.tohash(scripts.update.texformats) - local mpformats = table.tohash(scripts.update.mpformats) - for k,v in next, texformats do - if not askedformats[k] then - texformats[k] = nil - end - end - for k,v in next, mpformats do - if not askedformats[k] then - mpformats[k] = nil - end - end - local formatlist = concat(table.fromhash(texformats), " ") - if formatlist ~= "" then - for engine in next, engines do - if engine == "luatex" then - scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make',texroot)) - elseif engine == "luajittex" then - scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make --engine=luajittex',texroot)) - else - scripts.update.run(format('mtxrun --tree="%s" --script texexec --make --all --%s %s',texroot,engine,formatlist)) - end - end - end - local formatlist = concat(table.fromhash(mpformats), " ") - if formatlist ~= "" then - scripts.update.run(format('mtxrun --tree="%s" --script texexec --make --all %s',texroot,formatlist)) - end - if not force then - report("make, use --force to really make formats") - end - - scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) -- needed for mpost - scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) - - report("make, done") -end - -scripts.savestate = true - -if scripts.savestate then - - states.load("status-of-update.lua") - - -- tag, value, default, persistent - - statistics.starttiming(states) - - states.set("info.version",0.1) -- ok - states.set("info.count",(states.get("info.count") or 0) + 1,1,false) -- ok - states.set("info.comment","this file contains the settings of the last 'mtxrun --script update' run",false) -- ok - states.set("info.date",os.date("!%Y-%m-%d %H:%M:%S")) -- ok - - states.set("rsync.program", environment.argument("rsync"), "rsync", true) -- ok - states.set("rsync.server", environment.argument("server"), "contextgarden.net::", true) -- ok - states.set("rsync.module", environment.argument("module"), "minimals", true) -- ok - states.set("rsync.flags.normal", environment.argument("flags"), "-rpztlv", true) -- ok - states.set("rsync.flags.delete", nil, "--delete", true) -- ok - - states.set("paths.root", environment.argument("texroot"), "tex", true) -- ok - - states.set("context.version", environment.argument("context"), "current", true) -- ok - - local valid = table.tohash(scripts.update.repositories) - for r in gmatch(environment.argument("repository") or "current","([^, ]+)") do - if valid[r] then states.set("repositories." .. r, true) end - end - - local valid = scripts.update.engines - local engine = environment.argument("engine") or "" - if engine == "" then - local e = states.get("engines") - if not e or not next(e) then - engine = "all" - end - end - if engine ~= "" then - for r in gmatch(engine,"([^, ]+)") do - if r == "all" then - for k, v in next, valid do - if k ~= "all" then - states.set("engines." .. k, true) - end - end - break - elseif valid[r] then - states.set("engines." .. r, true) - end - end - end - - local valid = scripts.update.platforms - for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do - if valid[r] then states.set("platforms." .. r, true) end - end - - local valid = table.tohash(scripts.update.texformats) - for r in gmatch(environment.argument("formats") or "","([^, ]+)") do - if valid[r] then states.set("formats." .. r, true) end - end - local valid = table.tohash(scripts.update.mpformats) - for r in gmatch(environment.argument("formats") or "","([^, ]+)") do - if valid[r] then states.set("formats." .. r, true) end - end - - states.set("formats.cont-en", true) - states.set("formats.cont-nl", true) - states.set("formats.metafun", true) - - for r in gmatch(environment.argument("extras") or "","([^, ]+)") do -- for old times sake - if r ~= "all" and not find(r,"^[a-z]%-") then - r = "t-" .. r - end - states.set("modules." .. r, true) - end - for r in gmatch(environment.argument("modules") or "","([^, ]+)") do - if r ~= "all" and not find(r,"^[a-z]%-") then - r = "t-" .. r - end - states.set("modules." .. r, true) - end - for r in gmatch(environment.argument("fonts") or "","([^, ]+)") do - states.set("fonts." .. r, true) - end - for r in gmatch(environment.argument("goodies") or "","([^, ]+)") do - states.set("goodies." .. r, true) - end - - report("state, loaded") - report() - -end - -if environment.argument("state") then - environment.setargument("update",true) - environment.setargument("force",true) - environment.setargument("make",true) -end - -if environment.argument("mingw") then - rsync_variant = "mingw" -elseif environment.argument("cygwin") then - rsync_variant = "cygwin" -end - -if environment.argument("update") then - scripts.update.synchronize() - if environment.argument("make") then - scripts.update.make() - end -elseif environment.argument("make") then - scripts.update.make() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end - -if scripts.savestate then - statistics.stoptiming(states) - states.set("info.runtime",tonumber(statistics.elapsedtime(states))) - if environment.argument("force") then - states.save() - report("state","saved") - end -end +if not modules then modules = { } end modules ['mtx-update'] = { + version = 1.002, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This script is dedicated to Mojca Miklavec, who is the driving force behind +-- moving minimal generation from our internal machines to the context garden. +-- Together with Arthur Reutenauer she made sure that it worked well on all +-- platforms that matter. + +local helpinfo = [[ + + + + mtx-update + ConTeXt Minimals Updater + 0.31 + + + + + platform (windows, linux, linux-64, osx-intel, osx-ppc, linux-ppc) + repository url (rsync://contextgarden.net) + repository url (minimals) + specify version (current, experimental) + specify version (current, latest, beta, yyyy.mm.dd) + rsync binary (rsync) + installation directory (not guessed for the moment) + tex engine (luatex, pdftex, xetex) + extra modules (can be list or 'all') + additional fonts (can be list or 'all') + extra binaries (like scite and texworks) + instead of a dryrun, do the real thing + update minimal tree + also make formats and generate file databases + don't delete unused or obsolete files + update tree using saved state + adapt drive specs to cygwin + assume mingw binaries being used + + + + +]] + +local application = logs.application { + name = "mtx-update", + banner = "ConTeXt Minimals Updater 0.31", + helpinfo = helpinfo, +} + +local report = application.report + +local format, concat, gmatch, gsub, find = string.format, table.concat, string.gmatch, string.gsub, string.find + +scripts = scripts or { } +scripts.update = scripts.update or { } + +minimals = minimals or { } +minimals.config = minimals.config or { } + +-- this is needed under windows +-- else rsync fails to set the right chmod flags to files + +os.setenv("CYGWIN","nontsec") + +scripts.update.texformats = { + "cont-en", + "cont-nl", + "cont-cz", + "cont-de", + "cont-fa", + "cont-it", + "cont-ro", + "cont-uk", + "cont-pe", + -- "cont-xp", + "mptopdf", + "plain" +} + +scripts.update.mpformats = { + -- "metafun", + -- "mpost", +} + +-- experimental is not functional at the moment + +scripts.update.repositories = { + "current", + "experimental" +} + +-- more options than just these two are available (no idea why this is here) + +scripts.update.versions = { + "current", + "latest" +} + +-- list of basic folders that are needed to make a functional distribution + +scripts.update.base = { + { "base/tex/", "texmf" }, + { "base/metapost/", "texmf" }, + { "fonts/common/", "texmf" }, + { "fonts/other/", "texmf" }, -- not *really* needed, but helpful + { "context//", "texmf-context" }, + { "misc/setuptex/", "." }, + { "misc/web2c", "texmf" }, + { "bin/common//", "texmf-" }, + { "bin/context//", "texmf-" }, + { "bin/metapost//", "texmf-" }, + { "bin/man/", "texmf-" }, +} + +-- binaries and font-related files +-- for pdftex we don't need OpenType fonts, for LuaTeX/XeTeX we don't need TFM files + +scripts.update.engines = { + ["luatex"] = { + { "fonts/new/", "texmf" }, + { "bin/luatex//", "texmf-" }, + { "bin/luajittex//","texmf-" }, + }, + ["xetex"] = { + { "base/xetex/", "texmf" }, + { "fonts/new/", "texmf" }, + { "bin/luatex//", "texmf-" }, -- tools + { "bin/xetex//", "texmf-" }, + }, + ["pdftex"] = { + { "fonts/old/", "texmf" }, + { "bin/luatex//", "texmf-" }, -- tools + { "bin/pdftex//", "texmf-" }, + }, + ["all"] = { + { "fonts/new/", "texmf" }, + { "fonts/old/", "texmf" }, + { "base/xetex/", "texmf" }, + { "bin/luatex//", "texmf-" }, + { "bin/luajittex//","texmf-" }, + { "bin/xetex//", "texmf-" }, + { "bin/pdftex//", "texmf-" }, + }, +} + +scripts.update.goodies = { + ["scite"] = { + { "bin//scite/", "texmf-" }, + }, + ["texworks"] = { + { "bin//texworks/", "texmf-" }, + }, +} + +scripts.update.platforms = { + ["mswin"] = "mswin", + ["windows"] = "mswin", + ["win32"] = "mswin", + ["win"] = "mswin", + ["linux"] = "linux", + ["freebsd"] = "freebsd", + ["freebsd-amd64"] = "freebsd-amd64", + ["kfreebsd"] = "kfreebsd-i386", + ["kfreebsd-i386"] = "kfreebsd-i386", + ["kfreebsd-amd64"] = "kfreebsd-amd64", + ["linux-32"] = "linux", + ["linux-64"] = "linux-64", + ["linux32"] = "linux", + ["linux64"] = "linux-64", + ["linux-ppc"] = "linux-ppc", + ["ppc"] = "linux-ppc", + ["osx"] = "osx-intel", + ["macosx"] = "osx-intel", + ["osx-intel"] = "osx-intel", + ["osx-ppc"] = "osx-ppc", + ["osx-powerpc"] = "osx-ppc", + ["osx-64"] = "osx-64", + ["osxintel"] = "osx-intel", + ["osxppc"] = "osx-ppc", + ["osxpowerpc"] = "osx-ppc", + ["solaris-intel"] = "solaris-intel", + ["solaris-sparc"] = "solaris-sparc", + ["solaris"] = "solaris-sparc", +} + +scripts.update.selfscripts = { + "mtxrun", + -- "luatools", +} + +-- the list is filled up later (when we know what modules to download) + +scripts.update.modules = { +} + +scripts.update.fonts = { +} + +function scripts.update.run(str) + -- important, otherwise formats fly to a weird place + -- (texlua sets luatex as the engine, we need to reset that or to fix texexec :) + os.setenv("engine",nil) + if environment.argument("force") then + report("run, %s",str) + os.execute(str) + else + report("dry run, %s",str) + end +end + +function scripts.update.fullpath(path) + if file.is_rootbased_path(path) then + return path + else + return lfs.currentdir() .. "/" .. path + end +end + +local rsync_variant = "cygwin" -- will be come mingw + +local function drive(d) + if rsync_variant == "cygwin" then + d = gsub(d,[[([a-zA-Z]):/]], "/cygdrive/%1/") + else + d = gsub(d,[[([a-zA-Z]):/]], "/%1/") + end + return d +end + +function scripts.update.synchronize() + + report("update, start") + + local texroot = scripts.update.fullpath(states.get("paths.root")) + local engines = states.get('engines') or { } + local platforms = states.get('platforms') or { } + local repositories = states.get('repositories') -- minimals + local bin = states.get("rsync.program") -- rsync + local url = states.get("rsync.server") -- contextgarden.net + local version = states.get("context.version") -- current (or beta) + local modules = states.get("modules") -- modules (third party) + local fonts = states.get("fonts") -- fonts (experimental or special) + local goodies = states.get("goodies") -- goodies (like editors) + local force = environment.argument("force") + + bin = gsub(bin,"\\","/") + + if not url:find("::$") then url = url .. "::" end + local ok = lfs.attributes(texroot,"mode") == "directory" + if not ok and force then + dir.mkdirs(texroot) + ok = lfs.attributes(texroot,"mode") == "directory" + end + + if force then + dir.mkdirs(format("%s/%s", texroot, "texmf-cache")) + dir.mkdirs(format("%s/%s", texroot, "texmf-local")) + dir.mkdirs(format("%s/%s", texroot, "texmf-project")) + dir.mkdirs(format("%s/%s", texroot, "texmf-fonts")) + dir.mkdirs(format("%s/%s", texroot, "texmf-modules")) + end + + if ok or not force then + + local fetched, individual, osplatform = { }, { }, os.platform + + -- takes a collection as argument and returns a list of folders + + local function collection_to_list_of_folders(collection, platform) + local archives = {} + for i=1,#collection do + local archive = collection[i][1] + archive = gsub(archive,"",platform) + archive = gsub(archive,"",version) + archives[#archives+1] = archive + end + return archives + end + + -- takes a list of folders as argument and returns a string for rsync + -- sample input: + -- {'bin/common', 'bin/context'} + -- output: + -- 'minimals/current/bin/common minimals/current/bin/context' + + local function list_of_folders_to_rsync_string(list_of_folders) + local repository = 'current' + local prefix = format("%s/%s/", states.get('rsync.module'), repository) -- minimals/current/ + + return prefix .. concat(list_of_folders, format(" %s", prefix)) + end + + -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(scripts.update.base, os.platform))) + + -- rename function and add some more functionality: + -- * recursive/non-recursive (default: non-recursive) + -- * filter folders or regular files only (default: no filter) + -- * grep for size of included files (with --stats switch) + + local function get_list_of_files_from_rsync(list_of_folders) + -- temporary file to store the output of rsync (could be a more random name; watch for overwrites) + local temp_file = "rsync.tmp.txt" + -- a set of folders + local folders = {} + local command = format("%s %s'%s' > %s", bin, url, list_of_folders_to_rsync_string(list_of_folders), temp_file) + os.execute(command) + -- read output of rsync + local data = io.loaddata(temp_file) or "" + -- for every line extract the filename + for chmod, s in data:gmatch("([d%-][rwx%-]+).-(%S+)[\n\r]") do + -- skip "current" folder + if s ~= '.' and chmod:len() == 10 then + folders[#folders+1] = s + end + end + -- delete the file to which we have put output of rsync + os.remove(temp_file) + return folders + end + + -- rsync://contextgarden.net/minimals/current/modules/ + + if modules and type(modules) == "table" then + -- fetch the list of available modules from rsync server + local available_modules = get_list_of_files_from_rsync({"modules/"}) + -- hash of requested modules + -- local h = table.tohash(modules:split(",")) + local asked = table.copy(modules) + asked.all = nil + for i=1,#available_modules do + local s = available_modules[i] + if modules.all or modules[s] then + scripts.update.modules[#scripts.update.modules+1] = { format("modules/%s/",s), "texmf-modules" } + end + asked[s] = nil + end + if next(asked) then + report("skipping unknown modules: %s",table.concat(table.sortedkeys(asked),", ")) + end + end + + -- rsync://contextgarden.net/minimals/current/fonts/extra/ + + if fonts and type(fonts) == "table" then + local available_fonts = get_list_of_files_from_rsync({"fonts/extra/"}) + local asked = table.copy(fonts) + asked.all = nil + for i=1,#available_fonts do + local s = available_fonts[i] + if fonts.all or fonts[s] then + scripts.update.fonts[#scripts.update.fonts+1] = { format("fonts/extra/%s/",s), "texmf" } + end + asked[s] = nil + end + if next(asked) then + report("skipping unknown fonts: %s",table.concat(table.sortedkeys(asked),", ")) + end + end + + local function add_collection(collection,platform) + if collection and platform then + platform = scripts.update.platforms[platform] + if platform then + for i=1,#collection do + local c = collection[i] + local archive = gsub(c[1],"",platform) + local destination = format("%s/%s", texroot, gsub(c[2],"", platform)) + destination = gsub(destination,"\\","/") + archive = gsub(archive,"",version) + if osplatform == "windows" or osplatform == "mswin" then + destination = drive(destination) + end + individual[#individual+1] = { archive, destination } + end + end + end + end + + for platform, _ in next, platforms do + add_collection(scripts.update.base,platform) + end + for platform, _ in next, platforms do + add_collection(scripts.update.modules,platform) + end + for platform, _ in next, platforms do + add_collection(scripts.update.fonts,platform) + end + for engine, _ in next, engines do + for platform, _ in next, platforms do + add_collection(scripts.update.engines[engine],platform) + end + end + + if goodies and type(goodies) == "table" then + for goodie, _ in next, goodies do + for platform, _ in next, platforms do + add_collection(scripts.update.goodies[goodie],platform) + end + end + end + + local combined = { } + local update_repositories = scripts.update.repositories + for i=1,#update_repositories do + local repository = update_repositories[i] + if repositories[repository] then + for _, v in next, individual do + local archive, destination = v[1], v[2] + local cd = combined[destination] + if not cd then + cd = { } + combined[destination] = cd + end + cd[#cd+1] = format("%s/%s/%s",states.get('rsync.module'),repository,archive) + end + end + end + for destination, archive in next, combined do + local archives, command = concat(archive," "), "" + local normalflags, deleteflags = states.get("rsync.flags.normal"), "" + if os.name == "windows" then + normalflags = normalflags .. " -L" -- no symlinks + end + local dryrunflags = "" + if not environment.argument("force") then + dryrunflags = "--dry-run" + end + if (destination:find("texmf$") or destination:find("texmf%-context$") or destination:find("texmf%-modules$")) and (not environment.argument("keep")) then + deleteflags = states.get("rsync.flags.delete") + end + command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, destination) + -- report("running command: %s",command) + if not fetched[command] then + scripts.update.run(command,true) + fetched[command] = command + end + end + + local function update_script(script, platform) + local bin = gsub(bin,"\\","/") + local texroot = gsub(texroot,"\\","/") + platform = scripts.update.platforms[platform] + if platform then + local command + if platform == 'mswin' then + bin = drive(bin) + texroot = drive(texroot) + command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-mswin/bin/"]], bin, texroot, script, texroot) + else + command = format([[%s -tgo --chmod=a+x '%s/texmf-context/scripts/context/lua/%s.lua' '%s/texmf-%s/bin/%s']], bin, texroot, script, texroot, platform, script) + end + report("updating %s for %s: %s", script, platform, command) + scripts.update.run(command) + end + end + + for platform, _ in next, platforms do + for i=1, #scripts.update.selfscripts do + update_script(scripts.update.selfscripts[i],platform) + end + end + + else + report("no valid texroot: %s",texroot) + end + if not force then + report("use --force to really update files") + end + + resolvers.load_tree(texroot) -- else we operate in the wrong tree + + -- update filename database for pdftex/xetex + scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) + -- update filename database for luatex + scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) + + report("update, done") +end + +function table.fromhash(t) + local h = { } + for k, v in next, t do -- not indexed + if v then h[#h+1] = k end + end + return h +end + +-- make the ConTeXt formats +function scripts.update.make() + + report("make, start") + + local force = environment.argument("force") + local texroot = scripts.update.fullpath(states.get("paths.root")) + local engines = states.get('engines') + local goodies = states.get('goodies') + local platforms = states.get('platforms') + local formats = states.get('formats') + + resolvers.load_tree(texroot) + + scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) + scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) + + local askedformats = formats + local texformats = table.tohash(scripts.update.texformats) + local mpformats = table.tohash(scripts.update.mpformats) + for k,v in next, texformats do + if not askedformats[k] then + texformats[k] = nil + end + end + for k,v in next, mpformats do + if not askedformats[k] then + mpformats[k] = nil + end + end + local formatlist = concat(table.fromhash(texformats), " ") + if formatlist ~= "" then + for engine in next, engines do + if engine == "luatex" then + scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make',texroot)) + elseif engine == "luajittex" then + scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make --engine=luajittex',texroot)) + else + scripts.update.run(format('mtxrun --tree="%s" --script texexec --make --all --%s %s',texroot,engine,formatlist)) + end + end + end + local formatlist = concat(table.fromhash(mpformats), " ") + if formatlist ~= "" then + scripts.update.run(format('mtxrun --tree="%s" --script texexec --make --all %s',texroot,formatlist)) + end + if not force then + report("make, use --force to really make formats") + end + + scripts.update.run(format('mtxrun --tree="%s" --direct --resolve mktexlsr',texroot)) -- needed for mpost + scripts.update.run(format('mtxrun --tree="%s" --generate',texroot)) + + report("make, done") +end + +scripts.savestate = true + +if scripts.savestate then + + states.load("status-of-update.lua") + + -- tag, value, default, persistent + + statistics.starttiming(states) + + states.set("info.version",0.1) -- ok + states.set("info.count",(states.get("info.count") or 0) + 1,1,false) -- ok + states.set("info.comment","this file contains the settings of the last 'mtxrun --script update' run",false) -- ok + states.set("info.date",os.date("!%Y-%m-%d %H:%M:%S")) -- ok + + states.set("rsync.program", environment.argument("rsync"), "rsync", true) -- ok + states.set("rsync.server", environment.argument("server"), "contextgarden.net::", true) -- ok + states.set("rsync.module", environment.argument("module"), "minimals", true) -- ok + states.set("rsync.flags.normal", environment.argument("flags"), "-rpztlv", true) -- ok + states.set("rsync.flags.delete", nil, "--delete", true) -- ok + + states.set("paths.root", environment.argument("texroot"), "tex", true) -- ok + + states.set("context.version", environment.argument("context"), "current", true) -- ok + + local valid = table.tohash(scripts.update.repositories) + for r in gmatch(environment.argument("repository") or "current","([^, ]+)") do + if valid[r] then states.set("repositories." .. r, true) end + end + + local valid = scripts.update.engines + local engine = environment.argument("engine") or "" + if engine == "" then + local e = states.get("engines") + if not e or not next(e) then + engine = "all" + end + end + if engine ~= "" then + for r in gmatch(engine,"([^, ]+)") do + if r == "all" then + for k, v in next, valid do + if k ~= "all" then + states.set("engines." .. k, true) + end + end + break + elseif valid[r] then + states.set("engines." .. r, true) + end + end + end + + local valid = scripts.update.platforms + for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do + if valid[r] then states.set("platforms." .. r, true) end + end + + local valid = table.tohash(scripts.update.texformats) + for r in gmatch(environment.argument("formats") or "","([^, ]+)") do + if valid[r] then states.set("formats." .. r, true) end + end + local valid = table.tohash(scripts.update.mpformats) + for r in gmatch(environment.argument("formats") or "","([^, ]+)") do + if valid[r] then states.set("formats." .. r, true) end + end + + states.set("formats.cont-en", true) + states.set("formats.cont-nl", true) + states.set("formats.metafun", true) + + for r in gmatch(environment.argument("extras") or "","([^, ]+)") do -- for old times sake + if r ~= "all" and not find(r,"^[a-z]%-") then + r = "t-" .. r + end + states.set("modules." .. r, true) + end + for r in gmatch(environment.argument("modules") or "","([^, ]+)") do + if r ~= "all" and not find(r,"^[a-z]%-") then + r = "t-" .. r + end + states.set("modules." .. r, true) + end + for r in gmatch(environment.argument("fonts") or "","([^, ]+)") do + states.set("fonts." .. r, true) + end + for r in gmatch(environment.argument("goodies") or "","([^, ]+)") do + states.set("goodies." .. r, true) + end + + report("state, loaded") + report() + +end + +if environment.argument("state") then + environment.setargument("update",true) + environment.setargument("force",true) + environment.setargument("make",true) +end + +if environment.argument("mingw") then + rsync_variant = "mingw" +elseif environment.argument("cygwin") then + rsync_variant = "cygwin" +end + +if environment.argument("update") then + scripts.update.synchronize() + if environment.argument("make") then + scripts.update.make() + end +elseif environment.argument("make") then + scripts.update.make() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end + +if scripts.savestate then + statistics.stoptiming(states) + states.set("info.runtime",tonumber(statistics.elapsedtime(states))) + if environment.argument("force") then + states.save() + report("state","saved") + end +end diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua index 95323f571..aa9b9262d 100644 --- a/scripts/context/lua/mtx-watch.lua +++ b/scripts/context/lua/mtx-watch.lua @@ -1,431 +1,431 @@ -if not modules then modules = { } end modules ['mtx-watch'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local helpinfo = [[ - - - - mtx-watch - ConTeXt Request Watchdog - 1.00 - - - - - optional path for log files - watch given path [ - use pipe instead of execute - delay between sweeps - replace /machine/ in path /servername/ - condense log files - remove files in given path [ - show log data - - - - -]] - -local application = logs.application { - name = "mtx-watch", - banner = "ConTeXt Request Watchdog 1.00", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.watch = scripts.watch or { } - -local format, concat, difftime, time = string.format, table.concat, os.difftime, os.time -local next, type = next, type -local basename, dirname, joinname = file.basename, file.dirname, file.join -local lfsdir, lfsattributes = lfs.dir, lfs.attributes - --- the machine/instance matches the server app we use - -local machine = socket.dns.gethostname() or "unknown-machine" -local instance = string.match(machine,"(%d+)$") or "0" - -function scripts.watch.save_exa_modes(joblog,ctmname) - local values = joblog and joblog.values - if values then - local t= { } - t[#t+1] = "\n" - t[#t+1] = "" - for k, v in next, joblog.values do - t[#t+1] = format("\t%s", k, tostring(v)) - end - t[#t+1] = "" - io.savedata(ctmname,concat(t,"\n")) - else - os.remove(ctmname) - end -end - -local function toset(t) - if type(t) == "table" then - return concat(t,",") - else - return t - end -end - -local function noset(t) - if type(t) == "table" then - return t[1] - else - return t - end -end - --- todo: split order (o-name.luj) and combine with atime to determine sort order. - -local function glob(files,path) -- some day: sort by name (order prefix) and atime - for name in lfsdir(path) do - if name:find("^%.") then - -- skip . and .. - else - name = path .. "/" .. name - local a = lfsattributes(name) - if not a then - -- weird - elseif a.mode == "directory" then - if name:find("graphics$") or name:find("figures$") or name:find("resources$") then - -- skip these too - else - glob(files,name) - end - elseif name:find(".%luj$") then - local bname = basename(name) - local dname = dirname(name) - local order = tonumber(bname:match("^(%d+)")) or 0 - files[#files+1] = { dname, bname, order } - end - end - end -end - -local clock = os.gettimeofday or (socket and socket.gettime) or os.time -- we cannot trust os.clock on linux - --- local function filenamesort(a,b) --- local fa, da = a[1], a[2] --- local fb, db = b[1], b[2] --- if da == db then --- return fa < fb --- else --- return da < db --- end --- end - -local function filenamesort(a,b) - local fa, oa = a[2], a[3] - local fb, ob = b[2], b[3] - if fa == fb then - if oa == ob then - return a[1] < b[1] -- order file dir - else - return oa < ob -- order file - end - else - if oa == ob then - return fa < fb -- order file - else - return oa < ob -- order file - end - end -end - -function scripts.watch.watch() - local delay = tonumber(environment.argument("delay") or 5) or 5 - if delay == 0 then - delay = .25 - end - local logpath = environment.argument("logpath") or "" - local pipe = environment.argument("pipe") or false - local watcher = "mtxwatch.run" - local paths = environment.files - if #paths > 0 then - if environment.argument("automachine") then - logpath = string.gsub(logpath,"/machine/","/"..machine.."/") - for i=1,#paths do - paths[i] = string.gsub(paths[i],"/machine/","/"..machine.."/") - end - end - for i=1,#paths do - report("watching path %s",paths[i]) - end - local function process() - local done = false - for i=1,#paths do - local path = paths[i] - lfs.chdir(path) - local files = { } - glob(files,path) - table.sort(files,filenamesort) --- for name, time in next, files do - for i=1,#files do - local f = files[i] - local dirname = f[1] - local basename = f[2] -- we can use that later on - local name = joinname(dirname,basename) - --~ local ok, joblog = xpcall(function() return dofile(name) end, function() end ) - local ok, joblog = pcall(dofile,name) - if ok and joblog then - if joblog.status == "processing" then - report("aborted job, %s added to queue",name) - joblog.status = "queued" - io.savedata(name, table.serialize(joblog,true)) - elseif joblog.status == "queued" then - local command = joblog.command - if command then - local replacements = { - inputpath = toset((joblog.paths and joblog.paths.input ) or "."), - outputpath = noset((joblog.paths and joblog.paths.output) or "."), - filename = joblog.filename or "", - } - -- todo: revision path etc - command = command:gsub("%%(.-)%%", replacements) - if command ~= "" then - joblog.status = "processing" - joblog.runtime = clock() - io.savedata(name, table.serialize(joblog,true)) - report("running: %s", command) - local newpath = file.dirname(name) - io.flush() - local result = "" - local ctmname = file.basename(replacements.filename) - if ctmname == "" then ctmname = name end -- use self as fallback - ctmname = file.replacesuffix(ctmname,"ctm") - if newpath ~= "" and newpath ~= "." then - local oldpath = lfs.currentdir() - lfs.chdir(newpath) - scripts.watch.save_exa_modes(joblog,ctmname) - if pipe then result = os.resultof(command) else result = os.spawn(command) end - lfs.chdir(oldpath) - else - scripts.watch.save_exa_modes(joblog,ctmname) - if pipe then result = os.resultof(command) else result = os.spawn(command) end - end - report("return value: %s", result) - done = true - local path, base = replacements.outputpath, file.basename(replacements.filename) - joblog.runtime = clock() - joblog.runtime - if base ~= "" then - joblog.result = file.replacesuffix(file.join(path,base),"pdf") - joblog.size = lfs.attributes(joblog.result,"size") - end - joblog.status = "finished" - else - joblog.status = "invalid command" - end - else - joblog.status = "no command" - end - -- pcall, when error sleep + again - -- todo: just one log file and append - io.savedata(name, table.serialize(joblog,true)) - if logpath and logpath ~= "" then - local name = file.join(logpath,os.uuid() .. ".lua") - io.savedata(name, table.serialize(joblog,true)) - report("saving joblog in %s",name) - end - end - end - end - end - end - local n, start = 0, time() - local wtime = 0 - local function wait() - io.flush() - if not done then - n = n + 1 - if n >= 10 then - report("run time: %i seconds, memory usage: %0.3g MB", difftime(time(),start), (status.luastate_bytes/1024)/1000) - n = 0 - end - local ttime = 0 - while ttime <= delay do - local wt = lfs.attributes(watcher,"mtime") - if wt and wt ~= wtime then - -- fast signal that there is a request - wtime = wt - break - end - ttime = ttime + 0.2 - os.sleep(0.2) - end - end - end - local cleanupdelay, cleanup = environment.argument("cleanup"), false - if cleanupdelay then - local lasttime = time() - cleanup = function() - local currenttime = time() - local delta = difftime(currenttime,lasttime) - if delta > cleanupdelay then - lasttime = currenttime - for i=1,#paths do - local path = paths[i] - if string.find(path,"%.") then - -- safeguard, we want a fully qualified path - else - local files = dir.glob(file.join(path,"*")) - for i=1,#files do - local name = files[i] - local filetime = lfs.attributes(name,"modification") - local delta = difftime(currenttime,filetime) - if delta > cleanupdelay then - -- report("cleaning up '%s'",name) - os.remove(name) - end - end - end - end - end - end - else - cleanup = function() - -- nothing - end - end - while true do - if false then ---~ if true then - process() - cleanup() - wait() - else - pcall(process) - pcall(cleanup) - pcall(wait) - end - end - else - report("no paths to watch") - end -end - -function scripts.watch.collect_logs(path) -- clean 'm up too - path = path or environment.argument("logpath") or "" - path = (path == "" and ".") or path - local files = dir.globfiles(path,false,"^%d+%.lua$") - local collection = { } - local valid = table.tohash({"filename","result","runtime","size","status"}) - for i=1,#files do - local name = files[i] - local t = dofile(name) - if t and type(t) == "table" and t.status then - for k, v in next, t do - if not valid[k] then - t[k] = nil - end - end - collection[name:gsub("[^%d]","")] = t - end - end - return collection -end - -function scripts.watch.save_logs(collection,path) -- play safe - if collection and next(collection) then - path = path or environment.argument("logpath") or "" - path = (path == "" and ".") or path - local filename = format("%s/collected-%s.lua",path,tostring(time())) - io.savedata(filename,table.serialize(collection,true)) - local check = dofile(filename) - for k,v in next, check do - if not collection[k] then - report("error in saving file") - os.remove(filename) - return false - end - end - for k,v in next, check do - os.remove(format("%s.lua",k)) - end - return true - else - return false - end -end - -function scripts.watch.collect_collections(path) -- removes duplicates - path = path or environment.argument("logpath") or "" - path = (path == "" and ".") or path - local files = dir.globfiles(path,false,"^collected%-%d+%.lua$") - local collection = { } - for i=1,#files do - local name = files[i] - local t = dofile(name) - if t and type(t) == "table" then - for k, v in next, t do - collection[k] = v - end - end - end - return collection -end - -function scripts.watch.show_logs(path) -- removes duplicates - local collection = scripts.watch.collect_collections(path) or { } - local max = 0 - for k,v in next, collection do - v = v.filename or "?" - if #v > max then max = #v end - end - -- print(max) - local sorted = table.sortedkeys(collection) - for k=1,#sorted do - local v = sorted[k] - local c = collection[v] - local f, s, r, n = c.filename or "?", c.status or "?", c.runtime or 0, c.size or 0 - report("%s %s %3i %8i %s",string.padd(f,max," "),string.padd(s,10," "),r,n,v) - end -end - -function scripts.watch.cleanup_stale_files() -- removes duplicates - local path = environment.files[1] - local delay = tonumber(environment.argument("cleanup")) - local force = environment.argument("force") - if not path or path == "." then - report("provide qualified path") - elseif not delay then - report("missing --cleanup=delay") - else - report("dryrun, use --force for real cleanup") - local files = dir.glob(file.join(path,"*")) - local rtime = time() - for i=1,#files do - local name = files[i] - local mtime = lfs.attributes(name,"modification") - local delta = difftime(rtime,mtime) - if delta > delay then - report("cleaning up '%s'",name) - if force then - os.remove(name) - end - end - end - end -end - -if environment.argument("watch") then - scripts.watch.watch() -elseif environment.argument("collect") then - scripts.watch.save_logs(scripts.watch.collect_logs()) -elseif environment.argument("cleanup") then - scripts.watch.save_logs(scripts.watch.cleanup_stale_files()) -elseif environment.argument("showlog") then - scripts.watch.show_logs() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-watch'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local helpinfo = [[ + + + + mtx-watch + ConTeXt Request Watchdog + 1.00 + + + + + optional path for log files + watch given path [ + use pipe instead of execute + delay between sweeps + replace /machine/ in path /servername/ + condense log files + remove files in given path [ + show log data + + + + +]] + +local application = logs.application { + name = "mtx-watch", + banner = "ConTeXt Request Watchdog 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.watch = scripts.watch or { } + +local format, concat, difftime, time = string.format, table.concat, os.difftime, os.time +local next, type = next, type +local basename, dirname, joinname = file.basename, file.dirname, file.join +local lfsdir, lfsattributes = lfs.dir, lfs.attributes + +-- the machine/instance matches the server app we use + +local machine = socket.dns.gethostname() or "unknown-machine" +local instance = string.match(machine,"(%d+)$") or "0" + +function scripts.watch.save_exa_modes(joblog,ctmname) + local values = joblog and joblog.values + if values then + local t= { } + t[#t+1] = "\n" + t[#t+1] = "" + for k, v in next, joblog.values do + t[#t+1] = format("\t%s", k, tostring(v)) + end + t[#t+1] = "" + io.savedata(ctmname,concat(t,"\n")) + else + os.remove(ctmname) + end +end + +local function toset(t) + if type(t) == "table" then + return concat(t,",") + else + return t + end +end + +local function noset(t) + if type(t) == "table" then + return t[1] + else + return t + end +end + +-- todo: split order (o-name.luj) and combine with atime to determine sort order. + +local function glob(files,path) -- some day: sort by name (order prefix) and atime + for name in lfsdir(path) do + if name:find("^%.") then + -- skip . and .. + else + name = path .. "/" .. name + local a = lfsattributes(name) + if not a then + -- weird + elseif a.mode == "directory" then + if name:find("graphics$") or name:find("figures$") or name:find("resources$") then + -- skip these too + else + glob(files,name) + end + elseif name:find(".%luj$") then + local bname = basename(name) + local dname = dirname(name) + local order = tonumber(bname:match("^(%d+)")) or 0 + files[#files+1] = { dname, bname, order } + end + end + end +end + +local clock = os.gettimeofday or (socket and socket.gettime) or os.time -- we cannot trust os.clock on linux + +-- local function filenamesort(a,b) +-- local fa, da = a[1], a[2] +-- local fb, db = b[1], b[2] +-- if da == db then +-- return fa < fb +-- else +-- return da < db +-- end +-- end + +local function filenamesort(a,b) + local fa, oa = a[2], a[3] + local fb, ob = b[2], b[3] + if fa == fb then + if oa == ob then + return a[1] < b[1] -- order file dir + else + return oa < ob -- order file + end + else + if oa == ob then + return fa < fb -- order file + else + return oa < ob -- order file + end + end +end + +function scripts.watch.watch() + local delay = tonumber(environment.argument("delay") or 5) or 5 + if delay == 0 then + delay = .25 + end + local logpath = environment.argument("logpath") or "" + local pipe = environment.argument("pipe") or false + local watcher = "mtxwatch.run" + local paths = environment.files + if #paths > 0 then + if environment.argument("automachine") then + logpath = string.gsub(logpath,"/machine/","/"..machine.."/") + for i=1,#paths do + paths[i] = string.gsub(paths[i],"/machine/","/"..machine.."/") + end + end + for i=1,#paths do + report("watching path %s",paths[i]) + end + local function process() + local done = false + for i=1,#paths do + local path = paths[i] + lfs.chdir(path) + local files = { } + glob(files,path) + table.sort(files,filenamesort) +-- for name, time in next, files do + for i=1,#files do + local f = files[i] + local dirname = f[1] + local basename = f[2] -- we can use that later on + local name = joinname(dirname,basename) + --~ local ok, joblog = xpcall(function() return dofile(name) end, function() end ) + local ok, joblog = pcall(dofile,name) + if ok and joblog then + if joblog.status == "processing" then + report("aborted job, %s added to queue",name) + joblog.status = "queued" + io.savedata(name, table.serialize(joblog,true)) + elseif joblog.status == "queued" then + local command = joblog.command + if command then + local replacements = { + inputpath = toset((joblog.paths and joblog.paths.input ) or "."), + outputpath = noset((joblog.paths and joblog.paths.output) or "."), + filename = joblog.filename or "", + } + -- todo: revision path etc + command = command:gsub("%%(.-)%%", replacements) + if command ~= "" then + joblog.status = "processing" + joblog.runtime = clock() + io.savedata(name, table.serialize(joblog,true)) + report("running: %s", command) + local newpath = file.dirname(name) + io.flush() + local result = "" + local ctmname = file.basename(replacements.filename) + if ctmname == "" then ctmname = name end -- use self as fallback + ctmname = file.replacesuffix(ctmname,"ctm") + if newpath ~= "" and newpath ~= "." then + local oldpath = lfs.currentdir() + lfs.chdir(newpath) + scripts.watch.save_exa_modes(joblog,ctmname) + if pipe then result = os.resultof(command) else result = os.spawn(command) end + lfs.chdir(oldpath) + else + scripts.watch.save_exa_modes(joblog,ctmname) + if pipe then result = os.resultof(command) else result = os.spawn(command) end + end + report("return value: %s", result) + done = true + local path, base = replacements.outputpath, file.basename(replacements.filename) + joblog.runtime = clock() - joblog.runtime + if base ~= "" then + joblog.result = file.replacesuffix(file.join(path,base),"pdf") + joblog.size = lfs.attributes(joblog.result,"size") + end + joblog.status = "finished" + else + joblog.status = "invalid command" + end + else + joblog.status = "no command" + end + -- pcall, when error sleep + again + -- todo: just one log file and append + io.savedata(name, table.serialize(joblog,true)) + if logpath and logpath ~= "" then + local name = file.join(logpath,os.uuid() .. ".lua") + io.savedata(name, table.serialize(joblog,true)) + report("saving joblog in %s",name) + end + end + end + end + end + end + local n, start = 0, time() + local wtime = 0 + local function wait() + io.flush() + if not done then + n = n + 1 + if n >= 10 then + report("run time: %i seconds, memory usage: %0.3g MB", difftime(time(),start), (status.luastate_bytes/1024)/1000) + n = 0 + end + local ttime = 0 + while ttime <= delay do + local wt = lfs.attributes(watcher,"mtime") + if wt and wt ~= wtime then + -- fast signal that there is a request + wtime = wt + break + end + ttime = ttime + 0.2 + os.sleep(0.2) + end + end + end + local cleanupdelay, cleanup = environment.argument("cleanup"), false + if cleanupdelay then + local lasttime = time() + cleanup = function() + local currenttime = time() + local delta = difftime(currenttime,lasttime) + if delta > cleanupdelay then + lasttime = currenttime + for i=1,#paths do + local path = paths[i] + if string.find(path,"%.") then + -- safeguard, we want a fully qualified path + else + local files = dir.glob(file.join(path,"*")) + for i=1,#files do + local name = files[i] + local filetime = lfs.attributes(name,"modification") + local delta = difftime(currenttime,filetime) + if delta > cleanupdelay then + -- report("cleaning up '%s'",name) + os.remove(name) + end + end + end + end + end + end + else + cleanup = function() + -- nothing + end + end + while true do + if false then +--~ if true then + process() + cleanup() + wait() + else + pcall(process) + pcall(cleanup) + pcall(wait) + end + end + else + report("no paths to watch") + end +end + +function scripts.watch.collect_logs(path) -- clean 'm up too + path = path or environment.argument("logpath") or "" + path = (path == "" and ".") or path + local files = dir.globfiles(path,false,"^%d+%.lua$") + local collection = { } + local valid = table.tohash({"filename","result","runtime","size","status"}) + for i=1,#files do + local name = files[i] + local t = dofile(name) + if t and type(t) == "table" and t.status then + for k, v in next, t do + if not valid[k] then + t[k] = nil + end + end + collection[name:gsub("[^%d]","")] = t + end + end + return collection +end + +function scripts.watch.save_logs(collection,path) -- play safe + if collection and next(collection) then + path = path or environment.argument("logpath") or "" + path = (path == "" and ".") or path + local filename = format("%s/collected-%s.lua",path,tostring(time())) + io.savedata(filename,table.serialize(collection,true)) + local check = dofile(filename) + for k,v in next, check do + if not collection[k] then + report("error in saving file") + os.remove(filename) + return false + end + end + for k,v in next, check do + os.remove(format("%s.lua",k)) + end + return true + else + return false + end +end + +function scripts.watch.collect_collections(path) -- removes duplicates + path = path or environment.argument("logpath") or "" + path = (path == "" and ".") or path + local files = dir.globfiles(path,false,"^collected%-%d+%.lua$") + local collection = { } + for i=1,#files do + local name = files[i] + local t = dofile(name) + if t and type(t) == "table" then + for k, v in next, t do + collection[k] = v + end + end + end + return collection +end + +function scripts.watch.show_logs(path) -- removes duplicates + local collection = scripts.watch.collect_collections(path) or { } + local max = 0 + for k,v in next, collection do + v = v.filename or "?" + if #v > max then max = #v end + end + -- print(max) + local sorted = table.sortedkeys(collection) + for k=1,#sorted do + local v = sorted[k] + local c = collection[v] + local f, s, r, n = c.filename or "?", c.status or "?", c.runtime or 0, c.size or 0 + report("%s %s %3i %8i %s",string.padd(f,max," "),string.padd(s,10," "),r,n,v) + end +end + +function scripts.watch.cleanup_stale_files() -- removes duplicates + local path = environment.files[1] + local delay = tonumber(environment.argument("cleanup")) + local force = environment.argument("force") + if not path or path == "." then + report("provide qualified path") + elseif not delay then + report("missing --cleanup=delay") + else + report("dryrun, use --force for real cleanup") + local files = dir.glob(file.join(path,"*")) + local rtime = time() + for i=1,#files do + local name = files[i] + local mtime = lfs.attributes(name,"modification") + local delta = difftime(rtime,mtime) + if delta > delay then + report("cleaning up '%s'",name) + if force then + os.remove(name) + end + end + end + end +end + +if environment.argument("watch") then + scripts.watch.watch() +elseif environment.argument("collect") then + scripts.watch.save_logs(scripts.watch.collect_logs()) +elseif environment.argument("cleanup") then + scripts.watch.save_logs(scripts.watch.cleanup_stale_files()) +elseif environment.argument("showlog") then + scripts.watch.show_logs() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end -- cgit v1.2.3