Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mouse support #186

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 65 additions & 24 deletions pudb/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,9 @@ def _runscript(self, filename):


# UI stuff --------------------------------------------------------------------

from pudb.ui_tools import make_hotkey_markup, labelled_value, \
SelectableText, SignalWrap, StackFrame, BreakpointFrame

from pudb.ui_tools import double_press_input_filter, labelled_value, \
make_hotkey_markup, SelectableText, SignalWrap, StackFrame, \
BreakpointFrame
from pudb.var_view import FrameVarInfoKeeper


Expand Down Expand Up @@ -749,13 +748,19 @@ def change_rhs_box(name, index, direction, w, size, key):

# {{{ variables listeners

def change_var_state(w, size, key):
def change_var_state(w, size, key, button=None, x=None, y=None, focus=None):
var, pos = self.var_list._w.get_focus()
if not var:
return

iinfo = self.get_frame_var_info(read_only=False) \
.get_inspect_info(var.id_path, read_only=False)

if key == "\\":
display_types = ["type", "repr", "str"]
if CONFIG["custom_stringifier"]:
display_types.append(CONFIG["custom_stringifier"])

if key == "\\" or (key == 'mouse press' and button == 3):
iinfo.show_detail = not iinfo.show_detail
elif key == "t":
iinfo.display_type = "type"
Expand All @@ -765,9 +770,9 @@ def change_var_state(w, size, key):
iinfo.display_type = "str"
elif key == "c":
iinfo.display_type = CONFIG["custom_stringifier"]
elif key == "h":
elif key == "h" or (key == 'ctrl mouse press' and button == 1):
iinfo.highlighted = not iinfo.highlighted
elif key == "@":
elif key == "@" or (key == 'ctrl mouse double press' and button == 1):
iinfo.repeated_at_top = not iinfo.repeated_at_top
elif key == "*":
levels = ["public", "private", "all", "public"]
Expand All @@ -776,10 +781,20 @@ def change_var_state(w, size, key):
iinfo.wrap = not iinfo.wrap
elif key == "m":
iinfo.show_methods = not iinfo.show_methods
elif key == 'mouse press' and button == 5:
# SignalWrap.mouse_event by doesn't select on scroll events,
# but we want to do that here.
super(SignalWrap, self.var_list).mouse_event(size,
'mouse press', 1, x, y, focus)
iinfo.display_type = display_types[(display_types.index(iinfo.display_type) + 1) % len(display_types)]
elif key == 'mouse press' and button == 4:
super(SignalWrap, self.var_list).mouse_event(size,
'mouse press', 1, x, y, focus)
iinfo.display_type = display_types[(display_types.index(iinfo.display_type) - 1 + len(display_types)) % len(display_types)]

self.update_var_view()

def edit_inspector_detail(w, size, key):
def edit_inspector_detail(w, size, key, button=None, x=None, y=None, focus=None):
var, pos = self.var_list._w.get_focus()

if var is None:
Expand Down Expand Up @@ -911,12 +926,16 @@ def insert_watch(w, size, key):
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_mouse_event("mouse press", None, change_var_state)
self.var_list.listen("h", change_var_state)
self.var_list.listen_mouse_event("ctrl mouse press", 1, 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_mouse_event("ctrl mouse double press", 1, change_var_state)
self.var_list.listen("enter", edit_inspector_detail)
self.var_list.listen_mouse_event("mouse double press", 1, edit_inspector_detail)
self.var_list.listen("n", insert_watch)
self.var_list.listen("insert", insert_watch)

Expand All @@ -926,24 +945,29 @@ def insert_watch(w, size, key):
# }}}

# {{{ stack listeners
def examine_frame(w, size, key):
def examine_frame(w, size, key, button=None, x=None, y=None, focus=None):
_, 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)
self.stack_list.listen_mouse_event("mouse press", 1, examine_frame)

def move_stack_top(w, size, key):
def move_stack_top(w, size, key, button=None, x=None, y=None, focus=None):
self.debugger.set_frame_index(len(self.debugger.stack)-1)

def move_stack_up(w, size, key):
def move_stack_up(w, size, key, button=None, x=None, y=None, focus=None):
self.debugger.move_up_frame()

def move_stack_down(w, size, key):
def move_stack_down(w, size, key, button=None, x=None, y=None, focus=None):
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_mouse_event("mouse press", 4, move_stack_up)
self.stack_list.listen("d", move_stack_down)
self.stack_list.listen_mouse_event("mouse press", 5, move_stack_down)
self.source_sigwrap.listen("u", move_stack_up)
self.source_sigwrap.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))
Expand Down Expand Up @@ -977,7 +1001,7 @@ def delete_breakpoint(w, size, key):
else:
self.update_breakpoints()

