console: globally respected nav commands

Use this to bind nav keys with commands throughout.
This commit is contained in:
Aldo Cortesi 2017-05-02 10:37:11 +12:00
parent 8d29492960
commit 9e58c36639
16 changed files with 110 additions and 52 deletions

View File

@ -353,6 +353,8 @@ class View(collections.Sequence):
the view, negative from the end of the view, so that 0 is the first
flow, -1 is the last flow.
"""
if len(self) == 0:
return
if dst < 0:
dst = len(self) + dst
if dst < 0:

View File

@ -120,6 +120,12 @@ class CommandsList(urwid.ListBox):
if key == "enter":
foc, idx = self.get_focus()
signals.status_prompt_command.send(partial=foc.cmd.path + " ")
elif key == "m_start":
self.set_focus(0)
self.walker._modified()
elif key == "m_end":
self.set_focus(len(self.walker.cmds) - 1)
self.walker._modified()
return super().keypress(size, key)
@ -159,7 +165,6 @@ class Commands(urwid.Pile):
self.master = master
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "tab":
self.focus_position = (
self.focus_position + 1

View File

@ -77,20 +77,6 @@ def format_keyvals(lst, key="key", val="text", indent=0):
return ret
def shortcuts(k):
if k == " ":
k = "page down"
elif k == "ctrl f":
k = "page down"
elif k == "ctrl b":
k = "page up"
elif k == "j":
k = "down"
elif k == "k":
k = "up"
return k
def fcol(s, attr):
s = str(s)
return (

View File

@ -58,13 +58,12 @@ class LogBufferBox(urwid.ListBox):
super().set_focus(index)
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "z":
self.master.clear_events()
key = None
elif key == "G":
elif key == "m_end":
self.set_focus(len(self.master.logbuffer) - 1)
elif key == "g":
elif key == "m_start":
self.set_focus(0)
return urwid.ListBox.keypress(self, size, key)
@ -136,8 +135,7 @@ class FlowItem(urwid.WidgetWrap):
return True
def keypress(self, xxx_todo_changeme, key):
(maxcol,) = xxx_todo_changeme
return common.shortcuts(key)
return key
class FlowListWalker(urwid.ListWalker):
@ -183,7 +181,10 @@ class FlowListBox(urwid.ListBox):
super().__init__(FlowListWalker(master))
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "m_start":
self.master.commands.call("view.go 0")
elif key == "m_end":
self.master.commands.call("view.go -1")
return urwid.ListBox.keypress(self, size, key)
def view_changed(self):

View File

@ -271,7 +271,6 @@ class FlowDetails(tabs.Tabs):
def keypress(self, size, key):
key = super().keypress(size, key)
key = common.shortcuts(key)
return self._w.keypress(size, key)

View File

@ -253,6 +253,7 @@ FIRST_WIDTH_MIN = 20
class BaseGridEditor(urwid.WidgetWrap):
def __init__(
self,
master: "mitmproxy.tools.console.master.ConsoleMaster",
@ -345,15 +346,14 @@ class BaseGridEditor(urwid.WidgetWrap):
self._w.keypress(size, key)
return None
key = common.shortcuts(key)
column = self.columns[self.walker.focus_col]
if key == "g":
if key == "m_start":
self.walker.set_focus(0)
elif key == "G":
elif key == "m_end":
self.walker.set_focus(len(self.walker.lst) - 1)
elif key in ["h", "left"]:
elif key == "left":
self.walker.left()
elif key in ["l", "right"]:
elif key == "right":
self.walker.right()
elif key == "tab":
self.walker.tab_next()

View File

@ -4,7 +4,6 @@ import urwid
from mitmproxy import flowfilter
from mitmproxy.tools.console import common
from mitmproxy.tools.console import signals
from mitmproxy import version
@ -85,14 +84,8 @@ class HelpView(urwid.ListBox):
return text
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "q":
signals.pop_view_state.send(self)
return None
elif key == "?":
key = None
elif key == "g":
if key == "m_start":
self.set_focus(0)
elif key == "G":
elif key == "m_end":
self.set_focus(len(self.body.contents))
return urwid.ListBox.keypress(self, size, key)

View File

@ -4,6 +4,7 @@ from mitmproxy.tools.console import commandeditor
SupportedContexts = {
"chooser",
"commands",
"flowlist",
"flowview",

View File

@ -83,6 +83,62 @@ class ConsoleAddon:
self.master = master
self.started = False
@command.command("console.nav.start")
def nav_start(self) -> None:
"""
Go to the start of a list or scrollable.
"""
self.master.inject_key("m_start")
@command.command("console.nav.end")
def nav_end(self) -> None:
"""
Go to the end of a list or scrollable.
"""
self.master.inject_key("m_end")
@command.command("console.nav.up")
def nav_up(self) -> None:
"""
Go up.
"""
self.master.inject_key("up")
@command.command("console.nav.down")
def nav_down(self) -> None:
"""
Go down.
"""
self.master.inject_key("down")
@command.command("console.nav.pageup")
def nav_pageup(self) -> None:
"""
Go up.
"""
self.master.inject_key("page up")
@command.command("console.nav.pagedown")
def nav_pagedown(self) -> None:
"""
Go down.
"""
self.master.inject_key("page down")
@command.command("console.nav.left")
def nav_left(self) -> None:
"""
Go left.
"""
self.master.inject_key("left")
@command.command("console.nav.right")
def nav_right(self) -> None:
"""
Go right.
"""
self.master.inject_key("right")
@command.command("console.choose")
def console_choose(
self, prompt: str, choices: typing.Sequence[str], *cmd: typing.Sequence[str]
@ -101,7 +157,7 @@ class ConsoleAddon:
except exceptions.CommandError as e:
signals.status_message.send(message=str(e))
self.master.overlay(overlay.Chooser(prompt, choices, "", callback))
self.master.overlay(overlay.Chooser(self.master, prompt, choices, "", callback))
ctx.log.info(choices)
@command.command("console.choose.cmd")
@ -124,7 +180,7 @@ class ConsoleAddon:
except exceptions.CommandError as e:
signals.status_message.send(message=str(e))
self.master.overlay(overlay.Chooser(prompt, choices, "", callback))
self.master.overlay(overlay.Chooser(self.master, prompt, choices, "", callback))
ctx.log.info(choices)
@command.command("console.command")
@ -246,7 +302,7 @@ class ConsoleAddon:
signals.status_message.send(message=str(e))
opts = [i.name.lower() for i in contentviews.views]
self.master.overlay(overlay.Chooser("Mode", opts, "", callback))
self.master.overlay(overlay.Chooser(self.master, "Mode", opts, "", callback))
@command.command("console.flowview.mode")
def flowview_mode(self) -> str:
@ -288,6 +344,17 @@ def default_keymap(km):
km.add("O", "console.view.options", ["global"])
km.add("Q", "console.exit", ["global"])
km.add("q", "console.view.pop", ["global"])
km.add("g", "console.nav.start", ["global"])
km.add("G", "console.nav.end", ["global"])
km.add("k", "console.nav.up", ["global"])
km.add("j", "console.nav.down", ["global"])
km.add("l", "console.nav.right", ["global"])
km.add("h", "console.nav.left", ["global"])
km.add(" ", "console.nav.pagedown", ["global"])
km.add("ctrl f", "console.nav.pagedown", ["global"])
km.add("ctrl b", "console.nav.pageup", ["global"])
km.add("i", "console.command set intercept=", ["global"])
km.add("W", "console.command set save_stream_file=", ["global"])
@ -308,9 +375,7 @@ def default_keymap(km):
)
km.add("f", "console.command set view_filter=", ["flowlist"])
km.add("F", "set console_focus_follow=toggle", ["flowlist"])
km.add("g", "view.go 0", ["flowlist"])
km.add("G", "view.go -1", ["flowlist"])
km.add("l", "console.command cut.clip ", ["flowlist", "flowview"])
km.add("ctrl l", "console.command cut.clip ", ["flowlist", "flowview"])
km.add("L", "console.command view.load ", ["flowlist"])
km.add("m", "flow.mark.toggle @focus", ["flowlist"])
km.add("M", "view.marked.toggle", ["flowlist"])
@ -361,6 +426,7 @@ def default_keymap(km):
)
km.add("p", "view.focus.prev", ["flowview"])
km.add("m", "console.flowview.mode.set", ["flowview"])
km.add("tab", "console.nav.right", ["flowview"])
km.add(
"z",
"console.choose \"Part\" request,response "
@ -523,6 +589,9 @@ class ConsoleMaster(master.Master):
self.loop.draw_screen()
self.loop.set_alarm_in(0.01, self.ticker)
def inject_key(self, key):
self.loop.process_input([key])
def run(self):
self.ui = urwid.raw_display.Screen()
self.ui.set_terminal_properties(256)

View File

@ -214,10 +214,10 @@ class OptionsList(urwid.ListBox):
foc.opt.name,
self.master.options.default(foc.opt.name)
)
elif key == "g":
elif key == "m_start":
self.set_focus(0)
self.walker._modified()
elif key == "G":
elif key == "m_end":
self.set_focus(len(self.walker.opts) - 1)
self.walker._modified()
elif key == "l":
@ -299,7 +299,6 @@ class Options(urwid.Pile):
self.master = master
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "tab":
self.focus_position = (
self.focus_position + 1

View File

@ -80,7 +80,8 @@ class ChooserListWalker(urwid.ListWalker):
class Chooser(urwid.WidgetWrap):
def __init__(self, title, choices, current, callback):
def __init__(self, master, title, choices, current, callback):
self.master = master
self.choices = choices
self.callback = callback
choicewidth = max([len(i) for i in choices])
@ -103,7 +104,7 @@ class Chooser(urwid.WidgetWrap):
return True
def keypress(self, size, key):
key = common.shortcuts(key)
key = self.master.keymap.handle("chooser", key)
if key == "enter":
self.callback(self.choices[self.walker.index])
signals.pop_view_state.send(self)

View File

@ -35,10 +35,10 @@ class Searchable(urwid.ListBox):
self.find_next(False)
elif key == "N":
self.find_next(True)
elif key == "g":
elif key == "m_start":
self.set_focus(0)
self.walker._modified()
elif key == "G":
elif key == "m_end":
self.set_focus(len(self.walker) - 1)
self.walker._modified()
else:

View File

@ -113,7 +113,6 @@ class Select(urwid.ListBox):
if key == "enter" or key == " ":
self.get_focus()[0].option.activate()
return None
key = common.shortcuts(key)
if key in self.keymap:
self.keymap[key].activate()
self.set_focus(self.options.index(self.keymap[key]))

View File

@ -35,9 +35,9 @@ class Tabs(urwid.WidgetWrap):
def keypress(self, size, key):
n = len(self.tabs)
if key in ["tab", "l"]:
if key == "right":
self.change_tab((self.tab_offset + 1) % n)
elif key == "h":
elif key == "left":
self.change_tab((self.tab_offset - 1) % n)
return self._w.keypress(size, key)

View File

@ -76,6 +76,8 @@ class Window(urwid.Frame):
self.call(self.focus, "view_popping")
def push(self, wname):
if self.primary_stack and self.primary_stack[-1] == wname:
return
self.primary_stack.append(wname)
self.body = urwid.AttrWrap(
self.windows[wname], "background"

View File

@ -221,6 +221,7 @@ def test_resolve():
def test_movement():
v = view.View()
with taddons.context():
v.go(0)
v.add([
tflow.tflow(),
tflow.tflow(),