console: key binding viewer

Read-only for now.
This commit is contained in:
Aldo Cortesi 2017-06-13 11:48:08 +12:00
parent 88832f92a3
commit ba49b55684
8 changed files with 157 additions and 13 deletions

View File

@ -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()

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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."""

View File

@ -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),

View File

@ -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)