def enable_disable_breakpoint(w, size, key):
def enable_disable_breakpoint(w, size, key, button=None, x=None, y=None, focus=None):
bp_entry, pos = self.bp_list._w.get_focus()

if bp_entry is None:
Expand All @@ -991,7 +1015,7 @@ def enable_disable_breakpoint(w, size, key):

self.update_breakpoints()

def examine_breakpoint(w, size, key):
def examine_breakpoint(w, size, key, button=None, x=None, y=None, focus=None):
bp_entry, pos = self.bp_list._w.get_focus()

if bp_entry is None:
Expand Down Expand Up @@ -1063,9 +1087,11 @@ def examine_breakpoint(w, size, key):
self.update_breakpoints()

self.bp_list.listen("enter", examine_breakpoint)
self.bp_list.listen_mouse_event("mouse double press", 1, 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_mouse_event("mouse press", 3, 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))
Expand All @@ -1078,14 +1104,14 @@ def end():
self.debugger.save_breakpoints()
self.quit_event_loop = True

def next(w, size, key):
def next(w, size, key, button=None, x=None, y=None, focus=None):
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):
def step(w, size, key, button=None, x=None, y=None, focus=None):
if self.debugger.post_mortem:
self.message("Post-mortem mode: Can't modify state.")
else:
Expand All @@ -1106,7 +1132,7 @@ def cont(w, size, key):
self.debugger.set_continue()
end()

def run_to_cursor(w, size, key):
def run_to_cursor(w, size, key, button=None, x=None, y=None, focus=None):
if self.debugger.post_mortem:
self.message("Post-mortem mode: Can't modify state.")
else:
Expand Down Expand Up @@ -1166,16 +1192,16 @@ def go_to_line(w, size, key):
lineno = min(max(0, int(lineno_edit.value())-1), len(self.source)-1)
self.source.set_focus(lineno)

def move_down(w, size, key):
def move_down(w, size, key, button=None, x=None, y=None, focus=None):
w.keypress(size, "down")

def move_up(w, size, key):
def move_up(w, size, key, button=None, x=None, y=None, focus=None):
w.keypress(size, "up")

def page_down(w, size, key):
def page_down(w, size, key, button=None, x=None, y=None, focus=None):
w.keypress(size, "page down")

def page_up(w, size, key):
def page_up(w, size, key, button=None, x=None, y=None, focus=None):
w.keypress(size, "page up")

def scroll_left(w, size, key):
Expand All @@ -1199,7 +1225,7 @@ def search_next(w, size, key):
def search_previous(w, size, key):
self.search_controller.perform_search(dir=-1, update_search_start=True)

def toggle_breakpoint(w, size, key):
def toggle_breakpoint(w, size, key, button=None, x=None, y=None, focus=None):
bp_source_identifier = \
self.source_code_provider.get_breakpoint_source_identifier()

Expand Down Expand Up @@ -1230,7 +1256,7 @@ def toggle_breakpoint(w, size, key):

from pudb.lowlevel import get_breakpoint_invalid_reason
invalid_reason = get_breakpoint_invalid_reason(
bp_source_identifier, pos+1)
bp_source_identifier, lineno)

if invalid_reason is not None:
do_set = not self.dialog(
Expand Down Expand Up @@ -1386,16 +1412,23 @@ def keypress(self, size, key):
self.translate_ui_stack_index(pos))

self.source_sigwrap.listen("n", next)
self.source_sigwrap.listen_mouse_event("meta mouse press", 5, next)
self.source_sigwrap.listen("s", step)
self.source_sigwrap.listen_mouse_event("meta mouse press", 1, step)
self.source_sigwrap.listen("f", finish)
self.source_sigwrap.listen("r", finish)
self.source_sigwrap.listen("c", cont)
self.source_sigwrap.listen("t", run_to_cursor)
self.source_sigwrap.listen_mouse_event("mouse double press", 1, run_to_cursor)

