codekingpro/portable-devtools
114k
1import textwrap2 3import urwid4 5from mitmproxy.tools.console import layoutwidget6from mitmproxy.tools.console import signals7from mitmproxy.utils import signals as utils_signals8 9HELP_HEIGHT = 510 11 12class KeyItem(urwid.WidgetWrap):13 def __init__(self, walker, binding, focused):14 self.walker, self.binding, self.focused = walker, binding, focused15 super().__init__(self.get_widget())16 17 def get_widget(self):18 cmd = textwrap.dedent(self.binding.command).strip()19 parts = [20 (4, urwid.Text([("focus", ">> " if self.focused else " ")])),21 (10, urwid.Text([("title", self.binding.key)])),22 (12, urwid.Text([("highlight", "\n".join(self.binding.contexts))])),23 urwid.Text([("text", cmd)]),24 ]25 return urwid.Columns(parts)26 27 def get_edit_text(self):28 return self._w[1].get_edit_text()29 30 def selectable(self):31 return True32 33 def keypress(self, size, key):34 return key35 36 37class KeyListWalker(urwid.ListWalker):38 def __init__(self, master, keybinding_focus_change):39 self.keybinding_focus_change = keybinding_focus_change40 self.master = master41 42 self.index = 043 self.focusobj = None44 self.bindings = list(master.keymap.list("all"))45 self.set_focus(0)46 signals.keybindings_change.connect(self.sig_modified)47 48 def sig_modified(self):49 self.bindings = list(self.master.keymap.list("all"))50 self.set_focus(min(self.index, len(self.bindings) - 1))51 self._modified()52 53 def get_edit_text(self):54 return self.focus_obj.get_edit_text()55 56 def _get(self, pos):57 binding = self.bindings[pos]58 return KeyItem(self, binding, pos == self.index)59 60 def get_focus(self):61 return self.focus_obj, self.index62 63 def set_focus(self, index):64 binding = self.bindings[index]65 self.index = index66 self.focus_obj = self._get(self.index)67 self.keybinding_focus_change.send(binding.help or "")68 self._modified()69 70 def get_next(self, pos):71 if pos >= len(self.bindings) - 1:72 return None, None73 pos = pos + 174 return self._get(pos), pos75 76 def get_prev(self, pos):77 pos = pos - 178 if pos < 0:79 return None, None80 return self._get(pos), pos81 82 def positions(self, reverse=False):83 if reverse:84 return reversed(range(len(self.bindings)))85 else:86 return range(len(self.bindings))87 88 89class KeyList(urwid.ListBox):90 def __init__(self, master, keybinding_focus_change):91 self.master = master92 self.walker = KeyListWalker(master, keybinding_focus_change)93 super().__init__(self.walker)94 95 def keypress(self, size, key):96 if key == "m_select":97 foc, idx = self.get_focus()98 # Act here99 elif key == "m_start":100 self.set_focus(0)101 self.walker._modified()102 elif key == "m_end":103 self.set_focus(len(self.walker.bindings) - 1)104 self.walker._modified()105 return super().keypress(size, key)106 107 108class KeyHelp(urwid.Frame):109 def __init__(self, master, keybinding_focus_change):110 self.master = master111 super().__init__(self.widget(""))112 self.set_active(False)113 keybinding_focus_change.connect(self.sig_mod)114 115 def set_active(self, val):116 h = urwid.Text("Key Binding Help")117 style = "heading" if val else "heading_inactive"118 self.header = urwid.AttrMap(h, style)119 120 def widget(self, txt):121 cols, _ = self.master.ui.get_cols_rows()122 return urwid.ListBox([urwid.Text(i) for i in textwrap.wrap(txt, cols)])123 124 def sig_mod(self, txt):125 self.body = self.widget(txt)126 127 128class KeyBindings(urwid.Pile, layoutwidget.LayoutWidget):129 title = "Key Bindings"130 keyctx = "keybindings"131 focus_position: int132 133 def __init__(self, master):134 keybinding_focus_change = utils_signals.SyncSignal(lambda text: None)135 136 oh = KeyHelp(master, keybinding_focus_change)137 super().__init__(138 [139 KeyList(master, keybinding_focus_change),140 (HELP_HEIGHT, oh),141 ]142 )143 self.master = master144 145 def get_focused_binding(self):146 if self.focus_position != 0:147 return None148 f = self.contents[0][0]149 return f.walker.get_focus()[0].binding150 151 def keypress(self, size, key):152 if key == "m_next":153 self.focus_position = (self.focus_position + 1) % len(self.widget_list)154 self.contents[1][0].set_active(self.focus_position == 1)155 key = None156 157 # This is essentially a copypasta from urwid.Pile's keypress handler.158 # So much for "closed for modification, but open for extension".159 item_rows = None160 if len(size) == 2:161 item_rows = self.get_item_rows(size, focus=True)162 tsize = self.get_item_size(size, self.focus_position, True, item_rows)163 return self.focus.keypress(tsize, key)164 