1if not modules then modules = { } end modules ['trac-deb'] = {
2 version = 1.001,
3 comment = "companion to trac-deb.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
9
10
11
12local status = status
13
14local tonumber, tostring, type = tonumber, tostring, type
15local format, concat, match, find, gsub = string.format, table.concat, string.match, string.find, string.gsub
16
17local report_nl = logs.newline
18local report_str = logs.writer
19
20tracers = tracers or { }
21local tracers = tracers
22local implement = interfaces.implement
23
24local savedluaerror = nil
25local usescitelexer = nil
26local quitonerror = true
27
28local function errorreporter(luaerror)
29 local category = luaerror and "lua error" or "tex error"
30 local report = logs.reporter(category)
31 logs.enable(category)
32 return report
33end
34
35function tracers.showlines(filename,linenumber,offset,luaerrorline)
36 local data = io.loaddata(filename)
37 if not data or data == "" then
38 local hash = url.hashed(filename)
39 if not hash.noscheme then
40 local ok, d, n = resolvers.loaders.byscheme(hash.scheme,filename)
41 if ok and n > 0 then
42 data = d
43 end
44 end
45 end
46 local scite = usescitelexer and require("util-sci")
47 if scite then
48 return utilities.scite.tohtml(data,"tex",linenumber or true,false)
49 else
50 local lines = data and string.splitlines(data)
51 if lines and #lines > 0 then
52 if luaerrorline and luaerrorline > 0 then
53
54 local start = "\\startluacode"
55 local stop = "\\stopluacode"
56 local n = linenumber
57 for i=n,1,-1 do
58 local line = lines[i]
59 if not line then
60 break
61 elseif find(line,start) then
62 n = i + luaerrorline - 1
63 if n <= linenumber then
64 linenumber = n
65 end
66 break
67 end
68 end
69 end
70 offset = tonumber(offset) or 10
71 linenumber = tonumber(linenumber) or 10
72 local start = math.max(linenumber - offset,1)
73 local stop = math.min(linenumber + offset,#lines)
74 if stop > #lines then
75 return "<linenumber past end of file>"
76 else
77 local result, fmt = { }, "%" .. #tostring(stop) .. "d %s %s"
78 for n=start,stop do
79 result[#result+1] = format(fmt,n,n == linenumber and ">>" or " ",lines[n])
80 end
81 return concat(result,"\n")
82 end
83 else
84 return "<empty file>"
85 end
86 end
87end
88
89
90
91
92
93
94
95
96
97local nop = function() end
98local resetmessages = status.resetmessages or nop
99
100local function processerror(offset,eof)
101 local filename = status.filename
102 local linenumber = tonumber(status.linenumber) or 0
103 local lastcontext = status.lasterrorcontext
104 local lasttexerror = status.lasterrorstring or "?"
105 local lastluaerror = status.lastluaerrorstring or "?"
106 local luaerrorline = match(lastluaerror,[[lua%]?:.-(%d+)]]) or (lastluaerror and find(lastluaerror,"?:0:",1,true) and 0)
107 local lastmpserror = match(lasttexerror,[[^.-mp%serror:%s*(.*)$]])
108 resetmessages()
109 lastluaerror = gsub(lastluaerror,"%[\\directlua%]","[ctxlua]")
110 tracers.printerror {
111 filename = filename,
112 linenumber = linenumber,
113 offset = tonumber(offset) or 10,
114 lasttexerror = lasttexerror,
115 lastmpserror = lastmpserror,
116 lastluaerror = lastluaerror,
117 luaerrorline = luaerrorline,
118 lastcontext = lastcontext,
119 lasttexhelp = tex.gethelptext and tex.gethelptext() or nil,
120 endoffile = eof,
121 }
122 if job and type(job.disablesave) == "function" then
123 job.disablesave()
124 end
125end
126
127directives.register("system.quitonerror",function(v)
128 quitonerror = toboolean(v)
129end)
130
131directives.register("system.usescitelexer",function(v)
132 usescitelexer = toboolean(v)
133end)
134
135local busy = false
136
137function tracers.printerror(specification)
138 if not busy then
139 busy = true
140 local filename = specification.filename
141 local linenumber = specification.linenumber
142 local lasttexerror = specification.lasttexerror
143 local lastmpserror = specification.lastmpserror
144 local lastluaerror = specification.lastluaerror
145 local lastcontext = specification.lasterrorcontext
146 local luaerrorline = specification.luaerrorline
147 local errortype = specification.errortype
148 local offset = specification.offset
149 local endoffile = specification.endoffile
150 local report = errorreporter(luaerrorline)
151 if endoffile then
152 report("runaway error: %s",lasttexerror or "-")
153 if not quitonerror and texio.terminal then
154 texio.terminal()
155 end
156 elseif not filename then
157 report("fuzzy error:")
158 report(" tex: %s",lasttexerror or "-")
159 report(" lua: %s",lastluaerror or "-")
160 report(" mps: %s",lastmpserror or "-")
161 elseif type(filename) == "number" then
162 report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror)
163 else
164 report_nl()
165 if luaerrorline then
166 if linenumber == 0 or not filename or filename == "" then
167 print("\nfatal lua error:\n\n",lastluaerror,"\n")
168 luatex.abort()
169 return
170 else
171 report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror)
172 end
173 elseif lastmpserror then
174 report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror)
175 else
176 report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror)
177 if lastcontext then
178 report_nl()
179 report_str(lastcontext)
180 report_nl()
181 elseif tex.show_context then
182 report_nl()
183 tex.show_context()
184 end
185 if lastluaerror and not match(lastluaerror,"^%s*[%?]*%s*$") then
186 print("\nlua error:\n\n",lastluaerror,"\n")
187 quitonerror = true
188 end
189 end
190 report_nl()
191 report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline)))
192 report_nl()
193 end
194 if quitonerror then
195 local name = tex.jobname or ""
196 if name ~= "" then
197 table.save(name .. "-error.log",specification)
198 end
199 local help = specification.lasttexhelp
200 if help and #help > 0 then
201 report_nl()
202 report_str(help)
203 report_nl()
204 report_nl()
205 end
206 luatex.abort()
207 end
208 busy = false
209 end
210end
211
212luatex.wrapup(function() os.remove(file.addsuffix(tex.jobname .. "-error","log")) end)
213
214local function processwarning(offset)
215 local lastwarning = status.lastwarningstring or "?"
216 local lastlocation = status.lastwarningtag or "?"
217 resetmessages()
218 tracers.printwarning {
219 lastwarning = lastwarning ,
220 lastlocation = lastlocation,
221 }
222end
223
224function tracers.printwarning(specification)
225 logs.report("luatex warning","%s: %s",specification.lastlocation,specification.lastwarning)
226end
227
228directives.register("system.errorcontext", function(v)
229 local register = callback.register
230 if v then
231 register('show_error_message', nop)
232 register('show_warning_message',function() processwarning(v) end)
233 register('show_error_hook', function(eof) processerror(v,eof) end)
234 register('show_lua_error_hook', function() processerror(v) end)
235 else
236 register('show_error_message', nil)
237 register('show_error_hook', nil)
238 register('show_warning_message',nil)
239 register('show_lua_error_hook', nil)
240 end
241end)
242
243
244
245lmx = lmx or { }
246
247lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
248lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end
249
250local function reportback(lmxname,default,variables)
251 if lmxname == false then
252 return variables
253 else
254 local name = lmx.show(type(lmxname) == "string" and lmxname or default,variables)
255 if name then
256 logs.report("context report","file: %s",name)
257 end
258 end
259end
260
261local function showerror(lmxname)
262 local filename, linenumber, errorcontext = status.filename, tonumber(status.linenumber) or 0, ""
263 if not filename then
264 filename, errorcontext = 'unknown', 'error in filename'
265 elseif type(filename) == "number" then
266 filename, errorcontext = format("<read %s>",filename), 'unknown error'
267 else
268 errorcontext = tracers.showlines(filename,linenumber,offset)
269 end
270 local variables = {
271 ['title'] = 'ConTeXt Error Information',
272 ['errormessage'] = status.lasterrorstring,
273 ['linenumber'] = linenumber,
274 ['color-background-one'] = lmx.get('color-background-yellow'),
275 ['color-background-two'] = lmx.get('color-background-purple'),
276 ['filename'] = filename,
277 ['errorcontext'] = errorcontext,
278 }
279 reportback(lmxname,"context-error.lmx",variables)
280 luatex.abort()
281end
282
283lmx.showerror = showerror
284
285function lmx.overloaderror(v)
286 if v == "scite" then
287 usescitelexer = true
288 end
289 callback.register('show_error_hook', function() showerror() end)
290 callback.register('show_lua_error_hook', function() showerror() end)
291 callback.register('show_tex_error_hook', function() showerror() end)
292end
293
294directives.register("system.showerror", lmx.overloaderror)
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331implement { name = "showtrackers", actions = trackers.show }
332implement { name = "enabletrackers", actions = trackers.enable, arguments = "string" }
333implement { name = "disabletrackers", actions = trackers.disable, arguments = "string" }
334implement { name = "resettrackers", actions = trackers.reset }
335
336implement { name = "showdirectives", actions = directives.show }
337implement { name = "enabledirectives", actions = directives.enable, arguments = "string" }
338implement { name = "disabledirectives", actions = directives.disable, arguments = "string" }
339
340implement { name = "showexperiments", actions = experiments.show }
341implement { name = "enableexperiments", actions = experiments.enable, arguments = "string" }
342implement { name = "disableexperiments", actions = experiments.disable, arguments = "string" }
343
344implement { name = "overloaderror", actions = lmx.overloaderror }
345implement { name = "showlogcategories", actions = logs.show }
346
347local debugger = utilities.debugger
348
349directives.register("system.profile",function(n)
350 luatex.registerstopactions(function()
351 debugger.disable()
352 debugger.savestats("luatex-profile.log",tonumber(n) or 0)
353 report_nl()
354 logs.report("system","profiler stopped, log saved in %a","luatex-profile.log")
355 report_nl()
356 end)
357 logs.report("system","profiler started")
358 debugger.enable()
359end)
360 |