luat-run.lmt /size: 8764 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['luat-run'] = {
2    version   = 1.001,
3    comment   = "companion to luat-lib.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local next = next
10local find = string.find
11local insert, remove = table.insert, table.remove
12local osexit = os.exit
13
14-- trace_job_status is also controlled by statistics.enable that is set via the directive system.nostatistics
15
16local trace_lua_dump   = false  trackers.register("system.dump",      function(v) trace_lua_dump   = v end)
17local trace_temp_files = false  trackers.register("system.tempfiles", function(v) trace_temp_files = v end)
18local trace_job_status = true   trackers.register("system.jobstatus", function(v) trace_job_status = v end)
19local trace_tex_status = false  trackers.register("system.texstatus", function(v) trace_tex_status = v end)
20
21local report_lua       = logs.reporter("system","lua")
22local report_tex       = logs.reporter("system","status")
23local report_tempfiles = logs.reporter("resolvers","tempfiles")
24
25luatex        = luatex or { }
26local luatex  = luatex
27local synctex = luatex.synctex
28
29if not synctex then
30    synctex        = table.setmetatableindex(function() return function() end end)
31    luatex.synctex = synctex
32end
33
34local startactions = { }
35local stopactions  = { }
36local dumpactions  = { }
37local pageactions  = { }
38
39function luatex.registerstartactions(...) insert(startactions, ...) end
40function luatex.registerstopactions (...) insert(stopactions,  ...) end
41function luatex.registerdumpactions (...) insert(dumpactions,  ...) end
42function luatex.registerpageactions (...) insert(pageactions,  ...) end
43
44local setexitcode = lua.setexitcode or status.setexitcode or function() end
45
46local function start_run()
47    if logs.start_run then
48        logs.start_run()
49    end
50    for i=1,#startactions do
51        startactions[i]()
52    end
53end
54
55local function stop_run(badrun)
56    for i=1,#stopactions do
57        stopactions[i]()
58    end
59    local quit = logs.finalactions()
60    if trace_job_status then
61        statistics.show()
62    end
63    if trace_tex_status then
64        logs.newline()
65        for k, v in table.sortedhash(status.list()) do
66            if type(v) ~= "table" then
67                report_tex("%S=%S",k,v)
68            end
69        end
70    end
71    if quit then
72        setexitcode(1)
73        if type(quit) == "table" then
74            logs.newline()
75            report_tex("quitting due to: %, t",quit)
76            logs.newline()
77        end
78    elseif badrun and badrun > 0 then
79        setexitcode(1)
80    end
81    if logs.stop_run then
82        logs.stop_run()
83    end
84end
85
86-- watch out for synctex here:
87
88function callbacks.functions.start_page_number()
89    synctex.start()
90    logs.start_page_number()
91end
92
93function callbacks.functions.stop_page_number()
94    logs.stop_page_number()
95    for i=1,#pageactions do
96        pageactions[i]()
97    end
98    synctex.stop()
99end
100
101local function pre_dump_actions()
102    for i=1,#dumpactions do
103        dumpactions[i]()
104    end
105    lua.finalizeinitex(trace_lua_dump and report_lua or nil)
106end
107
108local function wrapup_synctex()
109    synctex.wrapup()
110end
111
112-- For Taco ...
113
114local sequencers     = utilities.sequencers
115local appendgroup    = sequencers.appendgroup
116local appendaction   = sequencers.appendaction
117local wrapupactions  = sequencers.new { }
118local cleanupactions = sequencers.new { }
119
120appendgroup(wrapupactions,"system")
121appendgroup(wrapupactions,"user")
122
123appendgroup(cleanupactions,"system")
124appendgroup(cleanupactions,"user")
125
126local function wrapup_run(someerror)
127    local runner = wrapupactions.runner
128    if runner then
129        runner(someerror) -- we could use the error flag in lmtx
130    end
131end
132
133local function cleanup_run()
134    local runner = cleanupactions.runner
135    if runner then
136        runner()
137    end
138end
139
140function luatex.wrapup(action)
141    appendaction(wrapupactions,"user",action)
142end
143
144function luatex.cleanup(action)
145    appendaction(cleanupactions,"user",action)
146end
147
148function luatex.abort()
149    cleanup_run()
150    setexitcode(1)
151    osexit(1)
152end
153
154appendaction(wrapupactions,"system",synctex.wrapup)
155
156-- this can be done later
157
158callbacks.register("start_run",  start_run,        "actions performed at the beginning of a run")
159callbacks.register("stop_run",   stop_run,         "actions performed at the end of a run")
160callbacks.register("pre_dump",   pre_dump_actions, "lua related finalizers called before we dump the format") -- comes after \everydump
161callbacks.register("wrapup_run", wrapup_run,       "actions performed after closing files")
162
163-- an example:
164
165local tempfiles = { }
166
167function luatex.registertempfile(name,extrasuffix,keep) -- namespace might change
168    if extrasuffix then
169        name = name .. ".mkiv-tmp" -- maybe just .tmp
170    end
171    if trace_temp_files and not tempfiles[name] then
172        if keep then
173            report_tempfiles("%s temporary file %a","registering",name)
174        else
175            report_tempfiles("%s temporary file %a","unregistering",name)
176        end
177    end
178    tempfiles[name] = keep or false
179    return name
180end
181
182function luatex.cleanuptempfiles()
183    for name, keep in next, tempfiles do
184        if not keep then
185            if trace_temp_files then
186                report_tempfiles("%s temporary file %a","removing",name)
187            end
188            os.remove(name)
189        end
190    end
191    tempfiles = { }
192end
193
194luatex.registerstopactions(luatex.cleanuptempfiles)
195
196-- Reporting filenames has been simplified since lmtx because we don't need  the
197-- traditional () {} <> etc methods (read: that directive option was never chosen).
198
199local report_open  = logs.reporter("open source")
200local report_close = logs.reporter("close source")
201local report_load  = logs.reporter("load resource")
202
203local level = 0
204local total = 0
205local stack = { }
206
207function luatex.currentfile()
208    return stack[#stack] or tex.jobname
209end
210
211function luatex.currentlevel()
212    return level
213end
214
215function luatex.currenttotal()
216    return total
217end
218
219local enabled = true  directives.register("system.reportfiles", function(v) enabled = v end)
220
221local function report_start(name,rest)
222    if enabled then
223        if rest then
224            -- luatex
225            if name ~= 1 then
226                insert(stack,false)
227                return
228            end
229            name = rest
230        end
231        if find(name,"virtual://",1,true) then
232            insert(stack,false)
233        else
234            insert(stack,name)
235            total = total + 1
236            level = level + 1
237         -- report_open("%i > %i > %s",level,total,name or "?")
238            report_open("level %i, order %i, name %a",level,total,name or "?")
239            synctex.setfilename(name)
240        end
241    end
242end
243
244local function report_stop()
245    if enabled then
246        local name = remove(stack)
247        if name then
248         -- report_close("%i > %i > %s",level,total,name or "?")
249            report_close("level %i, order %i, name %a",level,total,name or "?")
250            level = level - 1
251            name  = stack[#stack]
252    --      synctex.setfilename(stack[#stack] or tex.jobname)
253            if name then
254                synctex.setfilename(name)
255            end
256        end
257    end
258end
259
260callbacks.register("start_file",report_start,"report opening of a file")
261callbacks.register("stop_file", report_stop, "report closing of a file")
262
263-- start_run doesn't work
264
265-- luatex.registerstartactions(function()
266--     if environment.arguments.sandbox then
267--         sandbox.enable()
268--     end
269-- end)
270
271local report   = logs.reporter("csname overload")
272local reported = { }
273
274callbacks.register("handle_overload", function(fatal,overload,csname,flags)
275    if not reported[csname] then
276        logs.newline()
277        local readstate  = status.readstate
278        local filename   = readstate.filename
279        local linenumber = readstate.linenumber
280        local flags      = tokens.flags and tokens.flags(csname) or { }
281        if filename and linenumber then
282            report("%s, protection level %i, control sequence %a, properties '% t', file %a, line %i",
283                fatal and "fatal error" or "warning",overload,csname,flags,filename,linenumber)
284        else
285            report("%s, protection level %i, control sequence %a, properties '% t'",
286                fatal and "fatal error" or "warning",overload,csname,flags)
287        end
288        reported[csname] = true
289        logs.newline()
290        if fatal then
291            cleanup_run()
292            setexitcode(1)
293            osexit(1)
294        end
295    end
296end,"handle primitive and macro overload protection")
297
298-- bonus
299
300if environment.initex then
301
302    luatex.registerdumpactions(statistics.showmemory)
303
304end
305