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