diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/context/lua/luatools.lua | 164 | ||||
-rw-r--r-- | scripts/context/lua/mtx-context.lua | 44 | ||||
-rw-r--r-- | scripts/context/lua/mtx-fonts.lua | 20 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server-ctx-fonttest.lua | 244 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server-ctx-help.lua | 64 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server-ctx-startup.lua | 32 | ||||
-rw-r--r-- | scripts/context/lua/mtx-timing.lua | 41 | ||||
-rw-r--r-- | scripts/context/lua/mtx-tools.lua | 89 | ||||
-rw-r--r-- | scripts/context/lua/mtx-update.lua | 6 | ||||
-rw-r--r-- | scripts/context/lua/mtx-watch.lua | 266 | ||||
-rw-r--r-- | scripts/context/lua/mtxrun.lua | 272 | ||||
-rw-r--r-- | scripts/context/stubs/mswin/luatools.lua | 164 | ||||
-rw-r--r-- | scripts/context/stubs/mswin/mtxrun.lua | 272 | ||||
-rwxr-xr-x | scripts/context/stubs/unix/luatools | 164 | ||||
-rwxr-xr-x | scripts/context/stubs/unix/mtxrun | 272 |
15 files changed, 1387 insertions, 727 deletions
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua index 6feb7a9c5..06e2a1bfc 100644 --- a/scripts/context/lua/luatools.lua +++ b/scripts/context/lua/luatools.lua @@ -233,6 +233,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1756,59 +1770,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2343,6 +2352,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing) end end -local seperator = comma * space^0 +local separator = comma * space^0 local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern = lpeg.Ct(value*(seperator*value)^0) +local pattern = lpeg.Ct(value*(separator*value)^0) -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored @@ -3187,7 +3225,7 @@ local function set(t,v) end local value = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(seperator*value)^0 * lpeg.Carg(1) +local pattern = value*(separator*value)^0 * lpeg.Carg(1) function aux.add_settings_to_array(t,str) return pattern:match(str, nil, t) @@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t) return t end +local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace +local pattern = lpeg.Ct((space + value)^0) + +function aux.arguments_to_table(str) + return pattern:match(str) +end + -- temporary here function aux.getparameters(self,class,parentclass,settings) @@ -4068,7 +4113,7 @@ end -- of closure do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['luat-log'] = { +if not modules then modules = { } end modules ['trac-log'] = { version = 1.001, comment = "companion to trac-log.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4345,8 +4390,12 @@ end logs.simpleline = logs.reportline -function logs.help(message,option) +function logs.reportbanner() -- for scripts too logs.report(banner) +end + +function logs.help(message,option) + logs.reportbanner() logs.reportline() logs.reportlines(message) local moreinfo = logs.moreinfo or "" @@ -4509,6 +4558,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -5728,9 +5782,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 40ab67eff..9ce164ab3 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -1390,27 +1390,36 @@ logs.extendbanner("ConTeXt Process Management 0.51",true) messages.help = [[ --run process (one or more) files (default action) --make create context formats ---generate generate file database etc. ---ctx=name use ctx file ---version report installed context version + +--ctx=name use ctx file (process management specification) +--interface use specified user interface (default: en) + +--autopdf close pdf file in viewer and start pdf viewer afterwards +--purge(all) purge files either or not after a run (--pattern=...) + +--usemodule=list load the given module or style, normally part o fthe distribution +--environment=list load the given environment file first (document styles) +--mode=list enable given the modes (conditional processing in styles) +--path=list also consult the given paths when files are looked for +--arguments=list set variables that can be consulted during a run (key/value pairs) +--randomseed=number set the randomseed +--result=name rename the resulting output to the given name +--trackers=list show/set tracker variables +--directives=list show/set directive variables + --forcexml force xml stub (optional flag: --mkii) --forcecld force cld (context lua document) stub ---autopdf close pdf file in viewer and start pdf viewer afterwards ---once only one run ---purge(all) purge files (--pattern=...) ---result=name rename result to given name ---arrange run extra arrange pass ---noarrange ignore arrange commands in the file + +--arrange run extra imposition pass, given that the style sets up imposition +--noarrange ignore imposition specifications in the style + +--once only run once (no multipass data file is produced) --batchmode run without stopping and don't show messages on the console --nonstopmode run without stopping ---usemodule=list load the given module (or style) ---environment=list load the given file first ---mode=list enable given the mode(s) ---path=list also consult the given paths when files are looked for + +--generate generate file database etc. (as luatools does) --paranoid don't descend to .. and ../.. ---randomseed=number set the randomseed ---arguments=list set variables that can be consulted during a run (key/value pairs) ---interface use specified user interface +--version report installed context version --expert expert options ]] @@ -1430,11 +1439,8 @@ expert options: --nostats omit runtime statistics at the end of the run --update update context from website (not to be confused with contextgarden) --profile profile job (use: mtxrun --script profile --analyse) ---trackers show/set tracker variables ---directives show/set directive variables --timing generate timing and statistics overview --tracefiles show some extra info when locating files (at the tex end) ---randomseed --extra=name process extra (mtx-context-<name> in distribution) --extras show extras diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index bc93eaaa9..03c3eb068 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -96,20 +96,6 @@ local function showfeatures(tag,specification) logs.reportline() end -local function make_pattern(pattern) -- will become helper in string - pattern = pattern:lower() - pattern = pattern:gsub("%-","%%-") - pattern = pattern:gsub("%.","%%.") - pattern = pattern:gsub("%*",".*") - pattern = pattern:gsub("%?",".?") - if pattern == "" then - pattern = ".*" - else ---~ pattern = "^" .. pattern .. "$" - end - return pattern -end - local function reloadbase(reload) if reload then logs.simple("fontnames, reloading font database") @@ -195,7 +181,7 @@ function scripts.fonts.list() if environment.argument("name") then if pattern then --~ mtxrun --script font --list --name --pattern=*somename* - list_matches(fonts.names.list(make_pattern(pattern),reload,all)) + list_matches(fonts.names.list(string.topattern(pattern,true),reload,all)) elseif filter then logs.report("fontnames","not supported: --list --name --filter",name) elseif given then @@ -220,7 +206,7 @@ function scripts.fonts.list() elseif environment.argument("file") then if pattern then --~ mtxrun --script font --list --file --pattern=*somename* - list_specifications(fonts.names.collectfiles(make_pattern(pattern),reload,all)) + list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all)) elseif filter then logs.report("fontnames","not supported: --list --spec",name) elseif given then @@ -231,7 +217,7 @@ function scripts.fonts.list() end elseif pattern then --~ mtxrun --script font --list --pattern=*somename* - list_matches(fonts.names.list(make_pattern(pattern),reload,all)) + list_matches(fonts.names.list(string.topattern(pattern,true),reload,all)) elseif given then --~ mtxrun --script font --list somename list_matches(fonts.names.list(given,reload,all)) diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua index f3a5d7690..23a3b5d11 100644 --- a/scripts/context/lua/mtx-server-ctx-fonttest.lua +++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua @@ -147,9 +147,10 @@ local cache = { } local function showfeatures(f) if f then + logs.simple("processing font '%s'",f) local features = cache[f] if features == nil then - features = fonts.get_features(f) + features = fonts.get_features(resolvers.find_file(f)) if not features then logs.simple("building cache for '%s'",f) io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f)) @@ -217,25 +218,50 @@ local function showfeatures(f) end end +local template_h = [[ +<tr> + <th>safe name </th> + <th>family name </th> + <th>style-variant-weight-width </th> + <th>font name </th> + <th>weight </th> + <th>filename</th> +</tr>]] + +local template_d = [[ +<tr> + <td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a> </td> + <td>%s </td> + <td>%s-%s-%s-%s </td> + <td>%s </td> + <td>%s </td> + <td>%s</td> +</tr>]] + local function select_font() - local t = fonts.names.list(".*") + local t = fonts.names.list(".*",false,true) if t then local listoffonts = { } - local t = fonts.names.list(".*") - if t then - listoffonts[#listoffonts+1] = "<table>" - listoffonts[#listoffonts+1] = "<tr><th>safe name</th><th>font name</th><th>filename</th><th>sub font </th><th>type</th></tr>" - for k, id in ipairs(table.sortedkeys(t)) do - local ti = t[id] - local type, name, file, sub = ti[1], ti[2], ti[3], ti[4] - if type == "otf" or type == "ttf" or type == "ttc" then - if sub then sub = "(sub)" else sub = "" end - listoffonts[#listoffonts+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",id,id,name,file,sub,type) - end + listoffonts[#listoffonts+1] = "<table>" + listoffonts[#listoffonts+1] = template_h + for k, v in table.sortedpairs(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 - listoffonts[#listoffonts+1] = "</table>" - return concat(listoffonts,"\n") end + listoffonts[#listoffonts+1] = "</table>" + return concat(listoffonts,"\n") end return "<b>no fonts</b>" end @@ -260,59 +286,67 @@ local result_template = [[ scripts.webserver.registerpath(temppath) +local function get_specification(name) + return fonts.names.resolvedspecification(name or "") +end + local function edit_font(currentfont,detail,tempname) - local fontname, fontfile, issub = fonts.names.specification(currentfont or "") - local htmldata = showfeatures(fontfile) - if htmldata then - local features, languages, scripts, options = { }, { }, { }, { } - for k,v in ipairs(table.sortedkeys(htmldata.scripts)) do - local s = fonts.otf.tables.scripts[v] or v - if detail and v == detail.script then - scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/> <span id='t-s-%s'>%s</span>",s,v,v,v,v) - else - scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' /> <span id='t-s-%s'>%s</span>",s,v,v,v,v) + logs.simple("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 = { }, { }, { }, { } + for k,v in ipairs(table.sortedkeys(htmldata.scripts)) do + local s = fonts.otf.tables.scripts[v] or v + if detail and v == detail.script then + scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/> <span id='t-s-%s'>%s</span>",s,v,v,v,v) + else + scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' /> <span id='t-s-%s'>%s</span>",s,v,v,v,v) + end end - end - for k,v in ipairs(table.sortedkeys(htmldata.languages)) do - local l = fonts.otf.tables.languages[v] or v - if detail and v == detail.language then - languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/> <span id='t-l-%s'>%s</span>",l,v,v,v,v) - else - languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' /> <span id='t-l-%s'>%s</span>",l,v,v,v,v) + for k,v in ipairs(table.sortedkeys(htmldata.languages)) do + local l = fonts.otf.tables.languages[v] or v + if detail and v == detail.language then + languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/> <span id='t-l-%s'>%s</span>",l,v,v,v,v) + else + languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' /> <span id='t-l-%s'>%s</span>",l,v,v,v,v) + end end - end - for k,v in ipairs(table.sortedkeys(htmldata.features)) do - local f = fonts.otf.tables.features[v] or v - if detail and detail["f-"..v] then - features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/> <span id='t-f-%s'>%s</span>",f,v,v,v,v) - else - features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' /> <span id='t-f-%s'>%s</span>",f,v,v,v,v) + for k,v in ipairs(table.sortedkeys(htmldata.features)) do + local f = fonts.otf.tables.features[v] or v + if detail and detail["f-"..v] then + features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/> <span id='t-f-%s'>%s</span>",f,v,v,v,v) + else + features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' /> <span id='t-f-%s'>%s</span>",f,v,v,v,v) + end end - end - for k, v in ipairs { "trace", "basemode" } do - if detail and detail["o-"..v] then - options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/> %s",v,v,v) + for k, v in ipairs { "trace", "basemode" } do + if detail and detail["o-"..v] then + options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/> %s",v,v,v) + else + options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/> %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 - options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/> %s",v,v,v) + return e, htmldata.javascript or "" 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 "" + return "error, nothing set up yet" end else - return "error, nothing set up yet" + return "error, no info about font" end end local function process_font(currentfont,detail) -- maybe just fontname - local fontname, fontfile, issub = fonts.names.specification(currentfont or "") local features = { "mode=node", format("language=%s",detail.language or "dflt"), @@ -361,14 +395,27 @@ local function show_log(currentfont,detail) end local function show_font(currentfont,detail) - local fontname, fontfile, issub = fonts.names.specification(currentfont or "") - local features = fonts.get_features(fontfile) + local specification = get_specification(currentfont) + local features = fonts.get_features(specification.filename) local result = { } result[#result+1] = format("<h1>names</h1>",what) result[#result+1] = "<table>" - result[#result+1] = format("<tr><td class='tc'>fontname:</td><td>%s</td></tr>",currentfont) - result[#result+1] = format("<tr><td class='tc'>fullname:</td><td>%s</td></tr>",fontname) - result[#result+1] = format("<tr><td class='tc'>filename:</td><td>%s</td></tr>",fontfile) + result[#result+1] = format("<tr><td class='tc'>fontname: </td><td>%s</td></tr>",currentfont) + result[#result+1] = format("<tr><td class='tc'>fullname: </td><td>%s</td></tr>",specification.fontname or "-") + result[#result+1] = format("<tr><td class='tc'>filename: </td><td>%s</td></tr>",specification.fontfile or "-") + result[#result+1] = format("<tr><td class='tc'>familyname: </td><td>%s</td></tr>",specification.familyname or "-") + result[#result+1] = format("<tr><td class='tc'>fontweight: </td><td>%s</td></tr>",specification.fontweight or "-") + result[#result+1] = format("<tr><td class='tc'>format: </td><td>%s</td></tr>",specification.format or "-") + result[#result+1] = format("<tr><td class='tc'>fullname: </td><td>%s</td></tr>",specification.fullname or "-") + result[#result+1] = format("<tr><td class='tc'>subfamily: </td><td>%s</td></tr>",specification.subfamily or "-") + result[#result+1] = format("<tr><td class='tc'>rawname: </td><td>%s</td></tr>",specification.rawname or "-") + result[#result+1] = format("<tr><td class='tc'>designsize: </td><td>%s</td></tr>",specification.designsize or "-") + result[#result+1] = format("<tr><td class='tc'>minimumsize:</td><td>%s</td></tr>",specification.minsize or "-") + result[#result+1] = format("<tr><td class='tc'>maximumsize:</td><td>%s</td></tr>",specification.maxsize or "-") + result[#result+1] = format("<tr><td class='tc'>style: </td><td>%s</td></tr>",specification.style ~= "" and specification.style or "normal") + result[#result+1] = format("<tr><td class='tc'>variant: </td><td>%s</td></tr>",specification.variant ~= "" and specification.variant or "normal") + result[#result+1] = format("<tr><td class='tc'>weight: </td><td>%s</td></tr>",specification.weight ~= "" and specification.weight or "normal") + result[#result+1] = format("<tr><td class='tc'>width: </td><td>%s</td></tr>",specification.width ~= "" and specification.width or "normal") result[#result+1] = "</table>" if features then for what, v in table.sortedpairs(features) do @@ -486,10 +533,10 @@ local function deletestored(detail,currentfont,name) end local function save_font(currentfont,detail) - local fontname, fontfile, issub = fonts.names.specification(currentfont or "") + local specification = get_specification(currentfont) local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, "" if detail then - local htmldata = showfeatures(fontfile) + local htmldata = showfeatures(specification.filename) script = detail.script or script language = detail.language or language text = string.strip(detail.sampletext or text) @@ -519,7 +566,7 @@ local function load_font(currentfont) local result = {} result[#result+1] = format("<tr><th>del </th><th>name </th><th>font </th><th>fontname </th><th>script </th><th>language </th><th>features </th><th>title </th><th>sampletext </th></tr>") for k,v in table.sortedpairs(storage) do - local fontname, fontfile, issub = fonts.names.specification(v.font or "") + local fontname, fontfile = get_specification(v.font) result[#result+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?deletename=%s'>x</a> </td><td><a href='mtx-server-ctx-fonttest.lua?loadname=%s'>%s</a> </td><td>%s </td<td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td></tr>", k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "") end @@ -562,6 +609,13 @@ local status_template = [[ <input type="hidden" name="currentfont" value="%s" /> ]] +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() @@ -589,65 +643,49 @@ function doit(configuration,filename,hashed) action = "extras" end - lmx.restore() - - local fontname, fontfile, issub = fonts.names.specification(currentfont or "") + local fontname, fontfile = get_specification(currentfont) if fontfile then - lmx.variables['title-default'] = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) + variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) else - lmx.variables['title-default'] = 'ConTeXt Font Tester' + variables.title = 'ConTeXt Font Tester' end - lmx.variables['color-background-green'] = '#4F6F6F' - lmx.variables['color-background-blue'] = '#6F6F8F' - lmx.variables['color-background-yellow'] = '#8F8F6F' - lmx.variables['color-background-purple'] = '#8F6F8F' - - lmx.variables['color-background-body'] = '#808080' - lmx.variables['color-background-main'] = '#3F3F3F' - lmx.variables['color-background-one'] = lmx.variables['color-background-green'] - lmx.variables['color-background-two'] = lmx.variables['color-background-blue'] - - lmx.variables['title'] = lmx.variables['title-default'] - - lmx.set('title', lmx.get('title')) - lmx.set('color-background-one', lmx.get('color-background-green')) - lmx.set('color-background-two', lmx.get('color-background-blue')) - -- lua table and adapt - lmx.set('formaction', "mtx-server-ctx-fonttest.lua") - local menu = { } for k, v in ipairs { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} do menu[#menu+1] = format("<button name='action' value='%s' type='submit'>%s</button>",v,v) end - lmx.set('menu', concat(menu," ")) - logs.simple("action: %s",action or "no action") + variables.menu = concat(menu," ") + variables.status = format(status_template,currentfont or "") + variables.maintext = "" + variables.javascriptdata = "" + variables.javascripts = "" + variables.javascriptinit = "" - lmx.set("status",format(status_template,currentfont or "")) + logs.simple("action: %s",action or "no action") local result if action == "select" then - lmx.set('maintext',select_font()) + variables.maintext = select_font() elseif action == "info" then - lmx.set('maintext',info_about()) + variables.maintext = info_about() elseif action == "extras" then - lmx.set('maintext',do_extras()) + variables.maintext = do_extras() elseif currentfont and currentfont ~= "" then if action == "save" then - lmx.set('maintext',save_font(currentfont,detail)) + variables.maintext = save_font(currentfont,detail) elseif action == "load" then - lmx.set('maintext',load_font(currentfont,detail)) + variables.maintext = load_font(currentfont,detail) elseif action == "source" then - lmx.set('maintext',show_source(currentfont,detail)) + variables.maintext = show_source(currentfont,detail) elseif action == "log" then - lmx.set('maintext',show_log(currentfont,detail)) + variables.maintext = show_log(currentfont,detail) elseif action == "features" then - lmx.set('maintext',show_font(currentfont,detail)) + variables.maintext = show_font(currentfont,detail) else local e, s if action == "process" then @@ -659,16 +697,16 @@ function doit(configuration,filename,hashed) else e, s = process_font(currentfont,detail) end - lmx.set('maintext',e) - lmx.set('javascriptdata',s) - lmx.set('javascripts',javascripts) - lmx.set('javascriptinit', "check_form()") + variables.maintext = e + variables.javascriptdata = s + variables.javascripts = javascripts + variables.javascriptinit = "check_form()" end else - lmx.set('maintext',select_font()) + variables.maintext = select_font() end - result = { content = lmx.convert('context-fonttest.lmx') } + result = { content = lmx.convert('context-fonttest.lmx',false,variables) } logs.simple("time spent on page: %0.03f seconds",os.clock()-start) diff --git a/scripts/context/lua/mtx-server-ctx-help.lua b/scripts/context/lua/mtx-server-ctx-help.lua index d77cc66e8..b6c97118b 100644 --- a/scripts/context/lua/mtx-server-ctx-help.lua +++ b/scripts/context/lua/mtx-server-ctx-help.lua @@ -548,25 +548,6 @@ end tex = tex or { } -lmx.variables['color-background-green'] = '#4F6F6F' -lmx.variables['color-background-blue'] = '#6F6F8F' -lmx.variables['color-background-yellow'] = '#8F8F6F' -lmx.variables['color-background-purple'] = '#8F6F8F' - -lmx.variables['color-background-body'] = '#808080' -lmx.variables['color-background-main'] = '#3F3F3F' -lmx.variables['color-background-main-left'] = '#3F3F3F' -lmx.variables['color-background-main-right'] = '#5F5F5F' -lmx.variables['color-background-one'] = lmx.variables['color-background-green'] -lmx.variables['color-background-two'] = lmx.variables['color-background-blue'] - -lmx.variables['title-default'] = 'ConTeXt Help Information' -lmx.variables['title'] = lmx.variables['title-default'] - -function lmx.loadedfile(filename) - return io.loaddata(resolvers.find_file(filename)) -- return resolvers.texdatablob(filename) -end - -- -- -- local interfaces = { @@ -582,6 +563,18 @@ local interfaces = { local lastinterface, lastcommand, lastsource, lastmode = "en", "", "", 1 +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.find_file(filename)) -- return resolvers.texdatablob(filename) +--~ end + local function doit(configuration,filename,hashed) local formats = document.setups.formats @@ -615,34 +608,32 @@ local function doit(configuration,filename,hashed) end end - lmx.restore() - lmx.set('title', 'ConTeXt Help Information') - lmx.set('color-background-one', lmx.get('color-background-green')) - lmx.set('color-background-two', lmx.get('color-background-blue')) - local n = concat(refs,"<br/>") local i = concat(ints,"<br/><br/>") if div then - lmx.set('names',div:format(n)) - lmx.set('interfaces',div:format(i)) + variables.names = div:format(n) + variables.interfaces = div:format(i) else - lmx.set('names', n) - lmx.set('interfaces', i) + 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.find_file(lastsource)) - lmx.set('maintitle', lastsource) - lmx.set('maintext', formats.listing:format(data)) + variables.maintitle = lastsource + variables.maintext = formats.listing:format(data) lastsource = "" elseif lastcommand and lastcommand ~= "" then local data = document.setups.collect(lastcommand,lastinterface,lastmode) if data then - lmx.set('maintitle', data.sequence) local extra = { } for k, v in ipairs { "environment", "category", "source", "mode" } do if data[v] and data[v] ~= "" then @@ -650,16 +641,15 @@ local function doit(configuration,filename,hashed) extra[#extra+1] = v .. ": " .. data[v] end end - lmx.set('extra', concat(extra," ")) - lmx.set('maintext', formats.parameters:format(concat(data.parameters))) + variables.maintitle = data.sequence + variables.maintext = formats.parameters:format(concat(data.parameters)) + variables.extra = concat(extra," ") else - lmx.set('maintext', "select command") + variables.maintext = "select command" end - else - lmx.set('maintext', "no definition") end - local content = lmx.convert('context-help.lmx') + local content = lmx.convert('context-help.lmx',false,variables) logs.simple("time spent on page: %0.03f seconds",os.clock()-start) diff --git a/scripts/context/lua/mtx-server-ctx-startup.lua b/scripts/context/lua/mtx-server-ctx-startup.lua index fcb757b3e..59536c36c 100644 --- a/scripts/context/lua/mtx-server-ctx-startup.lua +++ b/scripts/context/lua/mtx-server-ctx-startup.lua @@ -10,25 +10,6 @@ dofile(resolvers.find_file("trac-lmx.lua","tex")) function doit(configuration,filename,hashed) - lmx.restore() - - lmx.variables['color-background-green'] = '#4F6F6F' - lmx.variables['color-background-blue'] = '#6F6F8F' - lmx.variables['color-background-yellow'] = '#8F8F6F' - lmx.variables['color-background-purple'] = '#8F6F8F' - - lmx.variables['color-background-body'] = '#808080' - lmx.variables['color-background-main'] = '#3F3F3F' - lmx.variables['color-background-one'] = lmx.variables['color-background-green'] - lmx.variables['color-background-two'] = lmx.variables['color-background-blue'] - - lmx.variables['title'] = "Overview Of Goodies" - - lmx.set('title', lmx.get('title')) - lmx.set('color-background-one', lmx.get('color-background-green')) - lmx.set('color-background-two', lmx.get('color-background-blue')) - - local list = { } local root = file.dirname(resolvers.find_file("mtx-server.lua") or ".") if root == "" then root = "." end @@ -42,11 +23,16 @@ function doit(configuration,filename,hashed) end end - lmx.set('maintext',table.concat(list,"\n")) - - result = { content = lmx.convert('context-base.lmx') } + 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 result + return { content = lmx.convert('context-base.lmx',false,variables) } end diff --git a/scripts/context/lua/mtx-timing.lua b/scripts/context/lua/mtx-timing.lua index 375d5d90b..a9a0c8745 100644 --- a/scripts/context/lua/mtx-timing.lua +++ b/scripts/context/lua/mtx-timing.lua @@ -124,50 +124,39 @@ function goodies.progress.valid_file(name) end function goodies.progress.make_lmx_page(name,launch,remove) + local filename = name .. "-luatex-progress" local other = "elapsed_time" local template = 'context-timing.lmx' - lmx.variables['color-background-green'] = '#4F6F6F' - lmx.variables['color-background-blue'] = '#6F6F8F' - lmx.variables['color-background-yellow'] = '#8F8F6F' - lmx.variables['color-background-purple'] = '#8F6F8F' - - lmx.variables['color-background-body'] = '#808080' - lmx.variables['color-background-main'] = '#3F3F3F' - lmx.variables['color-background-one'] = lmx.variables['color-background-green'] - lmx.variables['color-background-two'] = lmx.variables['color-background-blue'] - - lmx.variables['title-default'] = 'ConTeXt Timing Information' - lmx.variables['title'] = lmx.variables['title-default'] - - lmx.htmfile = function(name) return name .. "-timing.xhtml" end - lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end - - lmx.set('title', format('ConTeXt Timing Information: %s',file.basename(name))) - lmx.set('color-background-one', lmx.get('color-background-green')) - lmx.set('color-background-two', lmx.get('color-background-blue')) - goodies.progress.convert(filename) local menudata, metadata = goodies.progress.make_svg(filename,other) local htmldata = goodies.progress.makehtml(filename,other,menudata,metadata) - lmx.set('parametersmenu', concat(htmldata.parameters, " ")) - lmx.set('nodesmenu', concat(htmldata.nodes, " ")) - lmx.set('graphics', concat(htmldata.graphics, "\n\n")) + lmx.htmfile = function(name) return name .. "-timing.xhtml" end + lmx.lmxfile = function(name) return resolvers.find_file(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) + local htmfile = lmx.show(template,variables) if remove then os.sleep(1) -- give time to launch os.remove(htmfile) end else - lmx.make(template) + lmx.make(template,variables) end - lmx.restore() end scripts = scripts or { } diff --git a/scripts/context/lua/mtx-tools.lua b/scripts/context/lua/mtx-tools.lua index ca2faaf29..5c90df071 100644 --- a/scripts/context/lua/mtx-tools.lua +++ b/scripts/context/lua/mtx-tools.lua @@ -6,9 +6,7 @@ if not modules then modules = { } end modules ['mtx-tools'] = { license = "see context related readme files" } --- data tables by Thomas A. Schmitz - -local find, gsub = string.find, string.gsub +local find, format, sub, rep, gsub = string.find, string.format, string.sub, string.rep, string.gsub scripts = scripts or { } scripts.tools = scripts.tools or { } @@ -44,14 +42,97 @@ function scripts.tools.disarmutfbomb() end end -logs.extendbanner("Some File Related Goodies 1.00",true) +function scripts.tools.dirtoxml() + + local join, removesuffix, extname, date = file.join, file.removesuffix, file.extname, 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') + 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.sortedpairs(list) do + local mode = attr.mode + if mode == "file" then + result[#result+1] = format("%s<file name='%s'>",d,(longname and path and join(path,name)) or name) + result[#result+1] = format("%s <base>%s</base>",d,removesuffix(name)) + result[#result+1] = format("%s <type>%s</type>",d,extname(name)) + result[#result+1] = format("%s <size>%s</size>",d,attr.size) + result[#result+1] = format("%s <permissions>%s</permissions>",d,sub(attr.permissions,7,9)) + result[#result+1] = format("%s <date>%s</date>",d,date(timestamp,attr.modification)) + result[#result+1] = format("%s</file>",d) + elseif mode == "directory" then + result[#result+1] = format("%s<directory name='%s'>",d,name) + flush(attr.list,result,n+1,(path and join(path,name)) or name) + result[#result+1] = format("%s</directory>",d) + end + end + end + + if not pattern or pattern == "" then + logs.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.collect_pattern(root,luapattern,recurse) + + if list[outputfile] then + list[outputfile] = nil + end + + local result = { "<?xml version='1.0'?>" } + result[#result+1] = format("<files url=%q root=%q pattern=%q luapattern=%q xmlns='%s' timestamp='%s'>",url,root,pattern,luapattern,xmlns,date(timestamp)) + flush(list,result) + result[#result+1] = "</files>" + + result = table.concat(result,"\n") + + if not outputfile or outputfile == "" then + texio.write_nl(result) + else + io.savedata(outputfile,result) + end + +end + +logs.extendbanner("Some File Related Goodies 1.01",true) messages.help = [[ --disarmutfbomb remove utf bomb if present + --force remove indeed + +--dirtoxml glob directory into xml + --pattern glob pattern (default: .*) + --url url attribute (no processing) + --root the root of the globbed path (default: .) + --output output filename (console by default) + --recurse recurse into subdirecories + --stripname take pathpart of given pattern + --longname set name attributes to full path name ]] if environment.argument("disarmutfbomb") then scripts.tools.disarmutfbomb() +elseif environment.argument("dirtoxml") then + scripts.tools.dirtoxml() else logs.help(messages.help) end diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 61d6b0d84..48df6862a 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -195,7 +195,7 @@ function scripts.update.synchronize() if ok or not force then - local fetched, individual, osplatform = { }, { }, os.currentplatform() + local fetched, individual, osplatform = { }, { }, os.platform -- takes a collection as argument and returns a list of folders @@ -223,7 +223,7 @@ function scripts.update.synchronize() 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.currentplatform))) + -- 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) @@ -507,7 +507,7 @@ if scripts.savestate then end end local valid = scripts.update.platforms - for r in gmatch(environment.argument("platform") or os.currentplatform(),"([^, ]+)") do + for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do if valid[r] then states.set("platforms." .. r, true) end end diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua index 44f61ae6b..9cfe2bbfd 100644 --- a/scripts/context/lua/mtx-watch.lua +++ b/scripts/context/lua/mtx-watch.lua @@ -9,160 +9,168 @@ if not modules then modules = { } end modules ['mtx-watch'] = { scripts = scripts or { } scripts.watch = scripts.watch or { } -do - - function scripts.watch.save_exa_modes(joblog,ctmname) - local t= { } - if joblog then - t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n" - t[#t+1] = "<exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>" - if joblog.values then - for k, v in pairs(joblog.values) do - t[#t+1] = string.format("\t<exa:variable label='%s'>%s</exa:variable>", k, tostring(v)) - end - else - t[#t+1] = "<!-- no modes -->" +function scripts.watch.save_exa_modes(joblog,ctmname) + local t= { } + if joblog then + t[#t+1] = "<?xml version='1.0' standalone='yes'?>\n" + t[#t+1] = "<exa:variables xmlns:exa='htpp://www.pragma-ade.com/schemas/exa-variables.rng'>" + if joblog.values then + for k, v in pairs(joblog.values) do + t[#t+1] = string.format("\t<exa:variable label='%s'>%s</exa:variable>", k, tostring(v)) end - t[#t+1] = "</exa:variables>" + else + t[#t+1] = "<!-- no modes -->" end - os.remove(ctmname) - io.savedata(ctmname,table.concat(t,"\n")) + t[#t+1] = "</exa:variables>" end + os.remove(ctmname) + io.savedata(ctmname,table.concat(t,"\n")) +end - function scripts.watch.watch() - local delay = environment.argument("delay") or 5 - local logpath = environment.argument("logpath") or "" - local pipe = environment.argument("pipe") or false - if #environment.files > 0 then - for _, path in ipairs(environment.files) do - logs.report("watch", "watching path ".. path) - end - local function glob(files,path) - for name in lfs.dir(path) do - if name:find("^%.") then - -- skip . and .. - else - name = path .. "/" .. name - local a = lfs.attributes(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 - files[name] = a.change or a.ctime or a.modification or a.mtime - end - end - end - end - local function toset(t) - if type(t) == "table" then - return table.concat(t,",") - else - return t - end - end - local function noset(t) - if type(t) == "table" then - return t[1] +local function toset(t) + if type(t) == "table" then + return table.concat(t,",") + else + return t + end +end + +local function noset(t) + if type(t) == "table" then + return t[1] + else + return t + end +end + +local lfsdir, lfsattributes = lfs.dir, lfs.attributes + +local function glob(files,path) + 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 - return t + glob(files,name) end + elseif name:find(".%luj$") then + files[name] = a.change or a.ctime or a.modification or a.mtime end - local function process() - local done = false - for _, path in ipairs(environment.files) do - lfs.chdir(path) - local files = { } - glob(files,path) - table.sort(files) -- what gets sorted here - for name, time in pairs(files) do - --~ 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 - logs.report("watch",string.format("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 "", - } - command = command:gsub("%%(.-)%%", replacements) - if command ~= "" then - joblog.status = "processing" - joblog.runtime = os.time() -- os.clock() - io.savedata(name, table.serialize(joblog,true)) - logs.report("watch",string.format("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 - logs.report("watch",string.format("return value: %s", result)) - done = true - local path, base = replacements.outputpath, file.basename(replacements.filename) - joblog.runtime = os.time() - joblog.runtime -- os.clock() - joblog.runtime + end + end +end + +function scripts.watch.watch() + local delay = environment.argument("delay") or 5 + local logpath = environment.argument("logpath") or "" + local pipe = environment.argument("pipe") or false + if #environment.files > 0 then + for _, path in ipairs(environment.files) do + logs.report("watch", "watching path ".. path) + end + local function process() + local done = false + for _, path in ipairs(environment.files) do + lfs.chdir(path) + local files = { } + glob(files,path) + table.sort(files) -- what gets sorted here + for name, time in pairs(files) do + --~ 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 + logs.report("watch",string.format("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 "", + } + command = command:gsub("%%(.-)%%", replacements) + if command ~= "" then + joblog.status = "processing" + joblog.runtime = os.clock() + io.savedata(name, table.serialize(joblog,true)) + logs.report("watch",string.format("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 + logs.report("watch",string.format("return value: %s", result)) + done = true + local path, base = replacements.outputpath, file.basename(replacements.filename) + joblog.runtime = os.clock() - joblog.runtime + if base ~= "" then joblog.result = file.replacesuffix(file.join(path,base),"pdf") joblog.size = lfs.attributes(joblog.result,"size") - joblog.status = "finished" - else - joblog.status = "invalid command" end + joblog.status = "finished" else - joblog.status = "no command" + joblog.status = "invalid command" end - -- pcall, when error sleep + again + else + joblog.status = "no command" + end + -- pcall, when error sleep + again + io.savedata(name, table.serialize(joblog,true)) + if logpath ~= "" then + local name = string.format("%s/%s%04i%09i.lua", logpath, os.time(), math.floor((os.clock()*100)%1000), math.random(99999999)) io.savedata(name, table.serialize(joblog,true)) - if logpath ~= "" then - local name = string.format("%s/%s%04i%09i.lua", logpath, os.time(), math.floor((os.clock()*100)%1000), math.random(99999999)) - io.savedata(name, table.serialize(joblog,true)) - logs.report("watch", "saving joblog ".. name) - end + logs.report("watch", "saving joblog ".. name) end end end end end - local n, start = 0, os.clock() - local function wait() - io.flush() - if not done then - n = n + 1 - if n >= 10 then - logs.report("watch", string.format("run time: %i seconds, memory usage: %0.3g MB", os.clock() - start, (status.luastate_bytes/1024)/1000)) - n = 0 - end - os.sleep(delay) + end + local n, start = 0, os.clock() + local function wait() + io.flush() + if not done then + n = n + 1 + if n >= 10 then + logs.report("watch", string.format("run time: %i seconds, memory usage: %0.3g MB", os.clock() - start, (status.luastate_bytes/1024)/1000)) + n = 0 end + os.sleep(delay) end - while true do + end + while true do + if false then + process() + wait() + else pcall(process) pcall(wait) end - else - logs.report("watch", "no paths to watch") end + else + logs.report("watch", "no paths to watch") end - end function scripts.watch.collect_logs(path) -- clean 'm up too diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index a1fc6eaf5..c5b0acd04 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -242,6 +242,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1765,59 +1779,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2241,6 +2250,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -7264,6 +7302,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -8483,9 +8526,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end @@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate prefixes.file = prefixes.filename prefixes.path = prefixes.pathname +function resolvers.allprefixes(separator) + local all = table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i] = all[i] .. ":" + end + end + return all +end + local function _resolve_(method,target) if prefixes[method] then return prefixes[method](target) @@ -10130,43 +10183,109 @@ local trace_locating = false trackers.register("resolvers.locating", function(v local gsub = string.gsub -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -local libpaths = file.split_path(package.path) +local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +local clibformats = { 'lib' } +local libpaths = file.split_path(package.path) +local clibpaths = file.split_path(package.cpath) + +local function thepath(...) + local t = { ... } t[#t+1] = "?.lua" + local path = file.join(unpack(t)) + if trace_locating then + logs.report("fileio","! appending '%s' to 'package.path'",path) + end + return path +end + +function package.append_libpath(...) + table.insert(libpaths,thepath(...)) +end + +function package.prepend_libpath(...) + table.insert(libpaths,1,thepath(...)) +end + +-- beware, we need to return a loadfile result ! package.loaders[2] = function(name) -- was [#package.loaders+1] ---~ package.loaders[#package.loaders+1] = function(name) -- was + if trace_locating then -- mode detail + logs.report("fileio","! locating '%s'",name) + end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.find_file(name,format) or "" + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format) + end if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end end - local simple = file.removesuffix(name) + local simple = gsub(name,"%.lua$","") + local simple = gsub(simple,"%.","/") for i=1,#libpaths do -- package.path, might become option - local resolved = gsub(libpaths[i],"?",simple) + local libpath = libpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath) + end if resolvers.isreadable.file(resolved) then if trace_locating then logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) + end + end + local libname = file.addsuffix(simple,os.libsuffix) + for i=1,#clibformats do + -- better have a dedicated loop + local format = clibformats[i] + local paths = resolvers.expanded_path_list_from_var(format) + for p=1,#paths do + local path = paths[p] + local resolved = file.join(path,libname) + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved) + end + return package.loadlib(resolved,name) + end + end + end + for i=1,#clibpaths do -- package.path, might become option + local libpath = clibpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved) + end + return package.loadlib(resolved,name) end end -- just in case the distribution is messed up + if trace_loading then -- more detail + logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name) + end local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or "" if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end if trace_locating then logs.report("fileio",'? unable to locate lib: %s',name) end - return "unable to locate " .. name +-- return "unable to locate " .. name end resolvers.loadlualib = require @@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = { function resolvers.check_environment(tree) logs.simpleline() os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME')) - os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform())) + os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform)) os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",'')) os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS')) logs.simpleline() @@ -10723,10 +10842,11 @@ runners = runners or { } -- global messages = messages or { } messages.help = [[ ---script run an mtx script (--noquotes), no script gives list ---execute run a script or program (--noquotes) +--script run an mtx script (lua prefered method) (--noquotes), no script gives list +--execute run a script or program (texmfstart method) (--noquotes) --resolve resolve prefixed arguments --ctxlua run internally (using preloaded libs) +--internal run script using built in libraries (same as --ctxlua) --locate locate given filename --autotree use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree' @@ -10750,11 +10870,13 @@ messages.help = [[ --edit launch editor with found file --launch (--all) launch files like manuals, assumes os support ---internal run script using built in libraries (same as --ctxlua) --timedrun run a script an time its run +--autogenerate regenerate databases if needed (handy when used to run context in an editor) --usekpse use kpse as fallback (when no mkiv and cache installed, often slower) --forcekpse force using kpse (handy when no mkiv and cache installed but less functionality) + +--prefixes show supported prefixes ]] runners.applications = { @@ -10800,6 +10922,13 @@ runners.launchers = { unix = { } } +-- like runners.libpath("framework"): looks on script's subpath + +function runners.libpath(...) + package.prepend_libpath(file.dirname(environment.ownscript),...) + package.prepend_libpath(file.dirname(environment.ownname) ,...) +end + function runners.prepare() local checkname = environment.argument("ifchanged") if checkname and checkname ~= "" then @@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit) end if internal then arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end + environment.ownscript = result dofile(result) else local binary = runners.applications[file.extname(result)] @@ -10993,7 +11123,7 @@ function runners.locate_file(filename) end function runners.locate_platform() - runners.report_location(os.currentplatform()) + runners.report_location(os.platform) end function runners.report_location(result) @@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename) if logs.verbose then logs.simple("using script: %s\n",fullname) end + environment.ownscript = fullname dofile(fullname) local savename = environment.arguments['save'] if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then @@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename) end end +function runners.prefixes() + logs.reportbanner() + logs.reportline() + logs.simple(table.concat(resolvers.allprefixes(true)," ")) +end function runners.timedrun(filename) -- just for me if filename and filename ~= "" then @@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then elseif environment.argument("ctxlua") or environment.argument("internal") then -- run a script by loading it (using libs) ok = runners.execute_script(filename,true) -elseif environment.argument("script") or environment.argument("s") then +elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then -- run a script by loading it (using libs), pass args ok = runners.execute_ctx_script(filename) elseif environment.argument("execute") then @@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then elseif environment.argument("platform")then -- locate platform runners.locate_platform() +elseif environment.argument("prefixes") then + runners.prefixes() elseif environment.argument("timedrun") then -- locate platform runners.timedrun(filename) @@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then elseif filename:find("^bin:") then ok = runners.execute_program(filename) else - ok = runners.execute_script(filename) + ok = runners.execute_ctx_script(filename) if not ok then - ok = runners.execute_ctx_script(filename) + ok = runners.execute_script(filename) end end diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua index 6feb7a9c5..06e2a1bfc 100644 --- a/scripts/context/stubs/mswin/luatools.lua +++ b/scripts/context/stubs/mswin/luatools.lua @@ -233,6 +233,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1756,59 +1770,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2343,6 +2352,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing) end end -local seperator = comma * space^0 +local separator = comma * space^0 local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern = lpeg.Ct(value*(seperator*value)^0) +local pattern = lpeg.Ct(value*(separator*value)^0) -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored @@ -3187,7 +3225,7 @@ local function set(t,v) end local value = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(seperator*value)^0 * lpeg.Carg(1) +local pattern = value*(separator*value)^0 * lpeg.Carg(1) function aux.add_settings_to_array(t,str) return pattern:match(str, nil, t) @@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t) return t end +local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace +local pattern = lpeg.Ct((space + value)^0) + +function aux.arguments_to_table(str) + return pattern:match(str) +end + -- temporary here function aux.getparameters(self,class,parentclass,settings) @@ -4068,7 +4113,7 @@ end -- of closure do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['luat-log'] = { +if not modules then modules = { } end modules ['trac-log'] = { version = 1.001, comment = "companion to trac-log.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4345,8 +4390,12 @@ end logs.simpleline = logs.reportline -function logs.help(message,option) +function logs.reportbanner() -- for scripts too logs.report(banner) +end + +function logs.help(message,option) + logs.reportbanner() logs.reportline() logs.reportlines(message) local moreinfo = logs.moreinfo or "" @@ -4509,6 +4558,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -5728,9 +5782,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index a1fc6eaf5..c5b0acd04 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -242,6 +242,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1765,59 +1779,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2241,6 +2250,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -7264,6 +7302,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -8483,9 +8526,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end @@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate prefixes.file = prefixes.filename prefixes.path = prefixes.pathname +function resolvers.allprefixes(separator) + local all = table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i] = all[i] .. ":" + end + end + return all +end + local function _resolve_(method,target) if prefixes[method] then return prefixes[method](target) @@ -10130,43 +10183,109 @@ local trace_locating = false trackers.register("resolvers.locating", function(v local gsub = string.gsub -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -local libpaths = file.split_path(package.path) +local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +local clibformats = { 'lib' } +local libpaths = file.split_path(package.path) +local clibpaths = file.split_path(package.cpath) + +local function thepath(...) + local t = { ... } t[#t+1] = "?.lua" + local path = file.join(unpack(t)) + if trace_locating then + logs.report("fileio","! appending '%s' to 'package.path'",path) + end + return path +end + +function package.append_libpath(...) + table.insert(libpaths,thepath(...)) +end + +function package.prepend_libpath(...) + table.insert(libpaths,1,thepath(...)) +end + +-- beware, we need to return a loadfile result ! package.loaders[2] = function(name) -- was [#package.loaders+1] ---~ package.loaders[#package.loaders+1] = function(name) -- was + if trace_locating then -- mode detail + logs.report("fileio","! locating '%s'",name) + end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.find_file(name,format) or "" + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format) + end if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end end - local simple = file.removesuffix(name) + local simple = gsub(name,"%.lua$","") + local simple = gsub(simple,"%.","/") for i=1,#libpaths do -- package.path, might become option - local resolved = gsub(libpaths[i],"?",simple) + local libpath = libpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath) + end if resolvers.isreadable.file(resolved) then if trace_locating then logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) + end + end + local libname = file.addsuffix(simple,os.libsuffix) + for i=1,#clibformats do + -- better have a dedicated loop + local format = clibformats[i] + local paths = resolvers.expanded_path_list_from_var(format) + for p=1,#paths do + local path = paths[p] + local resolved = file.join(path,libname) + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved) + end + return package.loadlib(resolved,name) + end + end + end + for i=1,#clibpaths do -- package.path, might become option + local libpath = clibpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved) + end + return package.loadlib(resolved,name) end end -- just in case the distribution is messed up + if trace_loading then -- more detail + logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name) + end local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or "" if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end if trace_locating then logs.report("fileio",'? unable to locate lib: %s',name) end - return "unable to locate " .. name +-- return "unable to locate " .. name end resolvers.loadlualib = require @@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = { function resolvers.check_environment(tree) logs.simpleline() os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME')) - os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform())) + os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform)) os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",'')) os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS')) logs.simpleline() @@ -10723,10 +10842,11 @@ runners = runners or { } -- global messages = messages or { } messages.help = [[ ---script run an mtx script (--noquotes), no script gives list ---execute run a script or program (--noquotes) +--script run an mtx script (lua prefered method) (--noquotes), no script gives list +--execute run a script or program (texmfstart method) (--noquotes) --resolve resolve prefixed arguments --ctxlua run internally (using preloaded libs) +--internal run script using built in libraries (same as --ctxlua) --locate locate given filename --autotree use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree' @@ -10750,11 +10870,13 @@ messages.help = [[ --edit launch editor with found file --launch (--all) launch files like manuals, assumes os support ---internal run script using built in libraries (same as --ctxlua) --timedrun run a script an time its run +--autogenerate regenerate databases if needed (handy when used to run context in an editor) --usekpse use kpse as fallback (when no mkiv and cache installed, often slower) --forcekpse force using kpse (handy when no mkiv and cache installed but less functionality) + +--prefixes show supported prefixes ]] runners.applications = { @@ -10800,6 +10922,13 @@ runners.launchers = { unix = { } } +-- like runners.libpath("framework"): looks on script's subpath + +function runners.libpath(...) + package.prepend_libpath(file.dirname(environment.ownscript),...) + package.prepend_libpath(file.dirname(environment.ownname) ,...) +end + function runners.prepare() local checkname = environment.argument("ifchanged") if checkname and checkname ~= "" then @@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit) end if internal then arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end + environment.ownscript = result dofile(result) else local binary = runners.applications[file.extname(result)] @@ -10993,7 +11123,7 @@ function runners.locate_file(filename) end function runners.locate_platform() - runners.report_location(os.currentplatform()) + runners.report_location(os.platform) end function runners.report_location(result) @@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename) if logs.verbose then logs.simple("using script: %s\n",fullname) end + environment.ownscript = fullname dofile(fullname) local savename = environment.arguments['save'] if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then @@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename) end end +function runners.prefixes() + logs.reportbanner() + logs.reportline() + logs.simple(table.concat(resolvers.allprefixes(true)," ")) +end function runners.timedrun(filename) -- just for me if filename and filename ~= "" then @@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then elseif environment.argument("ctxlua") or environment.argument("internal") then -- run a script by loading it (using libs) ok = runners.execute_script(filename,true) -elseif environment.argument("script") or environment.argument("s") then +elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then -- run a script by loading it (using libs), pass args ok = runners.execute_ctx_script(filename) elseif environment.argument("execute") then @@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then elseif environment.argument("platform")then -- locate platform runners.locate_platform() +elseif environment.argument("prefixes") then + runners.prefixes() elseif environment.argument("timedrun") then -- locate platform runners.timedrun(filename) @@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then elseif filename:find("^bin:") then ok = runners.execute_program(filename) else - ok = runners.execute_script(filename) + ok = runners.execute_ctx_script(filename) if not ok then - ok = runners.execute_ctx_script(filename) + ok = runners.execute_script(filename) end end diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools index 6feb7a9c5..06e2a1bfc 100755 --- a/scripts/context/stubs/unix/luatools +++ b/scripts/context/stubs/unix/luatools @@ -233,6 +233,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -295,6 +296,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1756,59 +1770,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2343,6 +2352,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -3166,9 +3204,9 @@ function aux.settings_to_hash_strict(str,existing) end end -local seperator = comma * space^0 +local separator = comma * space^0 local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern = lpeg.Ct(value*(seperator*value)^0) +local pattern = lpeg.Ct(value*(separator*value)^0) -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored @@ -3187,7 +3225,7 @@ local function set(t,v) end local value = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(seperator*value)^0 * lpeg.Carg(1) +local pattern = value*(separator*value)^0 * lpeg.Carg(1) function aux.add_settings_to_array(t,str) return pattern:match(str, nil, t) @@ -3238,6 +3276,13 @@ function aux.settings_to_set(str,t) return t end +local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace +local pattern = lpeg.Ct((space + value)^0) + +function aux.arguments_to_table(str) + return pattern:match(str) +end + -- temporary here function aux.getparameters(self,class,parentclass,settings) @@ -4068,7 +4113,7 @@ end -- of closure do -- create closure to overcome 200 locals limit -if not modules then modules = { } end modules ['luat-log'] = { +if not modules then modules = { } end modules ['trac-log'] = { version = 1.001, comment = "companion to trac-log.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -4345,8 +4390,12 @@ end logs.simpleline = logs.reportline -function logs.help(message,option) +function logs.reportbanner() -- for scripts too logs.report(banner) +end + +function logs.help(message,option) + logs.reportbanner() logs.reportline() logs.reportlines(message) local moreinfo = logs.moreinfo or "" @@ -4509,6 +4558,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -5728,9 +5782,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index a1fc6eaf5..c5b0acd04 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -242,6 +242,7 @@ end local simple_escapes = { ["-"] = "%-", ["."] = "%.", + ["?"] = ".", ["*"] = ".*", } @@ -304,6 +305,19 @@ function string:striplong() -- strips newlines and leading spaces return self end +function string:topattern(lowercase,strict) + if lowercase then + self = self:lower() + end + self = gsub(self,".",simple_escapes) + if self == "" then + self = ".*" + elseif strict then + self = "^" .. self .. "$" + end + return self +end + end -- of closure @@ -1765,59 +1779,54 @@ os.arch = os.arch or function() return a end -local platform +-- no need for function anymore as we have more clever code and helpers now -function os.currentplatform(name,default) - if not platform then - local name = os.name or os.platform or name -- os.name is built in, os.platform is mine - if not name then - platform = default or "linux" - elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then - if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then - platform = "mswin-64" - else - platform = "mswin" - end +os.platform = os.name +os.libsuffix = 'so' + +local name = os.name + +if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then + if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then + os.platform = "mswin-64" + else + os.platform = "mswin" + end + os.libsuffix = 'dll' +else + local architecture = os.arch() + if name == "linux" then + if find(architecture,"x86_64") then + os.platform = "linux-64" + elseif find(architecture,"ppc") then + os.platform = "linux-ppc" else - local architecture = os.arch() - if name == "linux" then - if find(architecture,"x86_64") then - platform = "linux-64" - elseif find(architecture,"ppc") then - platform = "linux-ppc" - else - platform = "linux" - end - elseif name == "macosx" then - local architecture = os.resultof("echo $HOSTTYPE") - if find(architecture,"i386") then - platform = "osx-intel" - elseif find(architecture,"x86_64") then - platform = "osx-64" - else - platform = "osx-ppc" - end - elseif name == "sunos" then - if find(architecture,"sparc") then - platform = "solaris-sparc" - else -- if architecture == 'i86pc' - platform = "solaris-intel" - end - elseif name == "freebsd" then - if find(architecture,"amd64") then - platform = "freebsd-amd64" - else - platform = "freebsd" - end - else - platform = default or name - end + os.platform = "linux" + end + elseif name == "macosx" then + local architecture = os.resultof("echo $HOSTTYPE") + if find(architecture,"i386") then + os.platform = "osx-intel" + elseif find(architecture,"x86_64") then + os.platform = "osx-64" + else + os.platform = "osx-ppc" end - function os.currentplatform() - return platform + elseif name == "sunos" then + if find(architecture,"sparc") then + os.platform = "solaris-sparc" + else -- if architecture == 'i86pc' + os.platform = "solaris-intel" end + elseif name == "freebsd" then + if find(architecture,"amd64") then + os.platform = "freebsd-amd64" + else + os.platform = "freebsd" + end + else + os.platform = 'linux' end - return platform end -- beware, we set the randomseed @@ -2241,6 +2250,35 @@ end dir.glob_pattern = glob_pattern +local function collect_pattern(path,patt,recurse,result) + local ok, scanner + result = result or { } + if path == "/" then + ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe + else + ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe + end + if ok and type(scanner) == "function" then + if not find(path,"/$") then path = path .. '/' end + for name in scanner do + local full = path .. name + local attr = attributes(full) + local mode = attr.mode + if mode == 'file' then + if find(full,patt) then + result[name] = attr + end + elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then + attr.list = collect_pattern(full,patt,recurse) + result[name] = attr + end + end + end + return result +end + +dir.collect_pattern = collect_pattern + local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V local pattern = Ct { @@ -7264,6 +7302,11 @@ formats ['sfd'] = 'SFDFONTS' suffixes ['sfd'] = { 'sfd' } alternatives['subfont definition files'] = 'sfd' +-- lib paths + +formats ['lib'] = 'CLUAINPUTS' -- new (needs checking) +suffixes['lib'] = (os.libsuffix and { os.libsuffix }) or { 'dll', 'so' } + -- In practice we will work within one tds tree, but i want to keep -- the option open to build tools that look at multiple trees, which is -- why we keep the tree specific data in a table. We used to pass the @@ -8483,9 +8526,9 @@ end function resolvers.expanded_path_list_from_var(str) -- brrr local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$","")) if tmp ~= "" then - return resolvers.expanded_path_list(str) - else return resolvers.expanded_path_list(tmp) + else + return resolvers.expanded_path_list(str) end end @@ -9473,6 +9516,16 @@ prefixes.full = prefixes.locate prefixes.file = prefixes.filename prefixes.path = prefixes.pathname +function resolvers.allprefixes(separator) + local all = table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i] = all[i] .. ":" + end + end + return all +end + local function _resolve_(method,target) if prefixes[method] then return prefixes[method](target) @@ -10130,43 +10183,109 @@ local trace_locating = false trackers.register("resolvers.locating", function(v local gsub = string.gsub -local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -local libpaths = file.split_path(package.path) +local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' } -- 'luainputs' +local clibformats = { 'lib' } +local libpaths = file.split_path(package.path) +local clibpaths = file.split_path(package.cpath) + +local function thepath(...) + local t = { ... } t[#t+1] = "?.lua" + local path = file.join(unpack(t)) + if trace_locating then + logs.report("fileio","! appending '%s' to 'package.path'",path) + end + return path +end + +function package.append_libpath(...) + table.insert(libpaths,thepath(...)) +end + +function package.prepend_libpath(...) + table.insert(libpaths,1,thepath(...)) +end + +-- beware, we need to return a loadfile result ! package.loaders[2] = function(name) -- was [#package.loaders+1] ---~ package.loaders[#package.loaders+1] = function(name) -- was + if trace_locating then -- mode detail + logs.report("fileio","! locating '%s'",name) + end for i=1,#libformats do local format = libformats[i] local resolved = resolvers.find_file(name,format) or "" + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'libformat path': '%s'",name,format) + end if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end end - local simple = file.removesuffix(name) + local simple = gsub(name,"%.lua$","") + local simple = gsub(simple,"%.","/") for i=1,#libpaths do -- package.path, might become option - local resolved = gsub(libpaths[i],"?",simple) + local libpath = libpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.path': '%s'",simple,libpath) + end if resolvers.isreadable.file(resolved) then if trace_locating then logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) + end + end + local libname = file.addsuffix(simple,os.libsuffix) + for i=1,#clibformats do + -- better have a dedicated loop + local format = clibformats[i] + local paths = resolvers.expanded_path_list_from_var(format) + for p=1,#paths do + local path = paths[p] + local resolved = file.join(path,libname) + if trace_locating then -- mode detail + logs.report("fileio","! checking for '%s' using 'clibformat path': '%s'",libname,path) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'clibformat': '%s'",libname,resolved) + end + return package.loadlib(resolved,name) + end + end + end + for i=1,#clibpaths do -- package.path, might become option + local libpath = clibpaths[i] + local resolved = gsub(libpath,"?",simple) + if trace_locating then -- more detail + logs.report("fileio","! checking for '%s' on 'package.cpath': '%s'",simple,libpath) + end + if resolvers.isreadable.file(resolved) then + if trace_locating then + logs.report("fileio","! lib '%s' located via 'package.cpath': '%s'",name,resolved) + end + return package.loadlib(resolved,name) end end -- just in case the distribution is messed up + if trace_loading then -- more detail + logs.report("fileio","! checking for '%s' using 'luatexlibs': '%s'",name) + end local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or "" if resolved ~= "" then if trace_locating then logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved) end - return function() return dofile(resolved) end + return loadfile(resolved) end if trace_locating then logs.report("fileio",'? unable to locate lib: %s',name) end - return "unable to locate " .. name +-- return "unable to locate " .. name end resolvers.loadlualib = require @@ -10359,7 +10478,7 @@ if not modules then modules = { } end modules ['data-tmf'] = { function resolvers.check_environment(tree) logs.simpleline() os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME')) - os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform())) + os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.platform)) os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",'')) os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS')) logs.simpleline() @@ -10723,10 +10842,11 @@ runners = runners or { } -- global messages = messages or { } messages.help = [[ ---script run an mtx script (--noquotes), no script gives list ---execute run a script or program (--noquotes) +--script run an mtx script (lua prefered method) (--noquotes), no script gives list +--execute run a script or program (texmfstart method) (--noquotes) --resolve resolve prefixed arguments --ctxlua run internally (using preloaded libs) +--internal run script using built in libraries (same as --ctxlua) --locate locate given filename --autotree use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree' @@ -10750,11 +10870,13 @@ messages.help = [[ --edit launch editor with found file --launch (--all) launch files like manuals, assumes os support ---internal run script using built in libraries (same as --ctxlua) --timedrun run a script an time its run +--autogenerate regenerate databases if needed (handy when used to run context in an editor) --usekpse use kpse as fallback (when no mkiv and cache installed, often slower) --forcekpse force using kpse (handy when no mkiv and cache installed but less functionality) + +--prefixes show supported prefixes ]] runners.applications = { @@ -10800,6 +10922,13 @@ runners.launchers = { unix = { } } +-- like runners.libpath("framework"): looks on script's subpath + +function runners.libpath(...) + package.prepend_libpath(file.dirname(environment.ownscript),...) + package.prepend_libpath(file.dirname(environment.ownname) ,...) +end + function runners.prepare() local checkname = environment.argument("ifchanged") if checkname and checkname ~= "" then @@ -10890,6 +11019,7 @@ function runners.execute_script(fullname,internal,nosplit) end if internal then arg = { } for _,v in pairs(environment.arguments_after) do arg[#arg+1] = v end + environment.ownscript = result dofile(result) else local binary = runners.applications[file.extname(result)] @@ -10993,7 +11123,7 @@ function runners.locate_file(filename) end function runners.locate_platform() - runners.report_location(os.currentplatform()) + runners.report_location(os.platform) end function runners.report_location(result) @@ -11170,6 +11300,7 @@ function runners.execute_ctx_script(filename) if logs.verbose then logs.simple("using script: %s\n",fullname) end + environment.ownscript = fullname dofile(fullname) local savename = environment.arguments['save'] if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then @@ -11222,6 +11353,11 @@ function runners.execute_ctx_script(filename) end end +function runners.prefixes() + logs.reportbanner() + logs.reportline() + logs.simple(table.concat(resolvers.allprefixes(true)," ")) +end function runners.timedrun(filename) -- just for me if filename and filename ~= "" then @@ -11337,7 +11473,7 @@ elseif environment.argument("selfupdate") then elseif environment.argument("ctxlua") or environment.argument("internal") then -- run a script by loading it (using libs) ok = runners.execute_script(filename,true) -elseif environment.argument("script") or environment.argument("s") then +elseif environment.argument("script") or environment.argument("s") or environment.argument("scripts") then -- run a script by loading it (using libs), pass args ok = runners.execute_ctx_script(filename) elseif environment.argument("execute") then @@ -11366,6 +11502,8 @@ elseif environment.argument("locate") then elseif environment.argument("platform")then -- locate platform runners.locate_platform() +elseif environment.argument("prefixes") then + runners.prefixes() elseif environment.argument("timedrun") then -- locate platform runners.timedrun(filename) @@ -11375,9 +11513,9 @@ elseif environment.argument("help") or filename=='help' or filename == "" then elseif filename:find("^bin:") then ok = runners.execute_program(filename) else - ok = runners.execute_script(filename) + ok = runners.execute_ctx_script(filename) if not ok then - ok = runners.execute_ctx_script(filename) + ok = runners.execute_script(filename) end end |