diff options
-rw-r--r-- | mitmproxy/tools/console/commands.py | 1 | ||||
-rw-r--r-- | mitmproxy/tools/console/flowlist.py | 1 | ||||
-rw-r--r-- | mitmproxy/tools/console/grideditor/base.py | 17 | ||||
-rw-r--r-- | mitmproxy/tools/console/grideditor/editors.py | 1 | ||||
-rw-r--r-- | mitmproxy/tools/console/help.py | 84 | ||||
-rw-r--r-- | mitmproxy/tools/console/keymap.py | 5 | ||||
-rw-r--r-- | mitmproxy/tools/console/layoutwidget.py | 10 | ||||
-rw-r--r-- | mitmproxy/tools/console/options.py | 1 | ||||
-rw-r--r-- | mitmproxy/tools/console/overlay.py | 8 | ||||
-rw-r--r-- | mitmproxy/tools/console/window.py | 13 | ||||
-rw-r--r-- | test/mitmproxy/tools/console/test_help.py | 11 | ||||
-rw-r--r-- | test/mitmproxy/tools/console/test_keymap.py | 37 |
12 files changed, 111 insertions, 78 deletions
diff --git a/mitmproxy/tools/console/commands.py b/mitmproxy/tools/console/commands.py index 1ece5b63..7f680c72 100644 --- a/mitmproxy/tools/console/commands.py +++ b/mitmproxy/tools/console/commands.py @@ -1,7 +1,6 @@ import urwid import blinker import textwrap -from mitmproxy.tools.console import common from mitmproxy.tools.console import layoutwidget from mitmproxy.tools.console import signals diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py index d2990813..715ecb84 100644 --- a/mitmproxy/tools/console/flowlist.py +++ b/mitmproxy/tools/console/flowlist.py @@ -5,7 +5,6 @@ from mitmproxy.tools.console import layoutwidget import mitmproxy.tools.console.master # noqa - class FlowItem(urwid.WidgetWrap): def __init__(self, master, flow): diff --git a/mitmproxy/tools/console/grideditor/base.py b/mitmproxy/tools/console/grideditor/base.py index 325d8ab0..87172eb4 100644 --- a/mitmproxy/tools/console/grideditor/base.py +++ b/mitmproxy/tools/console/grideditor/base.py @@ -80,10 +80,10 @@ class GridRow(urwid.WidgetWrap): ) -> None: self.focused = focused self.editor = editor - self.edit_col = None # type: Optional[Cell] + self.edit_col = None # type: typing.Optional[Cell] errors = values[1] - self.fields = [] # type: Sequence[Any] + self.fields = [] # type: typing.Sequence[typing.Any] for i, v in enumerate(values[0]): if focused == i and editing: self.edit_col = self.editor.columns[i].Edit(v) @@ -132,11 +132,11 @@ class GridWalker(urwid.ListWalker): lst: typing.Iterable[list], editor: "GridEditor" ) -> None: - self.lst = [(i, set()) for i in lst] # type: Sequence[Tuple[Any, Set]] + self.lst = [(i, set()) for i in lst] # type: typing.Sequence[typing.Tuple[typing.Any, typing.Set]] self.editor = editor self.focus = 0 self.focus_col = 0 - self.edit_row = None # type: Optional[GridRow] + self.edit_row = None # type: typing.Optional[GridRow] def _modified(self): self.editor.show_empty_msg() @@ -266,6 +266,7 @@ FIRST_WIDTH_MIN = 20 class BaseGridEditor(urwid.WidgetWrap): + title = "" keyctx = "grideditor" def __init__( @@ -317,7 +318,7 @@ class BaseGridEditor(urwid.WidgetWrap): signals.footer_help.send(self, helptext="") self.show_empty_msg() - def view_popping(self): + def layout_popping(self): res = [] for i in self.walker.lst: if not i[1] and any([x for x in i[0]]): @@ -445,7 +446,7 @@ class BaseGridEditor(urwid.WidgetWrap): class GridEditor(BaseGridEditor): title = None # type: str - columns = None # type: Sequence[Column] + columns = None # type: typing.Sequence[Column] keyctx = "grideditor" def __init__( @@ -501,8 +502,8 @@ class FocusEditor(urwid.WidgetWrap, layoutwidget.LayoutWidget): def key_responder(self): return self._w - def view_popping(self): - self.call(self._w, "view_popping") + def layout_popping(self): + self.call(self._w, "layout_popping") def focus_changed(self): if self.master.view.focus.flow: diff --git a/mitmproxy/tools/console/grideditor/editors.py b/mitmproxy/tools/console/grideditor/editors.py index 511e246e..c6592960 100644 --- a/mitmproxy/tools/console/grideditor/editors.py +++ b/mitmproxy/tools/console/grideditor/editors.py @@ -9,7 +9,6 @@ from mitmproxy.tools.console.grideditor import col_text from mitmproxy.tools.console.grideditor import col_bytes from mitmproxy.tools.console.grideditor import col_subgrid from mitmproxy.tools.console import signals -from mitmproxy.net.http import user_agents from mitmproxy.net.http import Headers diff --git a/mitmproxy/tools/console/help.py b/mitmproxy/tools/console/help.py index edfae5f2..6b843e36 100644 --- a/mitmproxy/tools/console/help.py +++ b/mitmproxy/tools/console/help.py @@ -1,39 +1,71 @@ -import platform - import urwid from mitmproxy import flowfilter from mitmproxy.tools.console import common from mitmproxy.tools.console import layoutwidget +from mitmproxy.tools.console import tabs -from mitmproxy import version - -footer = [ - ("heading", 'mitmproxy {} (Python {}) '.format(version.VERSION, platform.python_version())), - ('heading_key', "q"), ":back ", -] - -class HelpView(urwid.ListBox, layoutwidget.LayoutWidget): +class HelpView(tabs.Tabs, layoutwidget.LayoutWidget): title = "Help" keyctx = "help" - def __init__(self, help_context): - urwid.ListBox.__init__( - self, - self.helptext() + def __init__(self, master): + self.master = master + self.helpctx = "" + super().__init__( + [ + [self.keybindings_title, self.keybindings], + [self.filtexp_title, self.filtexp], + ] ) - def helptext(self): - text = [] + def keybindings_title(self): + return "Key Bindings" - text.append(urwid.Text([("head", "\n\nFilter expressions:\n")])) - text.extend(common.format_keyvals(flowfilter.help, key="key", val="text", indent=4)) + def format_keys(self, binds): + kvs = [] + for b in binds: + k = b.key + if b.key == " ": + k = "space" + kvs.append((k, b.command)) + return common.format_keyvals(kvs) + + def keybindings(self): + text = [ + urwid.Text( + [ + ("title", "Keybindings for this view") + ] + ) + ] + if self.helpctx: + text.extend(self.format_keys(self.master.keymap.list(self.helpctx))) text.append( urwid.Text( [ "\n", + ("title", "Global Keybindings"), + ] + ) + ) + + text.extend(self.format_keys(self.master.keymap.list("global"))) + + return urwid.ListBox(text) + + def filtexp_title(self): + return "Filter Expressions" + + def filtexp(self): + text = [] + text.extend(common.format_keyvals(flowfilter.help, key="key", val="text", indent=4)) + text.append( + urwid.Text( + [ + "\n", ("text", " Regexes are Python-style.\n"), ("text", " Regexes can be specified as quoted strings.\n"), ("text", " Header matching (~h, ~hq, ~hs) is against a string of the form \"name: value\".\n"), @@ -51,11 +83,11 @@ class HelpView(urwid.ListBox, layoutwidget.LayoutWidget): text.extend( common.format_keyvals(examples, key="key", val="text", indent=4) ) - return text - - def keypress(self, size, key): - if key == "m_start": - self.set_focus(0) - elif key == "m_end": - self.set_focus(len(self.body.contents)) - return urwid.ListBox.keypress(self, size, key) + return urwid.ListBox(text) + + def layout_pushed(self, prev): + """ + We are just about to push a window onto the stack. + """ + self.helpctx = prev.keyctx + self.show() diff --git a/mitmproxy/tools/console/keymap.py b/mitmproxy/tools/console/keymap.py index 62e2dcfb..43a31530 100644 --- a/mitmproxy/tools/console/keymap.py +++ b/mitmproxy/tools/console/keymap.py @@ -49,6 +49,11 @@ class Keymap: return self.keys[context].get(key, None) return None + def list(self, context: str) -> typing.Sequence[Binding]: + b = [b for b in self.bindings if context in b.contexts] + b.sort(key=lambda x: x.key) + return b + def handle(self, context: str, key: str) -> typing.Optional[str]: """ Returns the key if it has not been handled, or None. diff --git a/mitmproxy/tools/console/layoutwidget.py b/mitmproxy/tools/console/layoutwidget.py index 27e270a0..65332238 100644 --- a/mitmproxy/tools/console/layoutwidget.py +++ b/mitmproxy/tools/console/layoutwidget.py @@ -6,7 +6,7 @@ class LayoutWidget: overlay must comply with this API. """ # Title is only required for windows, not overlay components - title = None + title = "" keyctx = "" def key_responder(self): @@ -29,8 +29,14 @@ class LayoutWidget: """ pass - def view_popping(self): + def layout_popping(self): """ We are just about to pop a window off the stack, or exit an overlay. """ pass + + def layout_pushed(self, prev): + """ + We have just pushed a window onto the stack. + """ + pass diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py index 54561134..89656a18 100644 --- a/mitmproxy/tools/console/options.py +++ b/mitmproxy/tools/console/options.py @@ -6,7 +6,6 @@ from typing import Optional, Sequence from mitmproxy import exceptions from mitmproxy import optmanager -from mitmproxy.tools.console import common from mitmproxy.tools.console import layoutwidget from mitmproxy.tools.console import signals from mitmproxy.tools.console import overlay diff --git a/mitmproxy/tools/console/overlay.py b/mitmproxy/tools/console/overlay.py index dbf69f2e..fecc7706 100644 --- a/mitmproxy/tools/console/overlay.py +++ b/mitmproxy/tools/console/overlay.py @@ -35,8 +35,8 @@ class SimpleOverlay(urwid.Overlay, layoutwidget.LayoutWidget): def view_changed(self): return self.widget.view_changed() - def view_popping(self): - return self.widget.view_popping() + def layout_popping(self): + return self.widget.layout_popping() class Choice(urwid.WidgetWrap): @@ -157,5 +157,5 @@ class OptionsOverlay(urwid.WidgetWrap, layoutwidget.LayoutWidget): def key_responder(self): return self.ge.key_responder() - def view_popping(self): - return self.ge.view_popping() + def layout_popping(self): + return self.ge.layout_popping() diff --git a/mitmproxy/tools/console/window.py b/mitmproxy/tools/console/window.py index 6a6a499c..43e5cceb 100644 --- a/mitmproxy/tools/console/window.py +++ b/mitmproxy/tools/console/window.py @@ -30,7 +30,7 @@ class WindowStack: flowview = flowview.FlowView(master), commands = commands.Commands(master), options = options.Options(master), - help = help.HelpView(None), + help = help.HelpView(master), eventlog = eventlog.EventLog(master), edit_focus_query = grideditor.QueryEditor(master), @@ -66,20 +66,21 @@ class WindowStack: def push(self, wname): if self.stack[-1] == wname: return + prev = self.top_window() self.stack.append(wname) + self.call("layout_pushed", prev) def pop(self, *args, **kwargs): """ Pop off the stack, return True if we're already at the top. """ + if not self.overlay and len(self.stack) == 1: + return True + self.call("layout_popping") if self.overlay: - self.call("view_popping") self.overlay = None - elif len(self.stack) > 1: - self.call("view_popping") - self.stack.pop() else: - return True + self.stack.pop() def call(self, name, *args, **kwargs): """ diff --git a/test/mitmproxy/tools/console/test_help.py b/test/mitmproxy/tools/console/test_help.py deleted file mode 100644 index 0ebc2d6a..00000000 --- a/test/mitmproxy/tools/console/test_help.py +++ /dev/null @@ -1,11 +0,0 @@ -import mitmproxy.tools.console.help as help - -from ....conftest import skip_appveyor - - -@skip_appveyor -class TestHelp: - - def test_helptext(self): - h = help.HelpView(None) - assert h.helptext() diff --git a/test/mitmproxy/tools/console/test_keymap.py b/test/mitmproxy/tools/console/test_keymap.py index 6a75800e..bbca4ac9 100644 --- a/test/mitmproxy/tools/console/test_keymap.py +++ b/test/mitmproxy/tools/console/test_keymap.py @@ -5,25 +5,28 @@ import pytest def test_bind(): - with taddons.context() as tctx: - km = keymap.Keymap(tctx.master) - km.executor = mock.Mock() + with taddons.context() as tctx: + km = keymap.Keymap(tctx.master) + km.executor = mock.Mock() - with pytest.raises(ValueError): - km.add("foo", "bar", ["unsupported"]) + with pytest.raises(ValueError): + km.add("foo", "bar", ["unsupported"]) - km.add("key", "str", ["options", "commands"]) - assert km.get("options", "key") - assert km.get("commands", "key") - assert not km.get("flowlist", "key") + km.add("key", "str", ["options", "commands"]) + assert km.get("options", "key") + assert km.get("commands", "key") + assert not km.get("flowlist", "key") + assert len((km.list("commands"))) == 1 - km.handle("unknown", "unknown") - assert not km.executor.called + km.handle("unknown", "unknown") + assert not km.executor.called - km.handle("options", "key") - assert km.executor.called + km.handle("options", "key") + assert km.executor.called - km.add("glob", "str", ["global"]) - km.executor = mock.Mock() - km.handle("options", "glob") - assert km.executor.called + km.add("glob", "str", ["global"]) + km.executor = mock.Mock() + km.handle("options", "glob") + assert km.executor.called + + assert len((km.list("global"))) == 1 |