From 2a1cdf7c89d300ddab484b492f0dc1ee77ad187a Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 13 Mar 2018 02:55:03 -0700 Subject: [PATCH] Almost working. --- cursed.moon | 278 +++++++++++++++++++++++++--------------------------- 1 file changed, 131 insertions(+), 147 deletions(-) diff --git a/cursed.moon b/cursed.moon index 75b6a37..dc8a2b0 100644 --- a/cursed.moon +++ b/cursed.moon @@ -1,69 +1,71 @@ C = require "curses" repr = require 'repr' -local REGULAR, INVERTED, HIGHLIGHTED, RED -local run_debugger, cursed +local REGULAR, INVERTED, HIGHLIGHTED, RED, SCREEN_H, SCREEN_W +local run_debugger, cursed, stdscr, main_loop AUTO = -1 +log = io.open("output.log", "w") -- Return the callstack index of the code that actually caused an error and the max index callstack_range = -> min, max = 0, -1 for i=1,999 do - if debug.getinfo(i,'f').func == run_debugger + info = debug.getinfo(i, 'f') + if not info + error("Could not find info at level #{i}") + continue unless info + if info.func == main_loop min = i+2 break for i=min,999 - if debug.getinfo(i,'f').func == cursed then + info = debug.getinfo(i, 'f') + continue unless info + if info.func == cursed then max = i-3 break return min, max +alternating_colors = setmetatable({}, {__index:(i)=> if i % 2 == 0 then INVERTED else REGULAR}) class Pad - new: (@y,@x,@height,@width)=> + new: (@y,@x,@height,@width,@lines,@attrs=alternating_colors)=> + --log\write("New Pad:\n #{table.concat @lines, "\n "}\n") @offset = 0 @selected = nil - @chstrs = {} - @lines = {} + + @_height = #@lines + 2 + @_width = 2 + for x in *@lines do @_width = math.max(@_width, #x+2) + if @height == AUTO - @resize_height = true - @height = 2 + @height = @_height if @width == AUTO - @resize_width = true - @width = 2 - @_width, @_height = 2, 2 + @width = @_width + + --log\write("#lines = #{#@lines}, height = #{@_height}, width = #{@_width}\n") @_pad = C.newpad(@_height, @_width) @_pad\scrollok(true) - - move_to: (y, x)=> - --@erase! - @y = y - @x = x + + @chstrs = {} + for i, line in ipairs(@lines) + attr = @attrs[i] + chstr = C.new_chstr(@width-2) + @chstrs[i] = chstr + chstr\set_str(0, line, attr) + chstr\set_str(#line+0, ' ', attr, chstr\len!-#line) + @_pad\mvaddchstr(i-1+1,0+1,chstr) @refresh! - if @on_move then @on_move! - - set_size: (h, w)=> - @height = h - @width = w - @refresh! - if @on_resize then @on_resize! - - set_internal_size: (h, w)=> - @_height = h - @_width = w - @refresh! - if @on_resize then @on_resize! select: (i)=> - return if i == @selected + if i == @selected or #@lines == 0 then return if i != nil i = math.max(1, math.min(#@lines, i)) if @selected j = @selected - attr = j % 2 == 0 and INVERTED or REGULAR - @chstrs[j]\set_str(0, @lines[j], attr) - @chstrs[j]\set_str(#@lines[j], ' ', attr, @chstrs[j]\len!-#@lines[j]) + @chstrs[j]\set_str(0, @lines[j], @attrs[j]) + @chstrs[j]\set_str(#@lines[j], ' ', @attrs[j], @chstrs[j]\len!-#@lines[j]) @_pad\mvaddchstr(j-1+1,0+1,@chstrs[j]) if i + assert(@chstrs[i], "DIDN'T FIND CHSTR: #{i}/#{#@chstrs} (#{#@lines})") @chstrs[i]\set_str(0, @lines[i], HIGHLIGHTED) @chstrs[i]\set_str(#@lines[i], ' ', HIGHLIGHTED, @chstrs[i]\len!-#@lines[i]) @_pad\mvaddchstr(i-1+1,0+1,@chstrs[i]) @@ -83,34 +85,7 @@ class Pad C.ACS_HLINE, C.ACS_HLINE, C.ACS_ULCORNER, C.ACS_URCORNER, C.ACS_LLCORNER, C.ACS_LRCORNER) - @_pad\pnoutrefresh(@offset,0,@y,@x,@y+@height,@x+@width) - - set_lines: (lines, attrs)=> - attrs = attrs or setmetatable({}, {__index:(i)=> if i % 2 == 0 then INVERTED else REGULAR}) - @lines = {} - @attrs = {} - @chstrs = {} - max_width = 0 - for i, line in ipairs(lines) - max_width = math.max(max_width, #line) - @_width = max_width + 2 - if @resize_width - @width = @_width - @_height = #lines + 2 - if @resize_height - @height = @_height - @_pad\resize(@_height, @_width) - - for i, line in ipairs(lines) - @lines[i] = line - attr = attrs[i] - @attrs[i] = attr - chstr = C.new_chstr(@width-2) - @chstrs[i] = chstr - chstr\set_str(0, line, attr) - chstr\set_str(#line+0, ' ', attr, chstr\len!-#line) - @_pad\mvaddchstr(i-1+1,0+1,chstr) - @refresh! + @_pad\pnoutrefresh(@offset,0,@y,@x,@y+@height+1,@x+@width) erase: => @_pad\erase! @@ -133,27 +108,11 @@ class Pad @select(@selected and (@selected + delta) or 1) -run_debugger = (err_msg)-> - initial_index = 1 - stdscr = C.initscr! +main_loop = (err_msg, stack_index=1, var_index)-> SCREEN_H, SCREEN_W = stdscr\getmaxyx! - C.cbreak! - C.echo(false) - C.nl(false) - C.curs_set(0) - C.start_color! - C.use_default_colors! - stdscr\clear! stdscr\refresh! - stdscr\keypad(true) - - export REGULAR, INVERTED, HIGHLIGHTED, RED - _, 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 stack_names = {} stack_locations = {} @@ -162,7 +121,7 @@ run_debugger = (err_msg)-> for i=stack_min,stack_max info = debug.getinfo(i) if not info then break - table.insert(stack_names, info.name or "???") + table.insert(stack_names, info.name or "") filename = info.short_src..":"..info.currentline table.insert(stack_locations, filename) max_filename = math.max(max_filename, #filename) @@ -170,8 +129,6 @@ run_debugger = (err_msg)-> for i=1,#stack_names do callstack[i] = stack_locations[i]..(" ")\rep(max_filename-#stack_locations[i]).." | "..stack_names[i].." " - err_pad = Pad(0,0,AUTO,SCREEN_W) - err_pad._pad\attrset(RED) err_msg_lines = {} for line in err_msg\gmatch("[^\n]*") buff = "" @@ -182,80 +139,107 @@ run_debugger = (err_msg)-> else buff = buff .. word table.insert(err_msg_lines, " "..buff) - err_pad\set_lines(err_msg_lines, setmetatable({}, __index:->RED)) + err_pad = Pad(0,0,AUTO,SCREEN_W, err_msg_lines,setmetatable({}, __index:->RED)) + err_pad._pad\attrset(RED) - stack_pad = Pad(err_pad.height,0,AUTO,50) - stack_pad\set_lines(callstack) - var_names = Pad(err_pad.height,stack_pad.x+stack_pad.width,10,AUTO) - var_values = Pad(err_pad.height,var_names.x+var_names.width,10,AUTO) + stack_pad = Pad(err_pad.height,0,AUTO,AUTO, callstack) + stack_pad\select(stack_index) - stack_pad.on_resize = => - var_names\erase! - var_names.x = self.x+self.width - var_names\refresh! - var_names\on_resize(var_names.height, var_names.width) - - var_names.on_resize = => - var_values\erase! - var_values.x = self.x+self.width - var_values.width = SCREEN_W - (self.x+self.width) - var_values\refresh! - - stack_pad.on_select = (i)=> - var_names\clear! - var_values\clear! - callstack_min, _ = callstack_range! - _var_names, _var_values = {}, {} - for loc=1,999 - name, value = debug.getlocal(callstack_min+i-1, loc) - if value == nil then break - table.insert(_var_names, tostring(name)) - if type(value) == 'function' - info = debug.getinfo(value, 'nS') - --var_values\add_line(("function: %s @ %s:%s")\format(info.name or '???', info.short_src, info.linedefined)) - table.insert(_var_values, repr(info)) - else - table.insert(_var_values, repr(value)) - var_names\set_lines(_var_names) - var_values\set_lines(_var_values) + callstack_min, _ = callstack_range! + _var_names, _var_values = {}, {} + for loc=1,999 + name, value = debug.getlocal(callstack_min+stack_index-1, loc) + if value == nil then break + table.insert(_var_names, tostring(name)) + if type(value) == 'function' + info = debug.getinfo(value, 'nS') + --var_values\add_line(("function: %s @ %s:%s")\format(info.name or '???', info.short_src, info.linedefined)) + table.insert(_var_values, repr(info)) + else + table.insert(_var_values, repr(value)) - stack_pad\select(initial_index) + 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) + if var_index and #_var_names > 0 + var_names\select(var_index) + var_values\select(var_index) while true C.doupdate! c = stdscr\getch! - old_index = index - if ({[C.KEY_DOWN]:1, [C.KEY_SF]:1, [("j")\byte!]:1})[c] - stack_pad\scroll(1) - elseif ({[C.KEY_UP]:1, [C.KEY_SR]:1, [("k")\byte!]:1})[c] - stack_pad\scroll(-1) - elseif c == ('n')\byte! - var_names.offset = var_names.offset + 1 - var_names\refresh! - --var_names\scroll(1) - elseif c == ('m')\byte! - var_names.offset = var_names.offset - 1 - var_names\refresh! - --var_names\scroll(-1) - elseif c == ('J')\byte! - stack_pad\scroll(10) - elseif c == ('K')\byte! - stack_pad\scroll(-10) - elseif c == ('o')\byte! - file = stack_locations[stack_pad.selected] - filename,line_no = file\match("([^:]*):(.*)") - -- Launch system editor and then redraw everything - C.endwin! - os.execute((os.getenv("EDITOR") or "nano").." +"..line_no.." "..filename) - initial_index = stack_pad.selected - -- TODO: improve this - return run_debugger(err_msg) + 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) + else + stack_pad\scroll(1) + return main_loop(err_msg,stack_pad.selected,nil) - if c == ('q')\byte! or c == ("Q")\byte! - break + 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) + else + stack_pad\scroll(-1) + return main_loop(err_msg,stack_pad.selected,nil) + + when ('J')\byte! + if var_index + var_names\scroll(10) + return main_loop(err_msg,stack_pad.selected,var_names.selected) + else + stack_pad\scroll(10) + return main_loop(err_msg,stack_pad.selected,nil) + + when ('K')\byte! + if var_index + var_names\scroll(-10) + return main_loop(err_msg,stack_pad.selected,var_names.selected) + else + stack_pad\scroll(-10) + return main_loop(err_msg,stack_pad.selected,nil) + + when C.KEY_RIGHT, ("l")\byte! + if var_index == nil + return main_loop(err_msg,stack_pad.selected,1) + + when C.KEY_LEFT, ("h")\byte! + if var_index != nil + return main_loop(err_msg,stack_pad.selected,nil) + + when ('o')\byte! + file = stack_locations[stack_pad.selected] + filename,line_no = file\match("([^:]*):(.*)") + -- Launch system editor and then redraw everything + C.endwin! + os.execute((os.getenv("EDITOR") or "nano").." +"..line_no.." "..filename) + initial_index = stack_pad.selected + return main_loop(err_msg,stack_pad.selected,var_index) + + when ('q')\byte!, ("Q")\byte! + break + +run_debugger = (err_msg)-> + export stdscr, SCREEN_H, SCREEN_W + stdscr = C.initscr! + SCREEN_H, SCREEN_W = stdscr\getmaxyx! + + C.cbreak! + C.echo(false) + C.nl(false) + C.curs_set(0) + C.start_color! + C.use_default_colors! + + export REGULAR, INVERTED, HIGHLIGHTED, RED + _, 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 + + return main_loop(err_msg) - C.endwin! - return cursed = (fn, ...)-> -- To display Lua errors, we must close curses to return to