aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/tools/console/commands.py1
-rw-r--r--mitmproxy/tools/console/flowlist.py1
-rw-r--r--mitmproxy/tools/console/grideditor/base.py17
-rw-r--r--mitmproxy/tools/console/grideditor/editors.py1
-rw-r--r--mitmproxy/tools/console/help.py84
-rw-r--r--mitmproxy/tools/console/keymap.py5
-rw-r--r--mitmproxy/tools/console/layoutwidget.py10
-rw-r--r--mitmproxy/tools/console/options.py1
-rw-r--r--mitmproxy/tools/console/overlay.py8
-rw-r--r--mitmproxy/tools/console/window.py13
-rw-r--r--test/mitmproxy/tools/console/test_help.py11
-rw-r--r--test/mitmproxy/tools/console/test_keymap.py37
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