aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2017-06-13 11:48:08 +1200
committerAldo Cortesi <aldo@corte.si>2017-06-13 11:48:08 +1200
commitba49b556843a7564b5a2a9bd49b206e42d8327c9 (patch)
tree39c739c7e19a0ff1afb3066049a525005ac28b88
parent88832f92a35cacc0d80bffa477d9ffb0e2bee97e (diff)
downloadmitmproxy-ba49b556843a7564b5a2a9bd49b206e42d8327c9.tar.gz
mitmproxy-ba49b556843a7564b5a2a9bd49b206e42d8327c9.tar.bz2
mitmproxy-ba49b556843a7564b5a2a9bd49b206e42d8327c9.zip
console: key binding viewer
Read-only for now.
-rw-r--r--mitmproxy/tools/console/commands.py10
-rw-r--r--mitmproxy/tools/console/defaultkeys.py1
-rw-r--r--mitmproxy/tools/console/flowlist.py2
-rw-r--r--mitmproxy/tools/console/keybindings.py146
-rw-r--r--mitmproxy/tools/console/keymap.py2
-rw-r--r--mitmproxy/tools/console/master.py5
-rw-r--r--mitmproxy/tools/console/window.py2
-rw-r--r--test/mitmproxy/addons/test_view.py2
8 files changed, 157 insertions, 13 deletions
diff --git a/mitmproxy/tools/console/commands.py b/mitmproxy/tools/console/commands.py
index e4535314..20efcee3 100644
--- a/mitmproxy/tools/console/commands.py
+++ b/mitmproxy/tools/console/commands.py
@@ -6,16 +6,6 @@ from mitmproxy.tools.console import signals
HELP_HEIGHT = 5
-
-def fcol(s, width, attr):
- s = str(s)
- return (
- "fixed",
- width,
- urwid.Text((attr, s))
- )
-
-
command_focus_change = blinker.Signal()
diff --git a/mitmproxy/tools/console/defaultkeys.py b/mitmproxy/tools/console/defaultkeys.py
index dbc170bc..cfefd533 100644
--- a/mitmproxy/tools/console/defaultkeys.py
+++ b/mitmproxy/tools/console/defaultkeys.py
@@ -3,6 +3,7 @@ def map(km):
km.add(":", "console.command ''", ["global"], "Command prompt")
km.add("?", "console.view.help", ["global"], "View help")
km.add("C", "console.view.commands", ["global"], "View commands")
+ km.add("K", "console.view.keybindings", ["global"], "View key bindings")
km.add("O", "console.view.options", ["global"], "View options")
km.add("E", "console.view.eventlog", ["global"], "View event log")
km.add("Q", "console.exit", ["global"], "Exit immediately")
diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py
index f00ed9fa..852c5163 100644
--- a/mitmproxy/tools/console/flowlist.py
+++ b/mitmproxy/tools/console/flowlist.py
@@ -30,7 +30,7 @@ class FlowItem(urwid.WidgetWrap):
self.master.commands.call("console.view.flow @focus")
return True
- def keypress(self, xxx_todo_changeme, key):
+ def keypress(self, size, key):
return key
diff --git a/mitmproxy/tools/console/keybindings.py b/mitmproxy/tools/console/keybindings.py
new file mode 100644
index 00000000..6bd13429
--- /dev/null
+++ b/mitmproxy/tools/console/keybindings.py
@@ -0,0 +1,146 @@
+import urwid
+import blinker
+import textwrap
+from mitmproxy.tools.console import layoutwidget
+
+HELP_HEIGHT = 5
+
+
+keybinding_focus_change = blinker.Signal()
+
+
+class KeyItem(urwid.WidgetWrap):
+ def __init__(self, walker, binding, focused):
+ self.walker, self.binding, self.focused = walker, binding, focused
+ super().__init__(None)
+ self._w = self.get_widget()
+
+ def get_widget(self):
+ cmd = textwrap.dedent(self.binding.command).strip()
+ parts = [
+ (4, urwid.Text([("focus", ">> " if self.focused else " ")])),
+ (10, urwid.Text([("title", self.binding.key)])),
+ (12, urwid.Text([("highlight", "\n".join(self.binding.contexts))])),
+ urwid.Text([("text", cmd)]),
+ ]
+ return urwid.Columns(parts)
+
+ def get_edit_text(self):
+ return self._w[1].get_edit_text()
+
+ def selectable(self):
+ return True
+
+ def keypress(self, size, key):
+ return key
+
+
+class KeyListWalker(urwid.ListWalker):
+ def __init__(self, master):
+ self.master = master
+
+ self.index = 0
+ self.focusobj = None
+ self.bindings = list(master.keymap.list("all"))
+ self.set_focus(0)
+
+ def get_edit_text(self):
+ return self.focus_obj.get_edit_text()
+
+ def _get(self, pos):
+ binding = self.bindings[pos]
+ return KeyItem(self, binding, pos == self.index)
+
+ def get_focus(self):
+ return self.focus_obj, self.index
+
+ def set_focus(self, index):
+ binding = self.bindings[index]
+ self.index = index
+ self.focus_obj = self._get(self.index)
+ keybinding_focus_change.send(binding.help or "")
+
+ def get_next(self, pos):
+ if pos >= len(self.bindings) - 1:
+ return None, None
+ pos = pos + 1
+ return self._get(pos), pos
+
+ def get_prev(self, pos):
+ pos = pos - 1
+ if pos < 0:
+ return None, None
+ return self._get(pos), pos
+
+
+class KeyList(urwid.ListBox):
+ def __init__(self, master):
+ self.master = master
+ self.walker = KeyListWalker(master)
+ super().__init__(self.walker)
+
+ def keypress(self, size, key):
+ if key == "m_select":
+ foc, idx = self.get_focus()
+ # Act here
+ elif key == "m_start":
+ self.set_focus(0)
+ self.walker._modified()
+ elif key == "m_end":
+ self.set_focus(len(self.walker.bindings) - 1)
+ self.walker._modified()
+ return super().keypress(size, key)
+
+
+class KeyHelp(urwid.Frame):
+ def __init__(self, master):
+ self.master = master
+ super().__init__(self.widget(""))
+ self.set_active(False)
+ keybinding_focus_change.connect(self.sig_mod)
+
+ def set_active(self, val):
+ h = urwid.Text("Key Binding Help")
+ style = "heading" if val else "heading_inactive"
+ self.header = urwid.AttrWrap(h, style)
+
+ def widget(self, txt):
+ cols, _ = self.master.ui.get_cols_rows()
+ return urwid.ListBox(
+ [urwid.Text(i) for i in textwrap.wrap(txt, cols)]
+ )
+
+ def sig_mod(self, txt):
+ self.set_body(self.widget(txt))
+
+
+class KeyBindings(urwid.Pile, layoutwidget.LayoutWidget):
+ title = "Key Bindings"
+ keyctx = "keybindings"
+
+ def __init__(self, master):
+ oh = KeyHelp(master)
+ super().__init__(
+ [
+ KeyList(master),
+ (HELP_HEIGHT, oh),
+ ]
+ )
+ self.master = master
+
+ def keypress(self, size, key):
+ if key == "m_next":
+ self.focus_position = (
+ self.focus_position + 1
+ ) % len(self.widget_list)
+ self.widget_list[1].set_active(self.focus_position == 1)
+ key = None
+
+ # This is essentially a copypasta from urwid.Pile's keypress handler.
+ # So much for "closed for modification, but open for extension".
+ item_rows = None
+ if len(size) == 2:
+ item_rows = self.get_item_rows(size, focus = True)
+ i = self.widget_list.index(self.focus_item)
+ tsize = self.get_item_size(size, i, True, item_rows)
+ return self.focus_item.keypress(tsize, key)
diff --git a/mitmproxy/tools/console/keymap.py b/mitmproxy/tools/console/keymap.py
index b904f706..4d8c3ec2 100644
--- a/mitmproxy/tools/console/keymap.py
+++ b/mitmproxy/tools/console/keymap.py
@@ -54,7 +54,7 @@ class Keymap:
return None
def list(self, context: str) -> typing.Sequence[Binding]:
- b = [b for b in self.bindings if context in b.contexts]
+ b = [b for b in self.bindings if context in b.contexts or context == "all"]
b.sort(key=lambda x: x.key)
return b
diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py
index 64e1a444..315fad94 100644
--- a/mitmproxy/tools/console/master.py
+++ b/mitmproxy/tools/console/master.py
@@ -240,6 +240,11 @@ class ConsoleAddon:
"""
signals.status_prompt_command.send(partial=" ".join(partial)) # type: ignore
+ @command.command("console.view.keybindings")
+ def view_keybindings(self) -> None:
+ """View the commands list."""
+ self.master.switch_view("keybindings")
+
@command.command("console.view.commands")
def view_commands(self) -> None:
"""View the commands list."""
diff --git a/mitmproxy/tools/console/window.py b/mitmproxy/tools/console/window.py
index 43e5cceb..6145b645 100644
--- a/mitmproxy/tools/console/window.py
+++ b/mitmproxy/tools/console/window.py
@@ -4,6 +4,7 @@ from mitmproxy.tools.console import statusbar
from mitmproxy.tools.console import flowlist
from mitmproxy.tools.console import flowview
from mitmproxy.tools.console import commands
+from mitmproxy.tools.console import keybindings
from mitmproxy.tools.console import options
from mitmproxy.tools.console import overlay
from mitmproxy.tools.console import help
@@ -29,6 +30,7 @@ class WindowStack:
flowlist = flowlist.FlowListBox(master),
flowview = flowview.FlowView(master),
commands = commands.Commands(master),
+ keybindings = keybindings.KeyBindings(master),
options = options.Options(master),
help = help.HelpView(master),
eventlog = eventlog.EventLog(master),
diff --git a/test/mitmproxy/addons/test_view.py b/test/mitmproxy/addons/test_view.py
index 03b2c8dd..40136f1f 100644
--- a/test/mitmproxy/addons/test_view.py
+++ b/test/mitmproxy/addons/test_view.py
@@ -265,7 +265,7 @@ def test_duplicate():
def test_remove():
v = view.View()
with taddons.context():
- f = [tflow.tflow(), tflow.tflow() ]
+ f = [tflow.tflow(), tflow.tflow()]
v.add(f)
assert len(v) == 2
v.remove(f)