diff options
| author | Andrew Lee <alee14498@gmail.com> | 2019-07-19 14:10:39 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@gmail.com> | 2019-07-19 14:10:39 -0400 |
| commit | fe08446d84e0aa939780ad013f0545778703da6d (patch) | |
| tree | f45358ae6470dc894c41abcb278c4898c7ef1b18 /.mbs/lib/stack_trace.lua | |
| parent | 21446806b264d8fd6694b1495f0c51bf24d26b35 (diff) | |
| download | bits-UI-fe08446d84e0aa939780ad013f0545778703da6d.tar.gz bits-UI-fe08446d84e0aa939780ad013f0545778703da6d.tar.bz2 bits-UI-fe08446d84e0aa939780ad013f0545778703da6d.zip | |
MBS as default shell
Diffstat (limited to '.mbs/lib/stack_trace.lua')
| -rw-r--r-- | .mbs/lib/stack_trace.lua | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/.mbs/lib/stack_trace.lua b/.mbs/lib/stack_trace.lua new file mode 100644 index 0000000..7674813 --- /dev/null +++ b/.mbs/lib/stack_trace.lua @@ -0,0 +1,88 @@ +local type = type +local debug_traceback = type(debug) == "table" and type(debug.traceback) == "function" and debug.traceback + +local function traceback(x) + -- Attempt to detect error() and error("xyz", 0). + -- This probably means they're erroring the program intentionally and so we + -- shouldn't display anything. + if x == nil or (type(x) == "string" and not x:find(":%d+:")) then + return x + end + + if debug_traceback then + -- The parens are important, as they prevent a tail call occuring, meaning + -- the stack level is preserved. This ensures the code behaves identically + -- on LuaJ and PUC Lua. + return (debug_traceback(tostring(x), 2)) + else + local level = 3 + local out = { tostring(x), "stack traceback:" } + while true do + local _, msg = pcall(error, "", level) + if msg == "" then break end + + out[#out + 1] = " " .. msg + level = level + 1 + end + + return table.concat(out, "\n") + end +end + +local function trim_traceback(target, marker) + local ttarget, tmarker = {}, {} + for line in target:gmatch("([^\n]*)\n?") do ttarget[#ttarget + 1] = line end + for line in marker:gmatch("([^\n]*)\n?") do tmarker[#tmarker + 1] = line end + + -- Trim identical suffixes + local t_len, m_len = #ttarget, #tmarker + while t_len >= 3 and ttarget[t_len] == tmarker[m_len] do + table.remove(ttarget, t_len) + t_len, m_len = t_len - 1, m_len - 1 + end + + -- Trim elements from this file and xpcall invocations + while t_len >= 1 and ttarget[t_len]:find("^\tstack_trace%.lua:%d+:") or + ttarget[t_len] == "\t[C]: in function 'xpcall'" or ttarget[t_len] == " xpcall: " do + table.remove(ttarget, t_len) + t_len = t_len - 1 + end + + return ttarget +end + +--- Run a function with +local function xpcall_with(fn) + -- So this is rather grim: we need to get the full traceback and current one and remove + -- the common prefix + local trace + local res = table.pack(xpcall(fn, traceback)) if not res[1] then trace = traceback("trace.lua:1:") end + local ok, err = res[1], res[2] + + if not ok and err ~= nil then + trace = trim_traceback(err, trace) + + -- Find the position where the stack traceback actually starts + local trace_starts + for i = #trace, 1, -1 do + if trace[i] == "stack traceback:" then trace_starts = i; break end + end + + -- If this traceback is more than 15 elements long, keep the first 9, last 5 + -- and put an ellipsis between the rest + local max = 15 + if trace_starts and #trace - trace_starts > max then + local keep_starts = trace_starts + 10 + for i = #trace - trace_starts - max, 0, -1 do table.remove(trace, keep_starts + i) end + table.insert(trace, keep_starts, " ...") + end + + return false, table.concat(trace, "\n") + end + + return table.unpack(res, 1, res.n) +end + +_ENV.traceback = traceback +_ENV.trim_traceback = trim_traceback +_ENV.xpcall_with = xpcall_with
\ No newline at end of file |
