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
22
23local implement = interfaces.implement
24
25local ioflush = io.flush
26local ioread = io.read
27local ossleep = os.sleep
28local osexit = os.exit
29local writenl = texio.writenl
30local write = texio.write
31
32local runlocal = tex.runlocal
33local terminaldata = false
34local context = context
35
36implement {
37 name = "fetchterminaldata",
38 actions = function()
39 context(terminaldata)
40 end,
41}
42
43function texio.terminal()
44 writenl("\n" .. "entering interactive mode, use \\quit to abort reading" .."\n\n")
45 while true do
46 write(">")
47 ioflush()
48 terminaldata = ioread()
49 if terminaldata == "\\quit" then
50 terminaldata = false
51 break
52 else
53 runlocal("t_syst_terminal_data",nil,nil,true)
54 end
55 end
56end
57
58implement {
59 name = "readfromterminal",
60 public = true,
61 protected = true,
62 actions = texio.terminal,
63}
64
65local savedluaerror = nil
66local usescitelexer = nil
67local quitonerror = true
68
69local function errorreporter(luaerror)
70 local category = luaerror and "lua error" or "tex error"
71 local report = logs.reporter(category)
72 logs.enable(category)
73 return report
74end
75
76function tracers.showlines(filename,linenumber,offset,luaerrorline)
77 local data = io.loaddata(filename)
78 if not data or data == "" then
79 local hash = url.hashed(filename)
80 if not hash.noscheme then
81 local ok, d, n = resolvers.loaders.byscheme(hash.scheme,filename)
82 if ok and n > 0 then
83 data = d
84 end
85 end
86 end
87 local scite = usescitelexer and require("util-sci")
88 if scite then
89 return utilities.scite.tohtml(data,"tex",linenumber or true,false)
90 else
91 local lines = data and string.splitlines(data)
92 if lines and #lines > 0 then
93 if luaerrorline and luaerrorline > 0 then
94
95 local start = "\\startluacode"
96 local stop = "\\stopluacode"
97 local n = linenumber
98 for i=n,1,-1 do
99 local line = lines[i]
100 if not line then
101 break
102 elseif find(line,start) then
103 n = i + luaerrorline - 1
104 if n <= linenumber then
105 linenumber = n
106 end
107 break
108 end
109 end
110 end
111 offset = tonumber(offset) or 10
112 linenumber = tonumber(linenumber) or 10
113 local start = math.max(linenumber - offset,1)
114 local stop = math.min(linenumber + offset,#lines)
115 if stop > #lines then
116 return "<linenumber past end of file>"
117 else
118 local result, fmt = { }, "%" .. #tostring(stop) .. "d %s %s"
119 for n=start,stop do
120 result[#result+1] = format(fmt,n,n == linenumber and ">>" or " ",lines[n])
121 end
122 return concat(result,"\n")
123 end
124 else
125 return "<empty file>"
126 end
127 end
128end
129
130
131
132
133
134
135
136local nop = function() end
137local resetmessages = status.resetmessages or nop
138
139local function processerror(offset,errortype)
140 local readstate = status.getreadstate()
141 local filename = readstate.filename
142 local linenumber = readstate.linenumber
143 local skiplinenumber = readstate.skiplinenumber
144 local errorstate = status.errorstate
145 local lastcontext = errorstate.errorcontext
146 local lasttexerror = errorstate.error or "?"
147 local lastluaerror = errorstate.luaerror or "?"
148 local luaerrorline = match(lastluaerror,[[lua%]?:.-(%d+)]]) or (lastluaerror and find(lastluaerror,"?:0:",1,true) and 0)
149 local lastmpserror = match(lasttexerror,[[^.-mp%serror:%s*(.*)$]])
150 resetmessages()
151 lastluaerror = gsub(lastluaerror,"%[\\directlua%]","[ctxlua]")
152 tracers.printerror {
153 filename = filename,
154 linenumber = linenumber,
155 skiplinenumber = skiplinenumber,
156 offset = tonumber(offset) or 10,
157 lasttexerror = lasttexerror,
158 lastmpserror = lastmpserror,
159 lastluaerror = lastluaerror,
160 luaerrorline = luaerrorline,
161 lastcontext = lastcontext,
162 lasttexhelp = tex.gethelptext and tex.gethelptext() or nil,
163 errortype = errortype,
164 }
165 if job and type(job.disablesave) == "function" then
166 job.disablesave()
167 end
168 lua.setexitcode(1)
169end
170
171directives.register("system.quitonerror",function(v)
172 quitonerror = toboolean(v)
173end)
174
175directives.register("system.usescitelexer",function(v)
176 usescitelexer = toboolean(v)
177end)
178
179local busy = false
180
181function tracers.printerror(specification)
182 if not busy then
183 busy = true
184 local errorvalues = table.swapped(tex.geterrorvalues())
185 local filename = specification.filename
186 local linenumber = specification.linenumber
187 local lasttexerror = specification.lasttexerror
188 local lastmpserror = specification.lastmpserror
189 local lastluaerror = specification.lastluaerror
190 local lastcontext = specification.lastcontext
191 local luaerrorline = specification.luaerrorline
192 local errortype = specification.errortype
193 local offset = specification.offset
194 local endoffile = specification.endoffile
195 local report = errorreporter(luaerrorline)
196 if errortype == errorvalues.warning then
197 report("warning error: %s",lasttexerror or "-")
198 busy = false;
199 return;
200 elseif errortype == errorvalues.eof then
201 report("runaway error: %s",lasttexerror or "-")
202 if not quitonerror and texio.terminal then
203 texio.terminal()
204 end
205 elseif errortype == errorvalues.condition then
206 linenumber = specification.skiplinenumber
207 if linenumber > 0 then
208 report("condition error on line %s in file %s: %s",linenumber,filename,lasttexerror)
209 report_nl()
210 report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline)))
211 report_nl()
212 else
213 report("runaway condition error: %s",lasttexerror or "-")
214 end
215 quitonerror = true
216 elseif not filename then
217 report("fuzzy error:")
218 report(" tex: %s",lasttexerror or "-")
219 report(" lua: %s",lastluaerror or "-")
220 report(" mps: %s",lastmpserror or "-")
221 elseif type(filename) == "number" then
222 report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror)
223 else
224 report_nl()
225 if luaerrorline then
226 if linenumber == 0 or not filename or filename == "" then
227 print("\nfatal lua error:\n\n",lastluaerror,"\n")
228 luatex.abort()
229 return
230 else
231 report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror)
232 end
233 elseif lastmpserror then
234 report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror)
235 else
236 report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror)
237 if lastcontext then
238 report_nl()
239 report_str(lastcontext)
240 report_nl()
241 else
242 report_nl()
243
244 end
245 if lastluaerror and not match(lastluaerror,"^%s*[%?]*%s*$") then
246 print("\nlua error:\n\n",lastluaerror,"\n")
247 quitonerror = true
248 end
249 end
250 report_nl()
251 report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline)))
252 report_nl()
253 end
254 if quitonerror then
255 local name = tex.jobname or ""
256 if name ~= "" then
257 table.save(name .. "-error.log",specification)
258 end
259 local help = specification.lasttexhelp
260 if help and #help > 0 then
261 report_nl()
262 report_str(help)
263 report_nl()
264 report_nl()
265 end
266 luatex.abort()
267 end
268 busy = false
269 end
270end
271
272luatex.wrapup(function() os.remove(tex.jobname .. "-error.log") end)
273
274local function processwarning(offset)
275 local warningstate = status.warningstate
276 local lastwarning = warningstate.warning or "?"
277 local lastlocation = warningstate.warningtag or "?"
278 resetmessages()
279 tracers.printwarning {
280 lastwarning = lastwarning,
281 lastlocation = lastlocation,
282 }
283end
284
285function tracers.printwarning(specification)
286 logs.report("luatex warning","%s: %s",specification.lastlocation,specification.lastwarning)
287end
288
289directives.register("system.errorcontext", function(v)
290 local register = callback.register
291 if v then
292 register("show_error_message", nop)
293 register("show_warning_message", function() processwarning(v) end)
294 register("intercept_lua_error", function() processerror(v) end)
295 register("intercept_tex_error", function(mode,eof) processerror(v,eof) return mode end)
296 else
297 register("show_error_message", nil)
298 register("show_warning_message", nil)
299 register("intercept_lua_error", nil)
300 register("intercept_tex_error", nil)
301 end
302end)
303
304
305
306lmx = lmx or { }
307
308lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
309lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end
310
311local function reportback(lmxname,default,variables)
312 if lmxname == false then
313 return variables
314 else
315 local name = lmx.show(type(lmxname) == "string" and lmxname or default,variables)
316 if name then
317 logs.report("context report","file: %s",name)
318 end
319 end
320end
321
322local function showerror(lmxname)
323 local readstate = status.getreadstate()
324 local filename = readstate.filename
325 local linenumber = tonumber(readstate.linenumber) or 0
326 local errorcontext = ""
327 if not filename then
328 filename = status.iocodes[readstate.iocode]
329 errorcontext = 'error in filename'
330 else
331 errorcontext = tracers.showlines(filename,linenumber,offset)
332 end
333 local variables = {
334 ['title'] = 'ConTeXt Error Information',
335 ['errormessage'] = status.geterrorstate().error or "?",
336 ['linenumber'] = linenumber,
337 ['color-background-one'] = lmx.get('color-background-yellow'),
338 ['color-background-two'] = lmx.get('color-background-purple'),
339 ['filename'] = filename,
340 ['errorcontext'] = errorcontext,
341 }
342 reportback(lmxname,"context-error.lmx",variables)
343 luatex.abort()
344end
345
346lmx.showerror = showerror
347
348function lmx.overloaderror(v)
349 if v == "scite" then
350 usescitelexer = true
351 end
352 callback.register('show_error_message', function() showerror() end)
353
354
355end
356
357directives.register("system.showerror", lmx.overloaderror)
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394implement { name = "showtrackers", public = true, protected = true, actions = trackers.show }
395implement { name = "enabletrackers", public = true, protected = true, actions = trackers.enable, arguments = "optional" }
396implement { name = "disabletrackers", public = true, protected = true, actions = trackers.disable, arguments = "optional" }
397implement { name = "resettrackers", public = true, protected = true, actions = trackers.reset }
398
399implement { name = "showdirectives", public = true, protected = true, actions = directives.show }
400implement { name = "enabledirectives", public = true, protected = true, actions = directives.enable, arguments = "optional" }
401implement { name = "disabledirectives", public = true, protected = true, actions = directives.disable, arguments = "optional" }
402
403implement { name = "showexperiments", public = true, protected = true, actions = experiments.show }
404implement { name = "enableexperiments", public = true, protected = true, actions = experiments.enable, arguments = "optional" }
405implement { name = "disableexperiments", public = true, protected = true, actions = experiments.disable, arguments = "optional" }
406
407implement { name = "overloaderror", public = true, protected = true, actions = lmx.overloaderror }
408implement { name = "showlogcategories", public = true, protected = true, actions = logs.show }
409
410local debugger = utilities.debugger
411
412directives.register("system.profile",function(n)
413 luatex.registerstopactions(function()
414 debugger.disable()
415 debugger.savestats("luatex-profile.log",tonumber(n) or 0)
416 report_nl()
417 logs.report("system","profiler stopped, log saved in %a","luatex-profile.log")
418 report_nl()
419 end)
420 logs.report("system","profiler started")
421 debugger.enable()
422end)
423
424local report = logs.reporter("[[diagnostic]]")
425
426implement {
427 name = "diagnostic",
428 public = true,
429
430 arguments = { "optional", "string" },
431 actions = function(t,s)
432 if t == "quit" then
433 report(s)
434 osexit()
435 else
436 t = tonumber(t)
437 if t then
438 report("%s (sleep: %.3N)",s,t)
439 ioflush()
440 ossleep(t)
441 else
442 report(s)
443 ioflush()
444 end
445 end
446 end
447}
448 |