Looking mostly good, sorta working for moonscript.
This commit is contained in:
parent
2a1cdf7c89
commit
c921ad41bd
169
cursed.moon
169
cursed.moon
@ -1,7 +1,7 @@
|
||||
C = require "curses"
|
||||
repr = require 'repr'
|
||||
local REGULAR, INVERTED, HIGHLIGHTED, RED, SCREEN_H, SCREEN_W
|
||||
local run_debugger, cursed, stdscr, main_loop
|
||||
local REGULAR, INVERTED, HIGHLIGHTED, RED, BLUE, SCREEN_H, SCREEN_W
|
||||
local run_debugger, guard, stdscr, main_loop
|
||||
AUTO = -1
|
||||
log = io.open("output.log", "w")
|
||||
|
||||
@ -10,23 +10,36 @@ callstack_range = ->
|
||||
min, max = 0, -1
|
||||
for i=1,999 do
|
||||
info = debug.getinfo(i, 'f')
|
||||
if not info
|
||||
error("Could not find info at level #{i}")
|
||||
continue unless info
|
||||
if not info then break
|
||||
if info.func == main_loop
|
||||
min = i+2
|
||||
min = i+1
|
||||
break
|
||||
for i=min,999
|
||||
info = debug.getinfo(i, 'f')
|
||||
continue unless info
|
||||
if info.func == cursed then
|
||||
if not info
|
||||
max = i-3
|
||||
break
|
||||
if info.func == guard
|
||||
max = i-3
|
||||
break
|
||||
return min, max
|
||||
|
||||
wrap_text = (text, width)->
|
||||
lines = {}
|
||||
for line in text\gmatch("[^\n]*")
|
||||
buff = ""
|
||||
for word in line\gmatch("%S%S*%s*")
|
||||
if #buff + #word > width
|
||||
table.insert(lines, " "..buff)
|
||||
buff = word
|
||||
else
|
||||
buff = buff .. word
|
||||
table.insert(lines, " "..buff)
|
||||
return lines
|
||||
|
||||
alternating_colors = setmetatable({}, {__index:(i)=> if i % 2 == 0 then INVERTED else REGULAR})
|
||||
class Pad
|
||||
new: (@y,@x,@height,@width,@lines,@attrs=alternating_colors)=>
|
||||
new: (@y,@x,@height,@width,@lines,@attrs=alternating_colors, pad_attr=0)=>
|
||||
--log\write("New Pad:\n #{table.concat @lines, "\n "}\n")
|
||||
@offset = 0
|
||||
@selected = nil
|
||||
@ -43,6 +56,7 @@ class Pad
|
||||
--log\write("#lines = #{#@lines}, height = #{@_height}, width = #{@_width}\n")
|
||||
@_pad = C.newpad(@_height, @_width)
|
||||
@_pad\scrollok(true)
|
||||
@_pad\attrset(pad_attr)
|
||||
|
||||
@chstrs = {}
|
||||
for i, line in ipairs(@lines)
|
||||
@ -79,6 +93,7 @@ class Pad
|
||||
@offset = @selected - 1
|
||||
@refresh!
|
||||
if @on_select then @on_select(@selected)
|
||||
return @selected
|
||||
|
||||
refresh: =>
|
||||
@_pad\border(C.ACS_VLINE, C.ACS_VLINE,
|
||||
@ -108,7 +123,21 @@ class Pad
|
||||
@select(@selected and (@selected + delta) or 1)
|
||||
|
||||
|
||||
main_loop = (err_msg, stack_index=1, var_index)->
|
||||
ok, to_lua = pcall -> require('moonscript.base').to_lua
|
||||
if not ok then to_lua = -> nil
|
||||
file_cache = setmetatable({}, {__index:(filename)=>
|
||||
@[filename] = io.open(filename)\read("*a")
|
||||
return @[filename]
|
||||
})
|
||||
line_tables = setmetatable({}, {__index:(filename)=>
|
||||
file = file_cache[filename]
|
||||
ok, line_table = to_lua(file)
|
||||
if ok
|
||||
@[filename] = line_table
|
||||
return line_table
|
||||
})
|
||||
|
||||
main_loop = (err_msg, stack_index=1, var_index, value_index)->
|
||||
SCREEN_H, SCREEN_W = stdscr\getmaxyx!
|
||||
|
||||
stdscr\clear!
|
||||
@ -122,28 +151,26 @@ main_loop = (err_msg, stack_index=1, var_index)->
|
||||
info = debug.getinfo(i)
|
||||
if not info then break
|
||||
table.insert(stack_names, info.name or "<unnamed function>")
|
||||
filename = info.short_src..":"..info.currentline
|
||||
table.insert(stack_locations, filename)
|
||||
max_filename = math.max(max_filename, #filename)
|
||||
|
||||
line = if line_tables[info.short_src]
|
||||
char = line_tables[info.short_src][info.currentline]
|
||||
line_num = 1
|
||||
file = file_cache[info.short_src]
|
||||
for _ in file\sub(1,char)\gmatch("\n") do line_num += 1
|
||||
"#{info.short_src}:#{line_num}"
|
||||
else
|
||||
info.short_src..":"..info.currentline
|
||||
table.insert(stack_locations, line)
|
||||
max_filename = math.max(max_filename, #line)
|
||||
callstack = {}
|
||||
for i=1,#stack_names do
|
||||
callstack[i] = stack_locations[i]..(" ")\rep(max_filename-#stack_locations[i]).." | "..stack_names[i].." "
|
||||
|
||||
err_msg_lines = {}
|
||||
for line in err_msg\gmatch("[^\n]*")
|
||||
buff = ""
|
||||
for word in line\gmatch("%S%S*%s*")
|
||||
if #buff + #word > SCREEN_W - 4
|
||||
table.insert(err_msg_lines, " "..buff)
|
||||
buff = word
|
||||
else
|
||||
buff = buff .. word
|
||||
table.insert(err_msg_lines, " "..buff)
|
||||
err_pad = Pad(0,0,AUTO,SCREEN_W, err_msg_lines,setmetatable({}, __index:->RED))
|
||||
err_pad._pad\attrset(RED)
|
||||
err_msg_lines = wrap_text(err_msg, SCREEN_W - 4)
|
||||
err_pad = Pad(0,0,AUTO,SCREEN_W, err_msg_lines,setmetatable({}, __index:->RED), RED)
|
||||
|
||||
stack_pad = Pad(err_pad.height,0,AUTO,AUTO, callstack)
|
||||
stack_pad\select(stack_index)
|
||||
stack_pad = Pad(err_pad.height,0,AUTO,AUTO, callstack, nil, BLUE)
|
||||
stack_index = stack_pad\select(stack_index)
|
||||
|
||||
callstack_min, _ = callstack_range!
|
||||
_var_names, _var_values = {}, {}
|
||||
@ -158,55 +185,71 @@ main_loop = (err_msg, stack_index=1, var_index)->
|
||||
else
|
||||
table.insert(_var_values, repr(value))
|
||||
|
||||
var_names = Pad(err_pad.height,stack_pad.x+stack_pad.width,10,AUTO,_var_names)
|
||||
var_values = Pad(err_pad.height,var_names.x+var_names.width,10,AUTO,_var_values)
|
||||
var_names = Pad(err_pad.height,stack_pad.x+stack_pad.width,AUTO,AUTO,_var_names, nil, BLUE)
|
||||
if var_index and #_var_names > 0
|
||||
var_names\select(var_index)
|
||||
var_values\select(var_index)
|
||||
var_index = var_names\select(var_index)
|
||||
|
||||
value_x = var_names.x+var_names.width
|
||||
value_w = SCREEN_W-(value_x+1)
|
||||
if value_index
|
||||
var_values = Pad(err_pad.height,value_x,AUTO,value_w,wrap_text(_var_values[var_index], value_w), nil, BLUE)
|
||||
value_index = var_values\select(value_index)
|
||||
else
|
||||
var_values = Pad(err_pad.height,value_x,AUTO,value_w,_var_values, nil, BLUE)
|
||||
|
||||
while true
|
||||
C.doupdate!
|
||||
c = stdscr\getch!
|
||||
switch c
|
||||
when C.KEY_DOWN, C.KEY_SF, ("j")\byte!
|
||||
if var_index
|
||||
var_names\scroll(1)
|
||||
return main_loop(err_msg,stack_pad.selected,var_names.selected)
|
||||
if value_index
|
||||
value_index += 1
|
||||
elseif var_index
|
||||
var_index += 1
|
||||
else
|
||||
stack_pad\scroll(1)
|
||||
return main_loop(err_msg,stack_pad.selected,nil)
|
||||
stack_index += 1
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when C.KEY_UP, C.KEY_SR, ("k")\byte!
|
||||
if var_index
|
||||
var_names\scroll(-1)
|
||||
return main_loop(err_msg,stack_pad.selected,var_names.selected)
|
||||
if value_index
|
||||
value_index -= 1
|
||||
elseif var_index
|
||||
var_index -= 1
|
||||
else
|
||||
stack_pad\scroll(-1)
|
||||
return main_loop(err_msg,stack_pad.selected,nil)
|
||||
stack_index -= 1
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when ('J')\byte!
|
||||
if var_index
|
||||
var_names\scroll(10)
|
||||
return main_loop(err_msg,stack_pad.selected,var_names.selected)
|
||||
if value_index
|
||||
value_index += 10
|
||||
elseif var_index
|
||||
var_index += 10
|
||||
else
|
||||
stack_pad\scroll(10)
|
||||
return main_loop(err_msg,stack_pad.selected,nil)
|
||||
stack_index += 10
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when ('K')\byte!
|
||||
if var_index
|
||||
var_names\scroll(-10)
|
||||
return main_loop(err_msg,stack_pad.selected,var_names.selected)
|
||||
if value_index
|
||||
value_index -= 10
|
||||
elseif var_index
|
||||
var_index -= 10
|
||||
else
|
||||
stack_pad\scroll(-10)
|
||||
return main_loop(err_msg,stack_pad.selected,nil)
|
||||
stack_index -= 10
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when C.KEY_RIGHT, ("l")\byte!
|
||||
if var_index == nil
|
||||
return main_loop(err_msg,stack_pad.selected,1)
|
||||
var_index = 1
|
||||
elseif value_index == nil
|
||||
value_index = 1
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when C.KEY_LEFT, ("h")\byte!
|
||||
if var_index != nil
|
||||
return main_loop(err_msg,stack_pad.selected,nil)
|
||||
if value_index
|
||||
value_index = nil
|
||||
elseif var_index
|
||||
var_index = nil
|
||||
return main_loop(err_msg,stack_index,var_index,value_index)
|
||||
|
||||
when ('o')\byte!
|
||||
file = stack_locations[stack_pad.selected]
|
||||
@ -232,18 +275,17 @@ run_debugger = (err_msg)->
|
||||
C.start_color!
|
||||
C.use_default_colors!
|
||||
|
||||
export REGULAR, INVERTED, HIGHLIGHTED, RED
|
||||
export REGULAR, INVERTED, HIGHLIGHTED, RED, BLUE
|
||||
_, REGULAR = C.init_pair(1, -1, -1), C.color_pair(1)
|
||||
_, INVERTED = C.init_pair(2, -1, C.COLOR_BLACK), C.color_pair(2)
|
||||
_, HIGHLIGHTED = C.init_pair(3, C.COLOR_BLACK, C.COLOR_YELLOW), C.color_pair(3)
|
||||
_, RED = C.init_pair(4, C.COLOR_RED, -1), C.color_pair(4) | C.A_BOLD
|
||||
_, BLUE = C.init_pair(5, C.COLOR_BLUE, -1), C.color_pair(5) | C.A_BOLD
|
||||
|
||||
return main_loop(err_msg)
|
||||
|
||||
|
||||
cursed = (fn, ...)->
|
||||
-- To display Lua errors, we must close curses to return to
|
||||
-- normal terminal mode, and then write the error to stdout.
|
||||
guard = (fn, ...)->
|
||||
err_hand = (err)->
|
||||
C.endwin!
|
||||
print "Caught an error:"
|
||||
@ -252,4 +294,13 @@ cursed = (fn, ...)->
|
||||
|
||||
return xpcall(fn, ((err_msg)-> xpcall(run_debugger, err_hand, err_msg)), ...)
|
||||
|
||||
return cursed
|
||||
breakpoint = ->
|
||||
err_hand = (err)->
|
||||
C.endwin!
|
||||
print "Caught an error:"
|
||||
print(debug.traceback(err, 2))
|
||||
os.exit(2)
|
||||
|
||||
return xpcall(run_debugger, err_hand, "Breakpoint triggered!")
|
||||
|
||||
return {:guard, :breakpoint}
|
||||
|
Loading…
Reference in New Issue
Block a user