From c740c500a1e314288534869c2deba6c023dc00a8 Mon Sep 17 00:00:00 2001 From: Adam Mesha Date: Tue, 23 Aug 2016 18:09:55 +0300 Subject: [PATCH 1/5] Enable j/k navigation in the RHS sidebar panels --- pudb/debugger.py | 848 ++++++++++++++++++++++++----------------------- 1 file changed, 429 insertions(+), 419 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index 7fa29d63..f9d72d01 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -748,457 +748,132 @@ def change_rhs_box(name, index, direction, w, size, key): self.rhs_col.item_types[index] = "weight", weight self.rhs_col._invalidate() - # {{{ variables listeners - - def change_var_state(w, size, key): - var, pos = self.var_list._w.get_focus() - - iinfo = self.get_frame_var_info(read_only=False) \ - .get_inspect_info(var.id_path, read_only=False) - - if key == "\\": - iinfo.show_detail = not iinfo.show_detail - elif key == "t": - iinfo.display_type = "type" - elif key == "r": - iinfo.display_type = "repr" - elif key == "s": - iinfo.display_type = "str" - elif key == "c": - iinfo.display_type = CONFIG["custom_stringifier"] - elif key == "h": - iinfo.highlighted = not iinfo.highlighted - elif key == "@": - iinfo.repeated_at_top = not iinfo.repeated_at_top - elif key == "*": - levels = ["public", "private", "all", "public"] - iinfo.access_level = levels[levels.index(iinfo.access_level)+1] - elif key == "w": - iinfo.wrap = not iinfo.wrap - elif key == "m": - iinfo.show_methods = not iinfo.show_methods - - self.update_var_view() - - def edit_inspector_detail(w, size, key): - var, pos = self.var_list._w.get_focus() - - if var is None: - return - - fvi = self.get_frame_var_info(read_only=False) - iinfo = fvi.get_inspect_info(var.id_path, read_only=False) - - buttons = [ - ("OK", True), - ("Cancel", False), - ] - - if var.watch_expr is not None: - watch_edit = urwid.Edit([ - ("label", "Watch expression: ") - ], var.watch_expr.expression) - id_segment = [urwid.AttrMap(watch_edit, "value"), urwid.Text("")] + # {{{ listener handler functions - buttons.extend([None, ("Delete", "del")]) + def end(): + self.debugger.save_breakpoints() + self.quit_event_loop = True - title = "Watch Expression Options" + def next(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") else: - id_segment = [ - labelled_value("Identifier Path: ", var.id_path), - urwid.Text(""), - ] + self.debugger.set_next(self.debugger.curframe) + end() - title = "Variable Inspection Options" + def step(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_step() + end() - rb_grp_show = [] - rb_show_type = urwid.RadioButton(rb_grp_show, "Show Type", - iinfo.display_type == "type") - rb_show_repr = urwid.RadioButton(rb_grp_show, "Show repr()", - iinfo.display_type == "repr") - rb_show_str = urwid.RadioButton(rb_grp_show, "Show str()", - iinfo.display_type == "str") - rb_show_custom = urwid.RadioButton( - rb_grp_show, "Show custom (set in prefs)", - iinfo.display_type == CONFIG["custom_stringifier"]) + def finish(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_return(self.debugger.curframe) + end() - rb_grp_access = [] - rb_access_public = urwid.RadioButton(rb_grp_access, "Public members", - iinfo.access_level == "public") - rb_access_private = urwid.RadioButton( - rb_grp_access, "Public and private members", - iinfo.access_level == "private") - rb_access_all = urwid.RadioButton( - rb_grp_access, "All members (including __dunder__)", - iinfo.access_level == "all") + def cont(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_continue() + end() - wrap_checkbox = urwid.CheckBox("Line Wrap", iinfo.wrap) - expanded_checkbox = urwid.CheckBox("Expanded", iinfo.show_detail) - highlighted_checkbox = urwid.CheckBox("Highlighted", iinfo.highlighted) - repeated_at_top_checkbox = urwid.CheckBox( - "Repeated at top", iinfo.repeated_at_top) - show_methods_checkbox = urwid.CheckBox( - "Show methods", iinfo.show_methods) + def run_to_cursor(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + sline, pos = self.source.get_focus() + lineno = pos+1 - lb = urwid.ListBox(urwid.SimpleListWalker( - id_segment + - rb_grp_show + [urwid.Text("")] + - rb_grp_access + [urwid.Text("")] + - [ - wrap_checkbox, - expanded_checkbox, - highlighted_checkbox, - repeated_at_top_checkbox, - show_methods_checkbox, - ])) + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() - result = self.dialog(lb, buttons, title=title) + if bp_source_identifier is None: + self.message( + "Cannot currently set a breakpoint here--" + "source code does not correspond to a file location. " + "(perhaps this is generated code)") - if result is True: - iinfo.show_detail = expanded_checkbox.get_state() - iinfo.wrap = wrap_checkbox.get_state() - iinfo.highlighted = highlighted_checkbox.get_state() - iinfo.repeated_at_top = repeated_at_top_checkbox.get_state() - iinfo.show_methods = show_methods_checkbox.get_state() + from pudb.lowlevel import get_breakpoint_invalid_reason + invalid_reason = get_breakpoint_invalid_reason( + bp_source_identifier, lineno) - if rb_show_type.get_state(): - iinfo.display_type = "type" - elif rb_show_repr.get_state(): - iinfo.display_type = "repr" - elif rb_show_str.get_state(): - iinfo.display_type = "str" - elif rb_show_custom.get_state(): - iinfo.display_type = CONFIG["custom_stringifier"] + if invalid_reason is not None: + self.message( + "Cannot run to the line you indicated, " + "for the following reason:\n\n" + + invalid_reason) + else: + err = self.debugger.set_break( + bp_source_identifier, pos+1, temporary=True) + if err: + self.message("Error dealing with breakpoint:\n" + err) - if rb_access_public.get_state(): - iinfo.access_level = "public" - elif rb_access_private.get_state(): - iinfo.access_level = "private" - elif rb_access_all.get_state(): - iinfo.access_level = "all" + self.debugger.set_continue() + end() - if var.watch_expr is not None: - var.watch_expr.expression = watch_edit.get_edit_text() + def move_home(w, size, key): + self.source.set_focus(0) - elif result == "del": - for i, watch_expr in enumerate(fvi.watches): - if watch_expr is var.watch_expr: - del fvi.watches[i] + def move_end(w, size, key): + self.source.set_focus(len(self.source)-1) - self.update_var_view() + def go_to_line(w, size, key): + _, line = self.source.get_focus() - def insert_watch(w, size, key): - watch_edit = urwid.Edit([ - ("label", "Watch expression: ") - ]) + lineno_edit = urwid.IntEdit([ + ("label", "Line number: ") + ], line+1) if self.dialog( urwid.ListBox(urwid.SimpleListWalker([ - urwid.AttrMap(watch_edit, "value") + labelled_value("File :", + self.source_code_provider.identifier()), + urwid.AttrMap(lineno_edit, "value") ])), [ ("OK", True), ("Cancel", False), - ], title="Add Watch Expression"): + ], title="Go to Line Number"): + lineno = min(max(0, int(lineno_edit.value())-1), len(self.source)-1) + self.source.set_focus(lineno) - from pudb.var_view import WatchExpression - we = WatchExpression(watch_edit.get_edit_text()) - fvi = self.get_frame_var_info(read_only=False) - fvi.watches.append(we) - self.update_var_view() + def move_down(w, size, key): + w.keypress(size, "down") - self.var_list.listen("\\", change_var_state) - self.var_list.listen("t", change_var_state) - self.var_list.listen("r", change_var_state) - self.var_list.listen("s", change_var_state) - self.var_list.listen("c", change_var_state) - self.var_list.listen("h", change_var_state) - self.var_list.listen("@", change_var_state) - self.var_list.listen("*", change_var_state) - self.var_list.listen("w", change_var_state) - self.var_list.listen("m", change_var_state) - self.var_list.listen("enter", edit_inspector_detail) - self.var_list.listen("n", insert_watch) - self.var_list.listen("insert", insert_watch) + def move_up(w, size, key): + w.keypress(size, "up") - self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) - self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) + def page_down(w, size, key): + w.keypress(size, "page down") - # }}} + def page_up(w, size, key): + w.keypress(size, "page up") - # {{{ stack listeners - def examine_frame(w, size, key): - _, pos = self.stack_list._w.get_focus() - self.debugger.set_frame_index(self.translate_ui_stack_index(pos)) + def scroll_left(w, size, key): + self.source_hscroll_start = max( + 0, + self.source_hscroll_start - 4) + for sl in self.source: + sl._invalidate() - self.stack_list.listen("enter", examine_frame) + def scroll_right(w, size, key): + self.source_hscroll_start += 4 + for sl in self.source: + sl._invalidate() - def move_stack_top(w, size, key): - self.debugger.set_frame_index(len(self.debugger.stack)-1) + def search(w, size, key): + self.search_controller.open_search_ui() - def move_stack_up(w, size, key): - self.debugger.move_up_frame() + def search_next(w, size, key): + self.search_controller.perform_search(dir=1, update_search_start=True) - def move_stack_down(w, size, key): - self.debugger.move_down_frame() - - self.stack_list.listen("H", move_stack_top) - self.stack_list.listen("u", move_stack_up) - self.stack_list.listen("d", move_stack_down) - - self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) - self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) - - # }}} - - # {{{ breakpoint listeners - def save_breakpoints(w, size, key): - self.debugger.save_breakpoints() - - def delete_breakpoint(w, size, key): - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() - - if bp_source_identifier is None: - self.message( - "Cannot currently delete a breakpoint here--" - "source code does not correspond to a file location. " - "(perhaps this is generated code)") - - bp_list = self._get_bp_list() - if bp_list: - _, pos = self.bp_list._w.get_focus() - bp = bp_list[pos] - if bp_source_identifier == bp.file and bp.line-1 < len(self.source): - self.source[bp.line-1].set_breakpoint(False) - - err = self.debugger.clear_break(bp.file, bp.line) - if err: - self.message("Error clearing breakpoint:\n" + err) - else: - self.update_breakpoints() - - def enable_disable_breakpoint(w, size, key): - bp_entry, pos = self.bp_list._w.get_focus() - - if bp_entry is None: - return - - bp = self._get_bp_list()[pos] - bp.enabled = not bp.enabled - - sline = self.source[bp.line-1] - sline.set_breakpoint(bp.enabled) - - self.update_breakpoints() - - def examine_breakpoint(w, size, key): - bp_entry, pos = self.bp_list._w.get_focus() - - if bp_entry is None: - return - - bp = self._get_bp_list()[pos] - - if bp.cond is None: - cond = "" - else: - cond = str(bp.cond) - - enabled_checkbox = urwid.CheckBox( - "Enabled", bp.enabled) - cond_edit = urwid.Edit([ - ("label", "Condition: ") - ], cond) - ign_count_edit = urwid.IntEdit([ - ("label", "Ignore the next N times: ") - ], bp.ignore) - - lb = urwid.ListBox(urwid.SimpleListWalker([ - labelled_value("File: ", bp.file), - labelled_value("Line: ", bp.line), - labelled_value("Hits: ", bp.hits), - urwid.Text(""), - enabled_checkbox, - urwid.AttrMap(cond_edit, "value", "value"), - urwid.AttrMap(ign_count_edit, "value", "value"), - ])) - - result = self.dialog(lb, [ - ("OK", True), - ("Cancel", False), - None, - ("Delete", "del"), - ("Location", "loc"), - ], title="Edit Breakpoint") - - if result is True: - bp.enabled = enabled_checkbox.get_state() - bp.ignore = int(ign_count_edit.value()) - cond = cond_edit.get_edit_text() - if cond: - bp.cond = cond - else: - bp.cond = None - elif result == "loc": - self.show_line(bp.line, - FileSourceCodeProvider(self.debugger, bp.file)) - self.columns.set_focus(0) - elif result == "del": - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() - - if bp_source_identifier is None: - self.message( - "Cannot currently delete a breakpoint here--" - "source code does not correspond to a file location. " - "(perhaps this is generated code)") - - if bp_source_identifier == bp.file: - self.source[bp.line-1].set_breakpoint(False) - - err = self.debugger.clear_break(bp.file, bp.line) - if err: - self.message("Error clearing breakpoint:\n" + err) - else: - self.update_breakpoints() - - self.bp_list.listen("enter", examine_breakpoint) - self.bp_list.listen("d", delete_breakpoint) - self.bp_list.listen("s", save_breakpoints) - self.bp_list.listen("e", enable_disable_breakpoint) - - self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) - self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) - - # }}} - - # {{{ source listeners - - def end(): - self.debugger.save_breakpoints() - self.quit_event_loop = True - - def next(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_next(self.debugger.curframe) - end() - - def step(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_step() - end() - - def finish(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_return(self.debugger.curframe) - end() - - def cont(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_continue() - end() - - def run_to_cursor(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - sline, pos = self.source.get_focus() - lineno = pos+1 - - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() - - if bp_source_identifier is None: - self.message( - "Cannot currently set a breakpoint here--" - "source code does not correspond to a file location. " - "(perhaps this is generated code)") - - from pudb.lowlevel import get_breakpoint_invalid_reason - invalid_reason = get_breakpoint_invalid_reason( - bp_source_identifier, lineno) - - if invalid_reason is not None: - self.message( - "Cannot run to the line you indicated, " - "for the following reason:\n\n" - + invalid_reason) - else: - err = self.debugger.set_break( - bp_source_identifier, pos+1, temporary=True) - if err: - self.message("Error dealing with breakpoint:\n" + err) - - self.debugger.set_continue() - end() - - def move_home(w, size, key): - self.source.set_focus(0) - - def move_end(w, size, key): - self.source.set_focus(len(self.source)-1) - - def go_to_line(w, size, key): - _, line = self.source.get_focus() - - lineno_edit = urwid.IntEdit([ - ("label", "Line number: ") - ], line+1) - - if self.dialog( - urwid.ListBox(urwid.SimpleListWalker([ - labelled_value("File :", - self.source_code_provider.identifier()), - urwid.AttrMap(lineno_edit, "value") - ])), - [ - ("OK", True), - ("Cancel", False), - ], title="Go to Line Number"): - lineno = min(max(0, int(lineno_edit.value())-1), len(self.source)-1) - self.source.set_focus(lineno) - - def move_down(w, size, key): - w.keypress(size, "down") - - def move_up(w, size, key): - w.keypress(size, "up") - - def page_down(w, size, key): - w.keypress(size, "page down") - - def page_up(w, size, key): - w.keypress(size, "page up") - - def scroll_left(w, size, key): - self.source_hscroll_start = max( - 0, - self.source_hscroll_start - 4) - for sl in self.source: - sl._invalidate() - - def scroll_right(w, size, key): - self.source_hscroll_start += 4 - for sl in self.source: - sl._invalidate() - - def search(w, size, key): - self.search_controller.open_search_ui() - - def search_next(w, size, key): - self.search_controller.perform_search(dir=1, update_search_start=True) - - def search_previous(w, size, key): - self.search_controller.perform_search(dir=-1, update_search_start=True) + def search_previous(w, size, key): + self.search_controller.perform_search(dir=-1, update_search_start=True) def toggle_breakpoint(w, size, key): bp_source_identifier = \ @@ -1392,6 +1067,341 @@ def keypress(self, size, key): self.debugger.set_frame_index( self.translate_ui_stack_index(pos)) + # }}} + + # {{{ variables listeners + + def change_var_state(w, size, key): + var, pos = self.var_list._w.get_focus() + + iinfo = self.get_frame_var_info(read_only=False) \ + .get_inspect_info(var.id_path, read_only=False) + + if key == "\\": + iinfo.show_detail = not iinfo.show_detail + elif key == "t": + iinfo.display_type = "type" + elif key == "r": + iinfo.display_type = "repr" + elif key == "s": + iinfo.display_type = "str" + elif key == "c": + iinfo.display_type = CONFIG["custom_stringifier"] + elif key == "h": + iinfo.highlighted = not iinfo.highlighted + elif key == "@": + iinfo.repeated_at_top = not iinfo.repeated_at_top + elif key == "*": + levels = ["public", "private", "all", "public"] + iinfo.access_level = levels[levels.index(iinfo.access_level)+1] + elif key == "w": + iinfo.wrap = not iinfo.wrap + elif key == "m": + iinfo.show_methods = not iinfo.show_methods + + self.update_var_view() + + def edit_inspector_detail(w, size, key): + var, pos = self.var_list._w.get_focus() + + if var is None: + return + + fvi = self.get_frame_var_info(read_only=False) + iinfo = fvi.get_inspect_info(var.id_path, read_only=False) + + buttons = [ + ("OK", True), + ("Cancel", False), + ] + + if var.watch_expr is not None: + watch_edit = urwid.Edit([ + ("label", "Watch expression: ") + ], var.watch_expr.expression) + id_segment = [urwid.AttrMap(watch_edit, "value"), urwid.Text("")] + + buttons.extend([None, ("Delete", "del")]) + + title = "Watch Expression Options" + else: + id_segment = [ + labelled_value("Identifier Path: ", var.id_path), + urwid.Text(""), + ] + + title = "Variable Inspection Options" + + rb_grp_show = [] + rb_show_type = urwid.RadioButton(rb_grp_show, "Show Type", + iinfo.display_type == "type") + rb_show_repr = urwid.RadioButton(rb_grp_show, "Show repr()", + iinfo.display_type == "repr") + rb_show_str = urwid.RadioButton(rb_grp_show, "Show str()", + iinfo.display_type == "str") + rb_show_custom = urwid.RadioButton( + rb_grp_show, "Show custom (set in prefs)", + iinfo.display_type == CONFIG["custom_stringifier"]) + + rb_grp_access = [] + rb_access_public = urwid.RadioButton(rb_grp_access, "Public members", + iinfo.access_level == "public") + rb_access_private = urwid.RadioButton( + rb_grp_access, "Public and private members", + iinfo.access_level == "private") + rb_access_all = urwid.RadioButton( + rb_grp_access, "All members (including __dunder__)", + iinfo.access_level == "all") + + wrap_checkbox = urwid.CheckBox("Line Wrap", iinfo.wrap) + expanded_checkbox = urwid.CheckBox("Expanded", iinfo.show_detail) + highlighted_checkbox = urwid.CheckBox("Highlighted", iinfo.highlighted) + repeated_at_top_checkbox = urwid.CheckBox( + "Repeated at top", iinfo.repeated_at_top) + show_methods_checkbox = urwid.CheckBox( + "Show methods", iinfo.show_methods) + + lb = urwid.ListBox(urwid.SimpleListWalker( + id_segment + + rb_grp_show + [urwid.Text("")] + + rb_grp_access + [urwid.Text("")] + + [ + wrap_checkbox, + expanded_checkbox, + highlighted_checkbox, + repeated_at_top_checkbox, + show_methods_checkbox, + ])) + + result = self.dialog(lb, buttons, title=title) + + if result is True: + iinfo.show_detail = expanded_checkbox.get_state() + iinfo.wrap = wrap_checkbox.get_state() + iinfo.highlighted = highlighted_checkbox.get_state() + iinfo.repeated_at_top = repeated_at_top_checkbox.get_state() + iinfo.show_methods = show_methods_checkbox.get_state() + + if rb_show_type.get_state(): + iinfo.display_type = "type" + elif rb_show_repr.get_state(): + iinfo.display_type = "repr" + elif rb_show_str.get_state(): + iinfo.display_type = "str" + elif rb_show_custom.get_state(): + iinfo.display_type = CONFIG["custom_stringifier"] + + if rb_access_public.get_state(): + iinfo.access_level = "public" + elif rb_access_private.get_state(): + iinfo.access_level = "private" + elif rb_access_all.get_state(): + iinfo.access_level = "all" + + if var.watch_expr is not None: + var.watch_expr.expression = watch_edit.get_edit_text() + + elif result == "del": + for i, watch_expr in enumerate(fvi.watches): + if watch_expr is var.watch_expr: + del fvi.watches[i] + + self.update_var_view() + + def insert_watch(w, size, key): + watch_edit = urwid.Edit([ + ("label", "Watch expression: ") + ]) + + if self.dialog( + urwid.ListBox(urwid.SimpleListWalker([ + urwid.AttrMap(watch_edit, "value") + ])), + [ + ("OK", True), + ("Cancel", False), + ], title="Add Watch Expression"): + + from pudb.var_view import WatchExpression + we = WatchExpression(watch_edit.get_edit_text()) + fvi = self.get_frame_var_info(read_only=False) + fvi.watches.append(we) + self.update_var_view() + + self.var_list.listen("\\", change_var_state) + self.var_list.listen("t", change_var_state) + self.var_list.listen("r", change_var_state) + self.var_list.listen("s", change_var_state) + self.var_list.listen("c", change_var_state) + self.var_list.listen("h", change_var_state) + self.var_list.listen("@", change_var_state) + self.var_list.listen("*", change_var_state) + self.var_list.listen("w", change_var_state) + self.var_list.listen("m", change_var_state) + self.var_list.listen("enter", edit_inspector_detail) + self.var_list.listen("n", insert_watch) + self.var_list.listen("insert", insert_watch) + self.var_list.listen("j", move_down) + self.var_list.listen("k", move_up) + + self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) + self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) + + # }}} + + # {{{ stack listeners + def examine_frame(w, size, key): + _, pos = self.stack_list._w.get_focus() + self.debugger.set_frame_index(self.translate_ui_stack_index(pos)) + + self.stack_list.listen("enter", examine_frame) + + def move_stack_top(w, size, key): + self.debugger.set_frame_index(len(self.debugger.stack)-1) + + def move_stack_up(w, size, key): + self.debugger.move_up_frame() + + def move_stack_down(w, size, key): + self.debugger.move_down_frame() + + self.stack_list.listen("H", move_stack_top) + self.stack_list.listen("u", move_stack_up) + self.stack_list.listen("d", move_stack_down) + self.stack_list.listen("j", move_down) + self.stack_list.listen("k", move_up) + + self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) + self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) + + # }}} + + # {{{ breakpoint listeners + def save_breakpoints(w, size, key): + self.debugger.save_breakpoints() + + def delete_breakpoint(w, size, key): + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() + + if bp_source_identifier is None: + self.message( + "Cannot currently delete a breakpoint here--" + "source code does not correspond to a file location. " + "(perhaps this is generated code)") + + bp_list = self._get_bp_list() + if bp_list: + _, pos = self.bp_list._w.get_focus() + bp = bp_list[pos] + if bp_source_identifier == bp.file and bp.line-1 < len(self.source): + self.source[bp.line-1].set_breakpoint(False) + + err = self.debugger.clear_break(bp.file, bp.line) + if err: + self.message("Error clearing breakpoint:\n" + err) + else: + self.update_breakpoints() + + def enable_disable_breakpoint(w, size, key): + bp_entry, pos = self.bp_list._w.get_focus() + + if bp_entry is None: + return + + bp = self._get_bp_list()[pos] + bp.enabled = not bp.enabled + + sline = self.source[bp.line-1] + sline.set_breakpoint(bp.enabled) + + self.update_breakpoints() + + def examine_breakpoint(w, size, key): + bp_entry, pos = self.bp_list._w.get_focus() + + if bp_entry is None: + return + + bp = self._get_bp_list()[pos] + + if bp.cond is None: + cond = "" + else: + cond = str(bp.cond) + + enabled_checkbox = urwid.CheckBox( + "Enabled", bp.enabled) + cond_edit = urwid.Edit([ + ("label", "Condition: ") + ], cond) + ign_count_edit = urwid.IntEdit([ + ("label", "Ignore the next N times: ") + ], bp.ignore) + + lb = urwid.ListBox(urwid.SimpleListWalker([ + labelled_value("File: ", bp.file), + labelled_value("Line: ", bp.line), + labelled_value("Hits: ", bp.hits), + urwid.Text(""), + enabled_checkbox, + urwid.AttrMap(cond_edit, "value", "value"), + urwid.AttrMap(ign_count_edit, "value", "value"), + ])) + + result = self.dialog(lb, [ + ("OK", True), + ("Cancel", False), + None, + ("Delete", "del"), + ("Location", "loc"), + ], title="Edit Breakpoint") + + if result is True: + bp.enabled = enabled_checkbox.get_state() + bp.ignore = int(ign_count_edit.value()) + cond = cond_edit.get_edit_text() + if cond: + bp.cond = cond + else: + bp.cond = None + elif result == "loc": + self.show_line(bp.line, + FileSourceCodeProvider(self.debugger, bp.file)) + self.columns.set_focus(0) + elif result == "del": + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() + + if bp_source_identifier is None: + self.message( + "Cannot currently delete a breakpoint here--" + "source code does not correspond to a file location. " + "(perhaps this is generated code)") + + if bp_source_identifier == bp.file: + self.source[bp.line-1].set_breakpoint(False) + + err = self.debugger.clear_break(bp.file, bp.line) + if err: + self.message("Error clearing breakpoint:\n" + err) + else: + self.update_breakpoints() + + self.bp_list.listen("enter", examine_breakpoint) + self.bp_list.listen("d", delete_breakpoint) + self.bp_list.listen("s", save_breakpoints) + self.bp_list.listen("e", enable_disable_breakpoint) + self.bp_list.listen("j", move_down) + self.bp_list.listen("k", move_up) + + self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) + self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) + + # }}} + + # {{{ source listeners + self.source_sigwrap.listen("n", next) self.source_sigwrap.listen("s", step) self.source_sigwrap.listen("f", finish) From 90640914d4a9653599ae80b26d79b5b55799c299 Mon Sep 17 00:00:00 2001 From: Adam Mesha Date: Thu, 25 Aug 2016 13:46:31 +0300 Subject: [PATCH 2/5] Revert "Enable j/k navigation in the RHS sidebar panels" This reverts commit c740c500a1e314288534869c2deba6c023dc00a8. --- pudb/debugger.py | 1042 +++++++++++++++++++++++----------------------- 1 file changed, 516 insertions(+), 526 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index f9d72d01..7fa29d63 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -748,659 +748,649 @@ def change_rhs_box(name, index, direction, w, size, key): self.rhs_col.item_types[index] = "weight", weight self.rhs_col._invalidate() - # {{{ listener handler functions + # {{{ variables listeners - def end(): - self.debugger.save_breakpoints() - self.quit_event_loop = True + def change_var_state(w, size, key): + var, pos = self.var_list._w.get_focus() - def next(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_next(self.debugger.curframe) - end() + iinfo = self.get_frame_var_info(read_only=False) \ + .get_inspect_info(var.id_path, read_only=False) - def step(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_step() - end() + if key == "\\": + iinfo.show_detail = not iinfo.show_detail + elif key == "t": + iinfo.display_type = "type" + elif key == "r": + iinfo.display_type = "repr" + elif key == "s": + iinfo.display_type = "str" + elif key == "c": + iinfo.display_type = CONFIG["custom_stringifier"] + elif key == "h": + iinfo.highlighted = not iinfo.highlighted + elif key == "@": + iinfo.repeated_at_top = not iinfo.repeated_at_top + elif key == "*": + levels = ["public", "private", "all", "public"] + iinfo.access_level = levels[levels.index(iinfo.access_level)+1] + elif key == "w": + iinfo.wrap = not iinfo.wrap + elif key == "m": + iinfo.show_methods = not iinfo.show_methods - def finish(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_return(self.debugger.curframe) - end() + self.update_var_view() - def cont(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") - else: - self.debugger.set_continue() - end() + def edit_inspector_detail(w, size, key): + var, pos = self.var_list._w.get_focus() - def run_to_cursor(w, size, key): - if self.debugger.post_mortem: - self.message("Post-mortem mode: Can't modify state.") + if var is None: + return + + fvi = self.get_frame_var_info(read_only=False) + iinfo = fvi.get_inspect_info(var.id_path, read_only=False) + + buttons = [ + ("OK", True), + ("Cancel", False), + ] + + if var.watch_expr is not None: + watch_edit = urwid.Edit([ + ("label", "Watch expression: ") + ], var.watch_expr.expression) + id_segment = [urwid.AttrMap(watch_edit, "value"), urwid.Text("")] + + buttons.extend([None, ("Delete", "del")]) + + title = "Watch Expression Options" else: - sline, pos = self.source.get_focus() - lineno = pos+1 + id_segment = [ + labelled_value("Identifier Path: ", var.id_path), + urwid.Text(""), + ] - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() + title = "Variable Inspection Options" - if bp_source_identifier is None: - self.message( - "Cannot currently set a breakpoint here--" - "source code does not correspond to a file location. " - "(perhaps this is generated code)") + rb_grp_show = [] + rb_show_type = urwid.RadioButton(rb_grp_show, "Show Type", + iinfo.display_type == "type") + rb_show_repr = urwid.RadioButton(rb_grp_show, "Show repr()", + iinfo.display_type == "repr") + rb_show_str = urwid.RadioButton(rb_grp_show, "Show str()", + iinfo.display_type == "str") + rb_show_custom = urwid.RadioButton( + rb_grp_show, "Show custom (set in prefs)", + iinfo.display_type == CONFIG["custom_stringifier"]) - from pudb.lowlevel import get_breakpoint_invalid_reason - invalid_reason = get_breakpoint_invalid_reason( - bp_source_identifier, lineno) + rb_grp_access = [] + rb_access_public = urwid.RadioButton(rb_grp_access, "Public members", + iinfo.access_level == "public") + rb_access_private = urwid.RadioButton( + rb_grp_access, "Public and private members", + iinfo.access_level == "private") + rb_access_all = urwid.RadioButton( + rb_grp_access, "All members (including __dunder__)", + iinfo.access_level == "all") - if invalid_reason is not None: - self.message( - "Cannot run to the line you indicated, " - "for the following reason:\n\n" - + invalid_reason) - else: - err = self.debugger.set_break( - bp_source_identifier, pos+1, temporary=True) - if err: - self.message("Error dealing with breakpoint:\n" + err) + wrap_checkbox = urwid.CheckBox("Line Wrap", iinfo.wrap) + expanded_checkbox = urwid.CheckBox("Expanded", iinfo.show_detail) + highlighted_checkbox = urwid.CheckBox("Highlighted", iinfo.highlighted) + repeated_at_top_checkbox = urwid.CheckBox( + "Repeated at top", iinfo.repeated_at_top) + show_methods_checkbox = urwid.CheckBox( + "Show methods", iinfo.show_methods) - self.debugger.set_continue() - end() + lb = urwid.ListBox(urwid.SimpleListWalker( + id_segment + + rb_grp_show + [urwid.Text("")] + + rb_grp_access + [urwid.Text("")] + + [ + wrap_checkbox, + expanded_checkbox, + highlighted_checkbox, + repeated_at_top_checkbox, + show_methods_checkbox, + ])) - def move_home(w, size, key): - self.source.set_focus(0) + result = self.dialog(lb, buttons, title=title) - def move_end(w, size, key): - self.source.set_focus(len(self.source)-1) + if result is True: + iinfo.show_detail = expanded_checkbox.get_state() + iinfo.wrap = wrap_checkbox.get_state() + iinfo.highlighted = highlighted_checkbox.get_state() + iinfo.repeated_at_top = repeated_at_top_checkbox.get_state() + iinfo.show_methods = show_methods_checkbox.get_state() - def go_to_line(w, size, key): - _, line = self.source.get_focus() + if rb_show_type.get_state(): + iinfo.display_type = "type" + elif rb_show_repr.get_state(): + iinfo.display_type = "repr" + elif rb_show_str.get_state(): + iinfo.display_type = "str" + elif rb_show_custom.get_state(): + iinfo.display_type = CONFIG["custom_stringifier"] - lineno_edit = urwid.IntEdit([ - ("label", "Line number: ") - ], line+1) + if rb_access_public.get_state(): + iinfo.access_level = "public" + elif rb_access_private.get_state(): + iinfo.access_level = "private" + elif rb_access_all.get_state(): + iinfo.access_level = "all" + + if var.watch_expr is not None: + var.watch_expr.expression = watch_edit.get_edit_text() + + elif result == "del": + for i, watch_expr in enumerate(fvi.watches): + if watch_expr is var.watch_expr: + del fvi.watches[i] + + self.update_var_view() + + def insert_watch(w, size, key): + watch_edit = urwid.Edit([ + ("label", "Watch expression: ") + ]) if self.dialog( urwid.ListBox(urwid.SimpleListWalker([ - labelled_value("File :", - self.source_code_provider.identifier()), - urwid.AttrMap(lineno_edit, "value") + urwid.AttrMap(watch_edit, "value") ])), [ ("OK", True), ("Cancel", False), - ], title="Go to Line Number"): - lineno = min(max(0, int(lineno_edit.value())-1), len(self.source)-1) - self.source.set_focus(lineno) + ], title="Add Watch Expression"): - def move_down(w, size, key): - w.keypress(size, "down") + from pudb.var_view import WatchExpression + we = WatchExpression(watch_edit.get_edit_text()) + fvi = self.get_frame_var_info(read_only=False) + fvi.watches.append(we) + self.update_var_view() - def move_up(w, size, key): - w.keypress(size, "up") + self.var_list.listen("\\", change_var_state) + self.var_list.listen("t", change_var_state) + self.var_list.listen("r", change_var_state) + self.var_list.listen("s", change_var_state) + self.var_list.listen("c", change_var_state) + self.var_list.listen("h", change_var_state) + self.var_list.listen("@", change_var_state) + self.var_list.listen("*", change_var_state) + self.var_list.listen("w", change_var_state) + self.var_list.listen("m", change_var_state) + self.var_list.listen("enter", edit_inspector_detail) + self.var_list.listen("n", insert_watch) + self.var_list.listen("insert", insert_watch) - def page_down(w, size, key): - w.keypress(size, "page down") + self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) + self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) - def page_up(w, size, key): - w.keypress(size, "page up") + # }}} - def scroll_left(w, size, key): - self.source_hscroll_start = max( - 0, - self.source_hscroll_start - 4) - for sl in self.source: - sl._invalidate() + # {{{ stack listeners + def examine_frame(w, size, key): + _, pos = self.stack_list._w.get_focus() + self.debugger.set_frame_index(self.translate_ui_stack_index(pos)) - def scroll_right(w, size, key): - self.source_hscroll_start += 4 - for sl in self.source: - sl._invalidate() + self.stack_list.listen("enter", examine_frame) - def search(w, size, key): - self.search_controller.open_search_ui() + def move_stack_top(w, size, key): + self.debugger.set_frame_index(len(self.debugger.stack)-1) - def search_next(w, size, key): - self.search_controller.perform_search(dir=1, update_search_start=True) + def move_stack_up(w, size, key): + self.debugger.move_up_frame() - def search_previous(w, size, key): - self.search_controller.perform_search(dir=-1, update_search_start=True) + def move_stack_down(w, size, key): + self.debugger.move_down_frame() - def toggle_breakpoint(w, size, key): - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() - - if bp_source_identifier: - sline, pos = self.source.get_focus() - lineno = pos+1 - - existing_breaks = self.debugger.get_breaks( - bp_source_identifier, lineno) - if existing_breaks: - err = None - for bp in existing_breaks: - if not bp.enabled: - bp.enable() - sline.set_breakpoint(True) - # Unsure about this. Are multiple breakpoints even - # possible? - break - else: - err = self.debugger.clear_break(bp_source_identifier, lineno) - sline.set_breakpoint(False) - else: - file_lineno = (bp_source_identifier, lineno) - if file_lineno in self.debugger.set_traces: - self.debugger.set_traces[file_lineno] = \ - not self.debugger.set_traces[file_lineno] - sline.set_breakpoint(self.debugger.set_traces[file_lineno]) - return + self.stack_list.listen("H", move_stack_top) + self.stack_list.listen("u", move_stack_up) + self.stack_list.listen("d", move_stack_down) - from pudb.lowlevel import get_breakpoint_invalid_reason - invalid_reason = get_breakpoint_invalid_reason( - bp_source_identifier, pos+1) + self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) + self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) - if invalid_reason is not None: - do_set = not self.dialog( - urwid.ListBox( - urwid.SimpleListWalker([ - urwid.Text( - "The breakpoint you just set may be " - "invalid, for the following reason:\n\n" - + invalid_reason), - ])), [ - ("Cancel", True), - ("Set Anyway", False), - ], - title="Possibly Invalid Breakpoint", - focus_buttons=True) - else: - do_set = True + # }}} - if do_set: - err = self.debugger.set_break(bp_source_identifier, pos+1) - sline.set_breakpoint(True) - else: - err = None + # {{{ breakpoint listeners + def save_breakpoints(w, size, key): + self.debugger.save_breakpoints() - if err: - self.message("Error dealing with breakpoint:\n" + err) + def delete_breakpoint(w, size, key): + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() - self.update_breakpoints() - else: + if bp_source_identifier is None: self.message( - "Cannot currently set a breakpoint here--" + "Cannot currently delete a breakpoint here--" "source code does not correspond to a file location. " "(perhaps this is generated code)") - def pick_module(w, size, key): - from os.path import splitext - - import sys - - def mod_exists(mod): - if not hasattr(mod, "__file__"): - return False - filename = mod.__file__ - - base, ext = splitext(filename) - ext = ext.lower() - - from os.path import exists + bp_list = self._get_bp_list() + if bp_list: + _, pos = self.bp_list._w.get_focus() + bp = bp_list[pos] + if bp_source_identifier == bp.file and bp.line-1 < len(self.source): + self.source[bp.line-1].set_breakpoint(False) - if ext == ".pyc": - return exists(base+".py") + err = self.debugger.clear_break(bp.file, bp.line) + if err: + self.message("Error clearing breakpoint:\n" + err) else: - return ext == ".py" - - new_mod_text = SelectableText("-- update me --") - new_mod_entry = urwid.AttrMap(new_mod_text, - None, "focused selectable") - - def build_filtered_mod_list(filt_string=""): - modules = sorted(name - # mod_exists may change the size of sys.modules, - # causing this to crash. Copy to a list. - for name, mod in list(sys.modules.items()) - if mod_exists(mod)) - - result = [urwid.AttrMap(SelectableText(mod), - None, "focused selectable") - for mod in modules if filt_string in mod] - new_mod_text.set_text("<<< IMPORT MODULE '%s' >>>" % filt_string) - result.append(new_mod_entry) - return result - - def show_mod(mod): - filename = self.debugger.canonic(mod.__file__) - - base, ext = splitext(filename) - if ext == ".pyc": - ext = ".py" - filename = base+".py" - - self.set_source_code_provider( - FileSourceCodeProvider(self.debugger, filename)) - self.source_list.set_focus(0) - - class FilterEdit(urwid.Edit): - def keypress(self, size, key): - result = urwid.Edit.keypress(self, size, key) - - if result is None: - mod_list[:] = build_filtered_mod_list( - self.get_edit_text()) - - return result - - filt_edit = FilterEdit([("label", "Filter: ")], - self.last_module_filter) - - mod_list = urwid.SimpleListWalker( - build_filtered_mod_list(filt_edit.get_edit_text())) - lb = urwid.ListBox(mod_list) - - w = urwid.Pile([ - ("flow", urwid.AttrMap(filt_edit, "value")), - ("fixed", 1, urwid.SolidFill()), - urwid.AttrMap(lb, "selectable")]) + self.update_breakpoints() - while True: - result = self.dialog(w, [ - ("OK", True), - ("Cancel", False), - ("Reload", "reload"), + def enable_disable_breakpoint(w, size, key): + bp_entry, pos = self.bp_list._w.get_focus() - ], title="Pick Module") - self.last_module_filter = filt_edit.get_edit_text() + if bp_entry is None: + return - if result is True: - widget, pos = lb.get_focus() - if widget is new_mod_entry: - new_mod_name = filt_edit.get_edit_text() - try: - __import__(str(new_mod_name)) - except: - from pudb.lowlevel import format_exception + bp = self._get_bp_list()[pos] + bp.enabled = not bp.enabled - self.message("Could not import module '%s':\n\n%s" % ( - new_mod_name, "".join( - format_exception(sys.exc_info()))), - title="Import Error") - else: - show_mod(__import__(str(new_mod_name))) - break - else: - show_mod(sys.modules[widget.base_widget.get_text()[0]]) - break - elif result is False: - break - elif result == "reload": - widget, pos = lb.get_focus() - if widget is not new_mod_entry: - mod_name = widget.base_widget.get_text()[0] - mod = sys.modules[mod_name] - if PY3: - reload(mod) # noqa (undef on Py3) - else: - import importlib - importlib.reload(mod) + sline = self.source[bp.line-1] + sline.set_breakpoint(bp.enabled) - self.message("'%s' was successfully reloaded." % mod_name) + self.update_breakpoints() - if self.source_code_provider is not None: - self.source_code_provider.clear_cache() + def examine_breakpoint(w, size, key): + bp_entry, pos = self.bp_list._w.get_focus() - self.set_source_code_provider(self.source_code_provider, - force_update=True) + if bp_entry is None: + return - _, pos = self.stack_list._w.get_focus() - self.debugger.set_frame_index( - self.translate_ui_stack_index(pos)) + bp = self._get_bp_list()[pos] - # }}} + if bp.cond is None: + cond = "" + else: + cond = str(bp.cond) - # {{{ variables listeners + enabled_checkbox = urwid.CheckBox( + "Enabled", bp.enabled) + cond_edit = urwid.Edit([ + ("label", "Condition: ") + ], cond) + ign_count_edit = urwid.IntEdit([ + ("label", "Ignore the next N times: ") + ], bp.ignore) - def change_var_state(w, size, key): - var, pos = self.var_list._w.get_focus() + lb = urwid.ListBox(urwid.SimpleListWalker([ + labelled_value("File: ", bp.file), + labelled_value("Line: ", bp.line), + labelled_value("Hits: ", bp.hits), + urwid.Text(""), + enabled_checkbox, + urwid.AttrMap(cond_edit, "value", "value"), + urwid.AttrMap(ign_count_edit, "value", "value"), + ])) - iinfo = self.get_frame_var_info(read_only=False) \ - .get_inspect_info(var.id_path, read_only=False) + result = self.dialog(lb, [ + ("OK", True), + ("Cancel", False), + None, + ("Delete", "del"), + ("Location", "loc"), + ], title="Edit Breakpoint") - if key == "\\": - iinfo.show_detail = not iinfo.show_detail - elif key == "t": - iinfo.display_type = "type" - elif key == "r": - iinfo.display_type = "repr" - elif key == "s": - iinfo.display_type = "str" - elif key == "c": - iinfo.display_type = CONFIG["custom_stringifier"] - elif key == "h": - iinfo.highlighted = not iinfo.highlighted - elif key == "@": - iinfo.repeated_at_top = not iinfo.repeated_at_top - elif key == "*": - levels = ["public", "private", "all", "public"] - iinfo.access_level = levels[levels.index(iinfo.access_level)+1] - elif key == "w": - iinfo.wrap = not iinfo.wrap - elif key == "m": - iinfo.show_methods = not iinfo.show_methods + if result is True: + bp.enabled = enabled_checkbox.get_state() + bp.ignore = int(ign_count_edit.value()) + cond = cond_edit.get_edit_text() + if cond: + bp.cond = cond + else: + bp.cond = None + elif result == "loc": + self.show_line(bp.line, + FileSourceCodeProvider(self.debugger, bp.file)) + self.columns.set_focus(0) + elif result == "del": + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() - self.update_var_view() + if bp_source_identifier is None: + self.message( + "Cannot currently delete a breakpoint here--" + "source code does not correspond to a file location. " + "(perhaps this is generated code)") - def edit_inspector_detail(w, size, key): - var, pos = self.var_list._w.get_focus() + if bp_source_identifier == bp.file: + self.source[bp.line-1].set_breakpoint(False) - if var is None: - return + err = self.debugger.clear_break(bp.file, bp.line) + if err: + self.message("Error clearing breakpoint:\n" + err) + else: + self.update_breakpoints() - fvi = self.get_frame_var_info(read_only=False) - iinfo = fvi.get_inspect_info(var.id_path, read_only=False) + self.bp_list.listen("enter", examine_breakpoint) + self.bp_list.listen("d", delete_breakpoint) + self.bp_list.listen("s", save_breakpoints) + self.bp_list.listen("e", enable_disable_breakpoint) - buttons = [ - ("OK", True), - ("Cancel", False), - ] + self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) + self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) - if var.watch_expr is not None: - watch_edit = urwid.Edit([ - ("label", "Watch expression: ") - ], var.watch_expr.expression) - id_segment = [urwid.AttrMap(watch_edit, "value"), urwid.Text("")] + # }}} - buttons.extend([None, ("Delete", "del")]) + # {{{ source listeners - title = "Watch Expression Options" + def end(): + self.debugger.save_breakpoints() + self.quit_event_loop = True + + def next(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") else: - id_segment = [ - labelled_value("Identifier Path: ", var.id_path), - urwid.Text(""), - ] + self.debugger.set_next(self.debugger.curframe) + end() - title = "Variable Inspection Options" + def step(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_step() + end() - rb_grp_show = [] - rb_show_type = urwid.RadioButton(rb_grp_show, "Show Type", - iinfo.display_type == "type") - rb_show_repr = urwid.RadioButton(rb_grp_show, "Show repr()", - iinfo.display_type == "repr") - rb_show_str = urwid.RadioButton(rb_grp_show, "Show str()", - iinfo.display_type == "str") - rb_show_custom = urwid.RadioButton( - rb_grp_show, "Show custom (set in prefs)", - iinfo.display_type == CONFIG["custom_stringifier"]) + def finish(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_return(self.debugger.curframe) + end() - rb_grp_access = [] - rb_access_public = urwid.RadioButton(rb_grp_access, "Public members", - iinfo.access_level == "public") - rb_access_private = urwid.RadioButton( - rb_grp_access, "Public and private members", - iinfo.access_level == "private") - rb_access_all = urwid.RadioButton( - rb_grp_access, "All members (including __dunder__)", - iinfo.access_level == "all") + def cont(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + self.debugger.set_continue() + end() - wrap_checkbox = urwid.CheckBox("Line Wrap", iinfo.wrap) - expanded_checkbox = urwid.CheckBox("Expanded", iinfo.show_detail) - highlighted_checkbox = urwid.CheckBox("Highlighted", iinfo.highlighted) - repeated_at_top_checkbox = urwid.CheckBox( - "Repeated at top", iinfo.repeated_at_top) - show_methods_checkbox = urwid.CheckBox( - "Show methods", iinfo.show_methods) + def run_to_cursor(w, size, key): + if self.debugger.post_mortem: + self.message("Post-mortem mode: Can't modify state.") + else: + sline, pos = self.source.get_focus() + lineno = pos+1 - lb = urwid.ListBox(urwid.SimpleListWalker( - id_segment + - rb_grp_show + [urwid.Text("")] + - rb_grp_access + [urwid.Text("")] + - [ - wrap_checkbox, - expanded_checkbox, - highlighted_checkbox, - repeated_at_top_checkbox, - show_methods_checkbox, - ])) + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() - result = self.dialog(lb, buttons, title=title) + if bp_source_identifier is None: + self.message( + "Cannot currently set a breakpoint here--" + "source code does not correspond to a file location. " + "(perhaps this is generated code)") - if result is True: - iinfo.show_detail = expanded_checkbox.get_state() - iinfo.wrap = wrap_checkbox.get_state() - iinfo.highlighted = highlighted_checkbox.get_state() - iinfo.repeated_at_top = repeated_at_top_checkbox.get_state() - iinfo.show_methods = show_methods_checkbox.get_state() + from pudb.lowlevel import get_breakpoint_invalid_reason + invalid_reason = get_breakpoint_invalid_reason( + bp_source_identifier, lineno) - if rb_show_type.get_state(): - iinfo.display_type = "type" - elif rb_show_repr.get_state(): - iinfo.display_type = "repr" - elif rb_show_str.get_state(): - iinfo.display_type = "str" - elif rb_show_custom.get_state(): - iinfo.display_type = CONFIG["custom_stringifier"] + if invalid_reason is not None: + self.message( + "Cannot run to the line you indicated, " + "for the following reason:\n\n" + + invalid_reason) + else: + err = self.debugger.set_break( + bp_source_identifier, pos+1, temporary=True) + if err: + self.message("Error dealing with breakpoint:\n" + err) - if rb_access_public.get_state(): - iinfo.access_level = "public" - elif rb_access_private.get_state(): - iinfo.access_level = "private" - elif rb_access_all.get_state(): - iinfo.access_level = "all" + self.debugger.set_continue() + end() - if var.watch_expr is not None: - var.watch_expr.expression = watch_edit.get_edit_text() + def move_home(w, size, key): + self.source.set_focus(0) - elif result == "del": - for i, watch_expr in enumerate(fvi.watches): - if watch_expr is var.watch_expr: - del fvi.watches[i] + def move_end(w, size, key): + self.source.set_focus(len(self.source)-1) - self.update_var_view() + def go_to_line(w, size, key): + _, line = self.source.get_focus() - def insert_watch(w, size, key): - watch_edit = urwid.Edit([ - ("label", "Watch expression: ") - ]) + lineno_edit = urwid.IntEdit([ + ("label", "Line number: ") + ], line+1) if self.dialog( urwid.ListBox(urwid.SimpleListWalker([ - urwid.AttrMap(watch_edit, "value") + labelled_value("File :", + self.source_code_provider.identifier()), + urwid.AttrMap(lineno_edit, "value") ])), [ ("OK", True), ("Cancel", False), - ], title="Add Watch Expression"): + ], title="Go to Line Number"): + lineno = min(max(0, int(lineno_edit.value())-1), len(self.source)-1) + self.source.set_focus(lineno) - from pudb.var_view import WatchExpression - we = WatchExpression(watch_edit.get_edit_text()) - fvi = self.get_frame_var_info(read_only=False) - fvi.watches.append(we) - self.update_var_view() + def move_down(w, size, key): + w.keypress(size, "down") - self.var_list.listen("\\", change_var_state) - self.var_list.listen("t", change_var_state) - self.var_list.listen("r", change_var_state) - self.var_list.listen("s", change_var_state) - self.var_list.listen("c", change_var_state) - self.var_list.listen("h", change_var_state) - self.var_list.listen("@", change_var_state) - self.var_list.listen("*", change_var_state) - self.var_list.listen("w", change_var_state) - self.var_list.listen("m", change_var_state) - self.var_list.listen("enter", edit_inspector_detail) - self.var_list.listen("n", insert_watch) - self.var_list.listen("insert", insert_watch) - self.var_list.listen("j", move_down) - self.var_list.listen("k", move_up) + def move_up(w, size, key): + w.keypress(size, "up") - self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) - self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) + def page_down(w, size, key): + w.keypress(size, "page down") - # }}} + def page_up(w, size, key): + w.keypress(size, "page up") - # {{{ stack listeners - def examine_frame(w, size, key): - _, pos = self.stack_list._w.get_focus() - self.debugger.set_frame_index(self.translate_ui_stack_index(pos)) + def scroll_left(w, size, key): + self.source_hscroll_start = max( + 0, + self.source_hscroll_start - 4) + for sl in self.source: + sl._invalidate() - self.stack_list.listen("enter", examine_frame) + def scroll_right(w, size, key): + self.source_hscroll_start += 4 + for sl in self.source: + sl._invalidate() - def move_stack_top(w, size, key): - self.debugger.set_frame_index(len(self.debugger.stack)-1) + def search(w, size, key): + self.search_controller.open_search_ui() - def move_stack_up(w, size, key): - self.debugger.move_up_frame() + def search_next(w, size, key): + self.search_controller.perform_search(dir=1, update_search_start=True) - def move_stack_down(w, size, key): - self.debugger.move_down_frame() + def search_previous(w, size, key): + self.search_controller.perform_search(dir=-1, update_search_start=True) + + def toggle_breakpoint(w, size, key): + bp_source_identifier = \ + self.source_code_provider.get_breakpoint_source_identifier() + + if bp_source_identifier: + sline, pos = self.source.get_focus() + lineno = pos+1 - self.stack_list.listen("H", move_stack_top) - self.stack_list.listen("u", move_stack_up) - self.stack_list.listen("d", move_stack_down) - self.stack_list.listen("j", move_down) - self.stack_list.listen("k", move_up) + existing_breaks = self.debugger.get_breaks( + bp_source_identifier, lineno) + if existing_breaks: + err = None + for bp in existing_breaks: + if not bp.enabled: + bp.enable() + sline.set_breakpoint(True) + # Unsure about this. Are multiple breakpoints even + # possible? + break + else: + err = self.debugger.clear_break(bp_source_identifier, lineno) + sline.set_breakpoint(False) + else: + file_lineno = (bp_source_identifier, lineno) + if file_lineno in self.debugger.set_traces: + self.debugger.set_traces[file_lineno] = \ + not self.debugger.set_traces[file_lineno] + sline.set_breakpoint(self.debugger.set_traces[file_lineno]) + return - self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) - self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) + from pudb.lowlevel import get_breakpoint_invalid_reason + invalid_reason = get_breakpoint_invalid_reason( + bp_source_identifier, pos+1) - # }}} + if invalid_reason is not None: + do_set = not self.dialog( + urwid.ListBox( + urwid.SimpleListWalker([ + urwid.Text( + "The breakpoint you just set may be " + "invalid, for the following reason:\n\n" + + invalid_reason), + ])), [ + ("Cancel", True), + ("Set Anyway", False), + ], + title="Possibly Invalid Breakpoint", + focus_buttons=True) + else: + do_set = True - # {{{ breakpoint listeners - def save_breakpoints(w, size, key): - self.debugger.save_breakpoints() + if do_set: + err = self.debugger.set_break(bp_source_identifier, pos+1) + sline.set_breakpoint(True) + else: + err = None - def delete_breakpoint(w, size, key): - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() + if err: + self.message("Error dealing with breakpoint:\n" + err) - if bp_source_identifier is None: + self.update_breakpoints() + else: self.message( - "Cannot currently delete a breakpoint here--" + "Cannot currently set a breakpoint here--" "source code does not correspond to a file location. " "(perhaps this is generated code)") - bp_list = self._get_bp_list() - if bp_list: - _, pos = self.bp_list._w.get_focus() - bp = bp_list[pos] - if bp_source_identifier == bp.file and bp.line-1 < len(self.source): - self.source[bp.line-1].set_breakpoint(False) + def pick_module(w, size, key): + from os.path import splitext - err = self.debugger.clear_break(bp.file, bp.line) - if err: - self.message("Error clearing breakpoint:\n" + err) + import sys + + def mod_exists(mod): + if not hasattr(mod, "__file__"): + return False + filename = mod.__file__ + + base, ext = splitext(filename) + ext = ext.lower() + + from os.path import exists + + if ext == ".pyc": + return exists(base+".py") else: - self.update_breakpoints() + return ext == ".py" - def enable_disable_breakpoint(w, size, key): - bp_entry, pos = self.bp_list._w.get_focus() + new_mod_text = SelectableText("-- update me --") + new_mod_entry = urwid.AttrMap(new_mod_text, + None, "focused selectable") - if bp_entry is None: - return + def build_filtered_mod_list(filt_string=""): + modules = sorted(name + # mod_exists may change the size of sys.modules, + # causing this to crash. Copy to a list. + for name, mod in list(sys.modules.items()) + if mod_exists(mod)) - bp = self._get_bp_list()[pos] - bp.enabled = not bp.enabled + result = [urwid.AttrMap(SelectableText(mod), + None, "focused selectable") + for mod in modules if filt_string in mod] + new_mod_text.set_text("<<< IMPORT MODULE '%s' >>>" % filt_string) + result.append(new_mod_entry) + return result - sline = self.source[bp.line-1] - sline.set_breakpoint(bp.enabled) + def show_mod(mod): + filename = self.debugger.canonic(mod.__file__) - self.update_breakpoints() + base, ext = splitext(filename) + if ext == ".pyc": + ext = ".py" + filename = base+".py" - def examine_breakpoint(w, size, key): - bp_entry, pos = self.bp_list._w.get_focus() + self.set_source_code_provider( + FileSourceCodeProvider(self.debugger, filename)) + self.source_list.set_focus(0) - if bp_entry is None: - return + class FilterEdit(urwid.Edit): + def keypress(self, size, key): + result = urwid.Edit.keypress(self, size, key) - bp = self._get_bp_list()[pos] + if result is None: + mod_list[:] = build_filtered_mod_list( + self.get_edit_text()) - if bp.cond is None: - cond = "" - else: - cond = str(bp.cond) + return result - enabled_checkbox = urwid.CheckBox( - "Enabled", bp.enabled) - cond_edit = urwid.Edit([ - ("label", "Condition: ") - ], cond) - ign_count_edit = urwid.IntEdit([ - ("label", "Ignore the next N times: ") - ], bp.ignore) + filt_edit = FilterEdit([("label", "Filter: ")], + self.last_module_filter) - lb = urwid.ListBox(urwid.SimpleListWalker([ - labelled_value("File: ", bp.file), - labelled_value("Line: ", bp.line), - labelled_value("Hits: ", bp.hits), - urwid.Text(""), - enabled_checkbox, - urwid.AttrMap(cond_edit, "value", "value"), - urwid.AttrMap(ign_count_edit, "value", "value"), - ])) + mod_list = urwid.SimpleListWalker( + build_filtered_mod_list(filt_edit.get_edit_text())) + lb = urwid.ListBox(mod_list) - result = self.dialog(lb, [ - ("OK", True), - ("Cancel", False), - None, - ("Delete", "del"), - ("Location", "loc"), - ], title="Edit Breakpoint") + w = urwid.Pile([ + ("flow", urwid.AttrMap(filt_edit, "value")), + ("fixed", 1, urwid.SolidFill()), + urwid.AttrMap(lb, "selectable")]) - if result is True: - bp.enabled = enabled_checkbox.get_state() - bp.ignore = int(ign_count_edit.value()) - cond = cond_edit.get_edit_text() - if cond: - bp.cond = cond - else: - bp.cond = None - elif result == "loc": - self.show_line(bp.line, - FileSourceCodeProvider(self.debugger, bp.file)) - self.columns.set_focus(0) - elif result == "del": - bp_source_identifier = \ - self.source_code_provider.get_breakpoint_source_identifier() + while True: + result = self.dialog(w, [ + ("OK", True), + ("Cancel", False), + ("Reload", "reload"), - if bp_source_identifier is None: - self.message( - "Cannot currently delete a breakpoint here--" - "source code does not correspond to a file location. " - "(perhaps this is generated code)") + ], title="Pick Module") + self.last_module_filter = filt_edit.get_edit_text() - if bp_source_identifier == bp.file: - self.source[bp.line-1].set_breakpoint(False) + if result is True: + widget, pos = lb.get_focus() + if widget is new_mod_entry: + new_mod_name = filt_edit.get_edit_text() + try: + __import__(str(new_mod_name)) + except: + from pudb.lowlevel import format_exception - err = self.debugger.clear_break(bp.file, bp.line) - if err: - self.message("Error clearing breakpoint:\n" + err) - else: - self.update_breakpoints() + self.message("Could not import module '%s':\n\n%s" % ( + new_mod_name, "".join( + format_exception(sys.exc_info()))), + title="Import Error") + else: + show_mod(__import__(str(new_mod_name))) + break + else: + show_mod(sys.modules[widget.base_widget.get_text()[0]]) + break + elif result is False: + break + elif result == "reload": + widget, pos = lb.get_focus() + if widget is not new_mod_entry: + mod_name = widget.base_widget.get_text()[0] + mod = sys.modules[mod_name] + if PY3: + reload(mod) # noqa (undef on Py3) + else: + import importlib + importlib.reload(mod) - self.bp_list.listen("enter", examine_breakpoint) - self.bp_list.listen("d", delete_breakpoint) - self.bp_list.listen("s", save_breakpoints) - self.bp_list.listen("e", enable_disable_breakpoint) - self.bp_list.listen("j", move_down) - self.bp_list.listen("k", move_up) + self.message("'%s' was successfully reloaded." % mod_name) - self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) - self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) + if self.source_code_provider is not None: + self.source_code_provider.clear_cache() - # }}} + self.set_source_code_provider(self.source_code_provider, + force_update=True) - # {{{ source listeners + _, pos = self.stack_list._w.get_focus() + self.debugger.set_frame_index( + self.translate_ui_stack_index(pos)) self.source_sigwrap.listen("n", next) self.source_sigwrap.listen("s", step) From fcacf1dde8b65441becd5b6daaddf99775b17651 Mon Sep 17 00:00:00 2001 From: Adam Mesha Date: Thu, 25 Aug 2016 13:56:18 +0300 Subject: [PATCH 3/5] Enable j/k sidebar navigation Works by passing "up" or "down" keypress messages to the Pile widget, so there is no difference between using j/k and using the up/down arrow keys. --- pudb/debugger.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pudb/debugger.py b/pudb/debugger.py index 7fa29d63..f262144c 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -713,6 +713,13 @@ def clear_cmdline_history(btn): ]) self.rhs_col_sigwrap = SignalWrap(self.rhs_col) + def rhs_up(w, size, key): + self.rhs_col.keypress(size, "up") + + def rhs_down(w, size, key): + self.rhs_col.keypress(size, "down") + + # }}} self.columns = urwid.Columns( @@ -920,6 +927,8 @@ def insert_watch(w, size, key): self.var_list.listen("enter", edit_inspector_detail) self.var_list.listen("n", insert_watch) self.var_list.listen("insert", insert_watch) + self.var_list.listen("j", rhs_down) + self.var_list.listen("k", rhs_up) self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) @@ -945,6 +954,8 @@ def move_stack_down(w, size, key): self.stack_list.listen("H", move_stack_top) self.stack_list.listen("u", move_stack_up) self.stack_list.listen("d", move_stack_down) + self.stack_list.listen("j", rhs_down) + self.stack_list.listen("k", rhs_up) self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) @@ -1067,6 +1078,8 @@ def examine_breakpoint(w, size, key): self.bp_list.listen("d", delete_breakpoint) self.bp_list.listen("s", save_breakpoints) self.bp_list.listen("e", enable_disable_breakpoint) + self.bp_list.listen("j", rhs_down) + self.bp_list.listen("k", rhs_up) self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) From f63315ab14d1999d39ad954b70c919a5131df7cc Mon Sep 17 00:00:00 2001 From: Adam Mesha Date: Thu, 3 Aug 2017 09:31:23 +0300 Subject: [PATCH 4/5] wip on j/k navigation --- pudb/debugger.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/pudb/debugger.py b/pudb/debugger.py index f262144c..9bd3f611 100644 --- a/pudb/debugger.py +++ b/pudb/debugger.py @@ -7,6 +7,10 @@ import sys import os +from urwid.command_map import command_map +command_map['j'] = 'cursor down' +command_map['k'] = 'cursor up' + from pudb.settings import load_config, save_config CONFIG = load_config() save_config(CONFIG) @@ -713,13 +717,6 @@ def clear_cmdline_history(btn): ]) self.rhs_col_sigwrap = SignalWrap(self.rhs_col) - def rhs_up(w, size, key): - self.rhs_col.keypress(size, "up") - - def rhs_down(w, size, key): - self.rhs_col.keypress(size, "down") - - # }}} self.columns = urwid.Columns( @@ -927,8 +924,6 @@ def insert_watch(w, size, key): self.var_list.listen("enter", edit_inspector_detail) self.var_list.listen("n", insert_watch) self.var_list.listen("insert", insert_watch) - self.var_list.listen("j", rhs_down) - self.var_list.listen("k", rhs_up) self.var_list.listen("[", partial(change_rhs_box, 'variables', 0, -1)) self.var_list.listen("]", partial(change_rhs_box, 'variables', 0, 1)) @@ -954,8 +949,6 @@ def move_stack_down(w, size, key): self.stack_list.listen("H", move_stack_top) self.stack_list.listen("u", move_stack_up) self.stack_list.listen("d", move_stack_down) - self.stack_list.listen("j", rhs_down) - self.stack_list.listen("k", rhs_up) self.stack_list.listen("[", partial(change_rhs_box, 'stack', 1, -1)) self.stack_list.listen("]", partial(change_rhs_box, 'stack', 1, 1)) @@ -1078,8 +1071,6 @@ def examine_breakpoint(w, size, key): self.bp_list.listen("d", delete_breakpoint) self.bp_list.listen("s", save_breakpoints) self.bp_list.listen("e", enable_disable_breakpoint) - self.bp_list.listen("j", rhs_down) - self.bp_list.listen("k", rhs_up) self.bp_list.listen("[", partial(change_rhs_box, 'breakpoints', 2, -1)) self.bp_list.listen("]", partial(change_rhs_box, 'breakpoints', 2, 1)) From 0fa206b07daf86abb012bfa4f1e3699ee0841c5f Mon Sep 17 00:00:00 2001 From: Adam Mesha Date: Thu, 3 Aug 2017 09:31:40 +0300 Subject: [PATCH 5/5] debugging stuff --- pudb/__init__.py | 2 +- pudb/ui_tools.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pudb/__init__.py b/pudb/__init__.py index 822d1567..1a85e395 100644 --- a/pudb/__init__.py +++ b/pudb/__init__.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function -NUM_VERSION = (2016, 2) +NUM_VERSION = (2016, 2, 'amesha') VERSION = ".".join(str(nv) for nv in NUM_VERSION) __version__ = VERSION diff --git a/pudb/ui_tools.py b/pudb/ui_tools.py index 8050b3df..d966c2aa 100644 --- a/pudb/ui_tools.py +++ b/pudb/ui_tools.py @@ -74,6 +74,7 @@ def keypress(self, size, key): return key +import xtraceback; xtraceback.compat.install() class SignalWrap(urwid.WidgetWrap): def __init__(self, w, is_preemptive=False): urwid.WidgetWrap.__init__(self, w) @@ -84,6 +85,20 @@ def listen(self, mask, handler): self.event_listeners.append((mask, handler)) def keypress(self, size, key): + # with open('/home/adam/tmp/keypress', 'a') as fp: + # if 1 or (key == 'down' and 0 in size): + # import traceback; traceback.print_stack(file=fp) + # fp.write('self: {!r}, w: {!r}, ' + # 'size: {!r}, key: {!r}\n\n'.format( + # self, self._w, size, key)) + # fp.write(repr(dir(self._w)) + '\n') + # fp.write(repr(self._w.contents)+'\n\n--------------------------------------------------------------------------------\n') + # # if 0 in size: + # # fp.write('\nsomething\n\n\n') + # # else: + # # fp.write('\nnothing here\n\n\n') + + result = key if self.is_preemptive: