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 local errname = file.addsuffix(tex.jobname .. "-error","log")
195 if quitonerror then
196 table.save(errname,specification)
197 local help = specification.lasttexhelp
198 if help and #help > 0 then
199 report_nl()
200 report_str(help)
201 report_nl()
202 report_nl()
203 end
204 luatex.abort()
205 end
206 busy = false
207 end
208end
209
210luatex.wrapup(function() os.remove(file.addsuffix(tex.jobname .. "-error","log")) end)
211
212local function processwarning(offset)
213 local lastwarning = status.lastwarningstring or "?"
214 local lastlocation = status.lastwarningtag or "?"
215 resetmessages()
216 tracers.printwarning {
217 lastwarning = lastwarning ,
218 lastlocation = lastlocation,
219 }
220end
221
222function tracers.printwarning(specification)
223 logs.report("luatex warning","%s: %s",specification.lastlocation,specification.lastwarning)
224end
225
226directives.register("system.errorcontext", function(v)
227 local register = callback.register
228 if v then
229 register('show_error_message', nop)
230 register('show_warning_message',function() processwarning(v) end)
231 register('show_error_hook', function(eof) processerror(v,eof) end)
232 register('show_lua_error_hook', function() processerror(v) end)
233 else
234 register('show_error_message', nil)
235 register('show_error_hook', nil)
236 register('show_warning_message',nil)
237 register('show_lua_error_hook', nil)
238 end
239end)
240
241
242
243lmx = lmx or { }
244
245lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
246lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end
247
248local function reportback(lmxname,default,variables)
249 if lmxname == false then
250 return variables
251 else
252 local name = lmx.show(type(lmxname) == "string" and lmxname or default,variables)
253 if name then
254 logs.report("context report","file: %s",name)
255 end
256 end
257end
258
259local function showerror(lmxname)
260 local filename, linenumber, errorcontext = status.filename, tonumber(status.linenumber) or 0, ""
261 if not filename then
262 filename, errorcontext = 'unknown', 'error in filename'
263 elseif type(filename) == "number" then
264 filename, errorcontext = format("<read %s>",filename), 'unknown error'
265 else
266 errorcontext = tracers.showlines(filename,linenumber,offset)
267 end
268 local variables = {
269 ['title'] = 'ConTeXt Error Information',
270 ['errormessage'] = status.lasterrorstring,
271 ['linenumber'] = linenumber,
272 ['color-background-one'] = lmx.get('color-background-yellow'),
273 ['color-background-two'] = lmx.get('color-background-purple'),
274 ['filename'] = filename,
275 ['errorcontext'] = errorcontext,
276 }
277 reportback(lmxname,"context-error.lmx",variables)
278 luatex.abort()
279end
280
281lmx.showerror = showerror
282
283function lmx.overloaderror(v)
284 if v == "scite" then
285 usescitelexer = true
286 end
287 callback.register('show_error_hook', function() showerror() end)
288 callback.register('show_lua_error_hook', function() showerror() end)
289 callback.register('show_tex_error_hook', function() showerror() end)
290end
291
292directives.register("system.showerror", lmx.overloaderror)
293
294
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
329implement { name = "showtrackers", actions = trackers.show }
330implement { name = "enabletrackers", actions = trackers.enable, arguments = "string" }
331implement { name = "disabletrackers", actions = trackers.disable, arguments = "string" }
332implement { name = "resettrackers", actions = trackers.reset }
333
334implement { name = "showdirectives", actions = directives.show }
335implement { name = "enabledirectives", actions = directives.enable, arguments = "string" }
336implement { name = "disabledirectives", actions = directives.disable, arguments = "string" }
337
338implement { name = "showexperiments", actions = experiments.show }
339implement { name = "enableexperiments", actions = experiments.enable, arguments = "string" }
340implement { name = "disableexperiments", actions = experiments.disable, arguments = "string" }
341
342implement { name = "overloaderror", actions = lmx.overloaderror }
343implement { name = "showlogcategories", actions = logs.show }
344
345local debugger = utilities.debugger
346
347directives.register("system.profile",function(n)
348 luatex.registerstopactions(function()
349 debugger.disable()
350 debugger.savestats("luatex-profile.log",tonumber(n) or 0)
351 report_nl()
352 logs.report("system","profiler stopped, log saved in %a","luatex-profile.log")
353 report_nl()
354 end)
355 logs.report("system","profiler started")
356 debugger.enable()
357end)
358 |