self.source_sigwrap.listen("j", move_down)
self.source_sigwrap.listen_mouse_event("mouse press", 5, move_down)
self.source_sigwrap.listen("k", move_up)
self.source_sigwrap.listen_mouse_event("mouse press", 4, move_up)
self.source_sigwrap.listen("ctrl d", page_down)
self.source_sigwrap.listen_mouse_event("ctrl mouse press", 5, page_down)
self.source_sigwrap.listen("ctrl u", page_up)
self.source_sigwrap.listen_mouse_event("ctrl mouse press", 4, page_up)
self.source_sigwrap.listen("ctrl f", page_down)
self.source_sigwrap.listen("ctrl b", page_up)
self.source_sigwrap.listen("h", scroll_left)
Expand All @@ -1412,6 +1445,7 @@ def keypress(self, size, key):
self.source_sigwrap.listen("L", go_to_line)

self.source_sigwrap.listen("b", toggle_breakpoint)
self.source_sigwrap.listen_mouse_event("mouse press", 3, toggle_breakpoint)
self.source_sigwrap.listen("m", pick_module)

self.source_sigwrap.listen("H", move_stack_top)
Expand Down Expand Up @@ -1886,6 +1920,8 @@ def help(w, size, key):

self.current_line = None

self.double_press_input_filter = double_press_input_filter()

self.quit_event_loop = False

# }}}
Expand Down Expand Up @@ -2059,6 +2095,8 @@ def show_exception_dialog(self, exc_tuple):
def show(self):
if self.show_count == 0:
self.screen.start()
if CONFIG["mouse_support"]:
self.screen.set_mouse_tracking()
self.show_count += 1

def hide(self):
Expand Down Expand Up @@ -2243,10 +2281,13 @@ def event_loop(self, toplevel=None):
canvas = toplevel.render(self.size, focus=True)
self.screen.draw_screen(self.size, canvas)
keys = self.screen.get_input()
keys = self.double_press_input_filter(keys, None)

for k in keys:
if k == "window resize":
self.size = self.screen.get_cols_rows()
elif urwid.is_mouse_event(k):
toplevel.mouse_event(self.size, *k, focus=True)
else:
toplevel.keypress(self.size, k)

Expand Down
27 changes: 27 additions & 0 deletions pudb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ def load_config():

conf_dict.setdefault("display", "auto")

conf_dict.setdefault("mouse_support", True)

conf_dict.setdefault("prompt_on_quit", True)

def normalize_bool_inplace(name):
Expand All @@ -92,6 +94,7 @@ def normalize_bool_inplace(name):

normalize_bool_inplace("line_numbers")
normalize_bool_inplace("wrap_variables")
normalize_bool_inplace("mouse_support")
normalize_bool_inplace("prompt_on_quit")

return conf_dict
Expand Down Expand Up @@ -146,6 +149,9 @@ def _update_stringifier():
def _update_wrap_variables():
ui.update_var_view()

def _update_mouse_support(mouse_support):
ui.screen.set_mouse_tracking(mouse_support)

def _update_config(check_box, new_state, option_newvalue):
option, newvalue = option_newvalue
new_conf_dict = {option: newvalue}
Expand Down Expand Up @@ -190,6 +196,11 @@ def _update_config(check_box, new_state, option_newvalue):
conf_dict.update(new_conf_dict)
_update_wrap_variables()

elif option == "mouse_support":
mouse_support = new_conf_dict["mouse_support"] = not check_box.get_state()
conf_dict.update(new_conf_dict)
_update_mouse_support(mouse_support)

heading = urwid.Text("This is the preferences screen for PuDB. "
"Hit Ctrl-P at any time to get back to it.\n\n"
"Configuration settings are saved in "
Expand Down Expand Up @@ -331,6 +342,18 @@ def _update_config(check_box, new_state, option_newvalue):

# }}}


# {{{ mouse support

cb_mouse_support = urwid.CheckBox("Mouse support",
bool(conf_dict["mouse_support"]), on_state_change=_update_config,
user_data=("mouse_support", None))

mouse_support_info = urwid.Text("Enable mouse support (for terminals that "
"support it)? See the help (hit '?') for information about what "
"different mouse buttons do.")
# }}}

lb_contents = (
[heading]
+ [urwid.AttrMap(urwid.Text("Line Numbers:\n"), "group head")]
Expand Down Expand Up @@ -361,6 +384,10 @@ def _update_config(check_box, new_state, option_newvalue):
+ [urwid.AttrMap(urwid.Text("\nDisplay driver:\n"), "group head")]
+ [display_info]
+ display_rbs

+ [urwid.AttrMap(urwid.Text("\nMouse support:\n"), "group head")]
+ [mouse_support_info]
+ [cb_mouse_support]
)

lb = urwid.ListBox(urwid.SimpleListWalker(lb_contents))
Expand Down
Loading