if not modules then modules = { } end modules ['trac-deb'] = { version = 1.001, comment = "companion to trac-deb.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local lpeg, status = lpeg, status local lpegmatch = lpeg.match local format, concat, match = string.format, table.concat, string.match local tonumber, tostring = tonumber, tostring -- maybe tracers -> tracers.tex (and tracers.lua for current debugger) local report_system = logs.reporter("system","tex") tracers = tracers or { } local tracers = tracers tracers.lists = { } local lists = tracers.lists tracers.strings = { } local strings = tracers.strings local texgetdimen = tex.getdimen local texgettoks = tex.gettoks local texgetcount = tex.getcount strings.undefined = "undefined" lists.scratch = { 0, 2, 4, 6, 8 } lists.internals = { 'p:hsize', 'p:parindent', 'p:leftskip','p:rightskip', 'p:vsize', 'p:parskip', 'p:baselineskip', 'p:lineskip', 'p:topskip' } lists.context = { 'd:lineheight', 'c:realpageno', 'c:userpageno', 'c:pageno', 'c:subpageno' } local types = { ['d'] = tracers.dimen, ['c'] = tracers.count, ['t'] = tracers.toks, ['p'] = tracers.primitive } local splitboth = lpeg.splitat(":") local splittype = lpeg.firstofsplit(":") local splitname = lpeg.secondofsplit(":") function tracers.type(csname) return lpegmatch(splittype,csname) end function tracers.name(csname) return lpegmatch(splitname,csname) or csname end function tracers.cs(csname) local tag, name = lpegmatch(splitboth,csname) if name and types[tag] then return types[tag](name) else return tracers.primitive(csname) end end function tracers.dimen(name) local d = texgetdimen(name) return d and number.topoints(d) or strings.undefined end function tracers.count(name) return texgetcount(name) or strings.undefined end function tracers.toks(name,limit) local t = texgettoks(name) return t and string.limit(t,tonumber(limit) or 40) or strings.undefined end function tracers.primitive(name) return tex[name] or strings.undefined end function tracers.knownlist(name) local l = lists[name] return l and #l > 0 end function tracers.showlines(filename,linenumber,offset,errorstr) local data = io.loaddata(filename) if not data or data == "" then local hash = url.hashed(filename) if not hash.noscheme then local ok, d, n = resolvers.loaders.byscheme(hash.scheme,filename) if ok and n > 0 then data = d end end end local lines = data and string.splitlines(data) if lines and #lines > 0 then -- This does not work completely as we cannot access the last Lua error using -- table.print(status.list()). This is on the agenda. Eventually we will -- have a sequence of checks here (tex, lua, mp) at this end. -- -- Actually, in 0.75+ the lua error message is even weirder as you can -- get: -- -- LuaTeX error [string "\directlua "]:3: unexpected symbol near '1' ... -- -- \endgroup \directlua { -- -- So there is some work to be done in the LuaTeX engine. -- local what, where = match(errorstr,[[LuaTeX error
:(%d+)]]) or match(errorstr,[[LuaTeX error %[string "\\(.-lua) "%]:(%d+)]]) -- buglet if where then -- lua error: linenumber points to last line local start = "\\startluacode" local stop = "\\stopluacode" local where = tonumber(where) if lines[linenumber] == start then local n = linenumber for i=n,1,-1 do if lines[i] == start then local n = i + where if n <= linenumber then linenumber = n end end end end end offset = tonumber(offset) or 10 linenumber = tonumber(linenumber) or 10 local start = math.max(linenumber - offset,1) local stop = math.min(linenumber + offset,#lines) if stop > #lines then return "" else local result, fmt = { }, "%" .. #tostring(stop) .. "d %s %s" for n=start,stop do result[#result+1] = format(fmt,n,n == linenumber and ">>" or " ",lines[n]) end return concat(result,"\n") end else return "" end end function tracers.printerror(offset) local inputstack = resolvers.inputstack local filename = inputstack[#inputstack] or status.filename local linenumber = tonumber(status.linenumber) or 0 if not filename then report_system("error not related to input file: %s ...",status.lasterrorstring) elseif type(filename) == "number" then report_system("error on line %s of filehandle %s: %s ...",linenumber,filename,status.lasterrorstring) else -- currently we still get the error message printed to the log/console so we -- add a bit of spacing around our variant texio.write_nl("\n") local errorstr = status.lasterrorstring or "?" -- inspect(status.list()) report_system("error on line %s in file %s: %s ...\n",linenumber,filename,errorstr) -- lua error? texio.write_nl(tracers.showlines(filename,linenumber,offset,errorstr),"\n") end end directives.register("system.errorcontext", function(v) if v then callback.register('show_error_hook', function() tracers.printerror(v) end) else callback.register('show_error_hook', nil) end end) -- this might move lmx = lmx or { } lmx.htmfile = function(name) return environment.jobname .. "-status.html" end lmx.lmxfile = function(name) return resolvers.findfile(name,'tex') end function lmx.showdebuginfo(lmxname) local variables = { ['title'] = 'ConTeXt Debug Information', ['color-background-one'] = lmx.get('color-background-green'), ['color-background-two'] = lmx.get('color-background-blue'), } if lmxname == false then return variables else lmx.show(lmxname or 'context-debug.lmx',variables) end end function lmx.showerror(lmxname) local filename, linenumber, errorcontext = status.filename, tonumber(status.linenumber) or 0, "" if not filename then filename, errorcontext = 'unknown', 'error in filename' elseif type(filename) == "number" then filename, errorcontext = format("",filename), 'unknown error' else errorcontext = tracers.showlines(filename,linenumber,offset) end local variables = { ['title'] = 'ConTeXt Error Information', ['errormessage'] = status.lasterrorstring, ['linenumber'] = linenumber, ['color-background-one'] = lmx.get('color-background-yellow'), ['color-background-two'] = lmx.get('color-background-purple'), ['filename'] = filename, ['errorcontext'] = errorcontext, } if lmxname == false then return variables else lmx.show(lmxname or 'context-error.lmx',variables) end end function lmx.overloaderror() callback.register('show_error_hook', function() lmx.showerror() end) -- prevents arguments being passed end directives.register("system.showerror", lmx.overloaderror) local debugger = utilities.debugger local function trace_calls(n) debugger.enable() luatex.registerstopactions(function() debugger.disable() debugger.savestats(tex.jobname .. "-luacalls.log",tonumber(n)) end) trace_calls = function() end end directives.register("system.tracecalls", function(n) trace_calls(n) end) -- indirect is needed for nilling