file-mod.lua /size: 8533 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['file-mod'] = {
2    version   = 1.001,
3    comment   = "companion to file-mod.mkvi",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- This module will be redone! For instance, the prefixes will move to data-*
10-- as they arr sort of generic along with home:// etc/.
11
12-- context is not defined yet! todo! (we need to load tupp-fil after cld)
13-- todo: move startreadingfile to lua and push regime there
14
15--[[ldx--
16<p>It's more convenient to manipulate filenames (paths) in
17<l n='lua'/> than in <l n='tex'/>. These methods have counterparts
18at the <l n='tex'/> side.</p>
19--ldx]]--
20
21local format, find, concat, tonumber = string.format, string.find, table.concat, tonumber
22local sortedhash = table.sortedhash
23local basename = file.basename
24
25local trace_modules     = false  trackers  .register("modules.loading",          function(v) trace_modules     = v end)
26local permit_unprefixed = false  directives.register("modules.permitunprefixed", function(v) permit_unprefixed = v end)
27
28local report            = logs.reporter("modules")
29
30local commands          = commands
31local context           = context
32local implement         = interfaces.implement
33
34local findbyscheme      = resolvers.finders.byscheme -- use different one
35local iterator          = utilities.parsers.iterator
36
37-- modules can have a specific suffix or can specify one
38
39local prefixes = {
40    "m", -- module, extends functionality
41    "p", -- private code
42    "s", -- styles
43    "x", -- xml specific modules
44 -- "v", -- an old internal one for examples
45    "t", -- third party extensions
46}
47
48-- the order might change and how about cld
49
50local suffixes = CONTEXTLMTXMODE > 0 and
51{
52    "mklx", -- preprocessed mkiv lmtx files
53    "mkxl", -- mkiv lmtx files
54    "mkvi", -- preprocessed mkiv files
55    "mkiv", -- mkiv files
56    "tex",  -- normally source code files
57    "cld",  -- context lua documents (often stand alone)
58    "lua",  -- lua files
59}
60    or
61{
62    "mkvi",
63    "mkiv",
64    "tex",
65    "cld",
66    "lua",
67}
68
69local modstatus = { }
70local missing   = false
71
72local function usemodule(name,hasscheme)
73    local foundname
74    if hasscheme then
75        -- no auto suffix as http will return a home page or error page
76        -- so we only add one if missing
77        local fullname = file.addsuffix(name,"tex")
78        if trace_modules then
79            report("checking url %a",fullname)
80        end
81        foundname = resolvers.findtexfile(fullname) or ""
82    elseif file.suffix(name) ~= "" then
83        if trace_modules then
84            report("checking file %a",name)
85        end
86        foundname = findbyscheme("any",name) or ""
87    else
88        for i=1,#suffixes do
89            local fullname = file.addsuffix(name,suffixes[i])
90            if trace_modules then
91                report("checking file %a",fullname)
92            end
93            foundname = findbyscheme("any",fullname) or ""
94            if foundname ~= "" then
95                break
96            end
97        end
98    end
99    if foundname ~= "" then
100        if trace_modules then
101            report("loading file %a",foundname)
102        end
103        context.startreadingfile()
104        resolvers.jobs.usefile(foundname,true) -- once, notext
105     -- context.input(foundname)
106        context.stopreadingfile()
107        return true
108    else
109        return false
110    end
111end
112
113function environment.usemodules(prefix,askedname,truename)
114    local truename = truename or environment.truefilename(askedname) or askedname
115    if truename and truename ~= "" then
116        local hasprefix = prefix and prefix ~= ""
117        local hashname = ((hasprefix and prefix) or "*") .. "-" .. truename
118        local status = modstatus[hashname] or false -- yet unset
119        if status == 0 then
120            -- not found
121        elseif status == 1 then
122            status = status + 1
123        else
124            if trace_modules then
125                report("locating, prefix %a, askedname %a, truename %a",prefix,askedname,truename)
126            end
127            local hasscheme = url.hasscheme(truename)
128            if hasscheme then
129                -- no prefix and suffix done
130                if usemodule(truename,true) then
131                    status = 1
132                else
133                    status = 0
134                end
135            elseif hasprefix then
136                if usemodule(prefix .. "-" .. truename) then
137                    status = 1
138                else
139                    status = 0
140                end
141            else
142                for i=1,#prefixes do
143                    -- todo: reconstruct name i.e. basename
144                    local thename = prefixes[i] .. "-" .. truename
145                    if usemodule(thename) then
146                        status = 1
147                        break
148                    end
149                end
150                if status then
151                    -- ok, don't change
152                elseif find(truename,"-",1,true) and usemodule(truename) then
153                    -- assume a user namespace
154                    report("using user prefixed file %a",truename)
155                    status = 1
156                elseif permit_unprefixed and usemodule(truename) then
157                    report("using unprefixed file %a",truename)
158                    status = 1
159                else
160                    status = 0
161                end
162            end
163        end
164        if status == 0 then
165            missing = true
166            report("%a is not found",askedname)
167        elseif status == 1 then
168            report("%a is loaded",trace_modules and truename or askedname)
169        else
170            report("%a is already loaded",trace_modules and truename or askedname)
171        end
172        modstatus[hashname] = status
173    end
174end
175
176statistics.register("loaded tex modules", function()
177    if next(modstatus) then
178        local t, f, nt, nf = { }, { }, 0, 0
179        for k, v in sortedhash(modstatus) do
180            local b = basename(k)
181            if v == 0 then
182                nf = nf + 1
183                f[nf] = b
184            else
185                nt = nt + 1
186                t[nt] = b
187            end
188        end
189        if nf == 0 then
190            return format("%s requested, all found (%s)",nt,concat(t," "))
191        elseif nt == 0 then
192            return format("%s requested, all missing (%s)",nf,concat(f," "))
193        else
194            return format("%s requested, %s found (%s), %s missing (%s)",nt+nf,nt,concat(t," "),nf,concat(f," "))
195        end
196    else
197        return nil
198    end
199end)
200
201logs.registerfinalactions(function()
202    logs.startfilelogging(report,"used modules")
203    for k, v in sortedhash(modstatus) do
204        report(v == 0 and "missing: %s" or "loaded : %s",basename(k))
205    end
206    logs.stopfilelogging()
207    if missing and logs.loggingerrors() then
208        logs.starterrorlogging(report,"missing modules")
209        for k, v in sortedhash(modstatus) do
210            if v == 0 then
211                report("%w%s",6,basename(k))
212            end
213        end
214        logs.stoperrorlogging()
215    end
216end)
217
218-- moved from syst-lua.lua:
219
220local lpegmatch = lpeg.match
221local splitter  = lpeg.tsplitter(lpeg.S(". "),tonumber)
222
223function environment.comparedversion(one,two) -- one >= two
224    if not two or two == "" then
225        one, two = environment.version, one
226    elseif one == "" then
227        one = environment.version
228    end
229    one = lpegmatch(splitter,one)
230    two = lpegmatch(splitter,two)
231    one = (one[1] or 0) * 10000 + (one[2] or 0) * 100 + (one[3] or 0)
232    two = (two[1] or 0) * 10000 + (two[2] or 0) * 100 + (two[3] or 0)
233    if one < two then
234        return -1
235    elseif one > two then
236        return 1
237    else
238        return 0
239    end
240end
241
242environment.comparedversion = comparedversion
243
244
245function environment.useluamodule(list)
246    for filename in iterator(list) do
247        environment.loadluafile(filename)
248    end
249end
250
251implement {
252    name      = "usemodules",
253    actions   = environment.usemodules,
254    arguments = "2 strings",
255}
256
257implement {
258    name      = "doifelseolderversion",
259    actions   = function(one,two) commands.doifelse(comparedversion(one,two) >= 0) end,
260    arguments = "2 strings"
261}
262
263implement {
264    name      = "useluamodule",
265    actions   = environment.useluamodule,
266    arguments = "string"
267}
268
269implement {
270    name      = "loadluamodule",
271    actions   = function(name) dofile(resolvers.findctxfile(name)) end, -- hack
272    arguments = "string"
273}
274
275