aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2017-03-17 07:33:07 +1300
committerAldo Cortesi <aldo@corte.si>2017-03-19 10:32:22 +1300
commitbc67cee6870af7033e5741d8d21d5bd016dfd132 (patch)
tree7db702df35097dcafec1dc9611b67598199bb497
parent39659c752884ae31ccc14bbe247f3918f97bab9c (diff)
downloadmitmproxy-bc67cee6870af7033e5741d8d21d5bd016dfd132.tar.gz
mitmproxy-bc67cee6870af7033e5741d8d21d5bd016dfd132.tar.bz2
mitmproxy-bc67cee6870af7033e5741d8d21d5bd016dfd132.zip
console: sketch out look and feel of the new Options editor
-rw-r--r--mitmproxy/optmanager.py6
-rw-r--r--mitmproxy/tools/console/options.py343
2 files changed, 109 insertions, 240 deletions
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py
index 495354f4..86f833e4 100644
--- a/mitmproxy/optmanager.py
+++ b/mitmproxy/optmanager.py
@@ -36,7 +36,7 @@ class _Option:
self.typespec = typespec
self._default = default
self.value = unset
- self.help = help
+ self.help = textwrap.dedent(help or "").strip()
self.choices = choices
def __repr__(self):
@@ -397,9 +397,7 @@ def dump_defaults(opts):
txt += " Type %s." % t
txt = "\n".join(
- textwrap.wrap(
- textwrap.dedent(txt)
- )
+ textwrap.wrap(txt)
)
s.yaml_set_comment_before_after_key(k, before = "\n" + txt)
return ruamel.yaml.round_trip_dump(s)
diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py
index 79bb53c2..903bde5b 100644
--- a/mitmproxy/tools/console/options.py
+++ b/mitmproxy/tools/console/options.py
@@ -1,14 +1,9 @@
import urwid
+import blinker
+import textwrap
-from mitmproxy import contentviews
-from mitmproxy import optmanager
from mitmproxy.tools.console import common
-from mitmproxy.tools.console import grideditor
-from mitmproxy.tools.console import select
-from mitmproxy.tools.console import signals
-from mitmproxy.addons import replace
-from mitmproxy.addons import setheaders
footer = [
('heading_key', "enter/space"), ":toggle ",
@@ -31,251 +26,127 @@ def _mkhelp():
help_context = _mkhelp()
-def checker(opt, options):
- def _check():
- return options.has_changed(opt)
- return _check
+def fcol(s, width, attr):
+ s = str(s)
+ return (
+ "fixed",
+ width,
+ urwid.Text((attr, s))
+ )
-class Options(urwid.WidgetWrap):
+option_focus_change = blinker.Signal()
- def __init__(self, master):
- self.master = master
- self.lb = select.Select(
- [
- select.Heading("Traffic Manipulation"),
- select.Option(
- "Header Set Patterns",
- "H",
- checker("setheaders", master.options),
- self.setheaders
- ),
- select.Option(
- "Ignore Patterns",
- "I",
- checker("ignore_hosts", master.options),
- self.ignore_hosts
- ),
- select.Option(
- "Replacement Patterns",
- "R",
- checker("replacements", master.options),
- self.replacepatterns
- ),
- select.Option(
- "Scripts",
- "S",
- checker("scripts", master.options),
- self.scripts
- ),
- select.Heading("Interface"),
- select.Option(
- "Default Display Mode",
- "M",
- checker("default_contentview", master.options),
- self.default_displaymode
- ),
- select.Option(
- "Palette",
- "P",
- checker("console_palette", master.options),
- self.palette
- ),
- select.Option(
- "Show Host",
- "w",
- checker("showhost", master.options),
- master.options.toggler("showhost")
- ),
+class OptionItem(urwid.WidgetWrap):
+ def __init__(self, master, opt, focused, namewidth):
+ self.master, self.opt, self.focused = master, opt, focused
+ self.namewidth = namewidth
+ w = self.get_text()
+ urwid.WidgetWrap.__init__(self, w)
- select.Heading("Network"),
- select.Option(
- "Upstream Certs",
- "U",
- checker("upstream_cert", master.options),
- master.options.toggler("upstream_cert")
- ),
- select.Option(
- "TCP Proxying",
- "T",
- checker("tcp_hosts", master.options),
- self.tcp_hosts
- ),
- select.Option(
- "Don't Verify SSL/TLS Certificates",
- "V",
- checker("ssl_insecure", master.options),
- master.options.toggler("ssl_insecure")
- ),
+ def get_text(self):
+ val = self.opt.current()
+ if self.opt.typespec == bool:
+ displayval = "true" if val else "false"
+ elif val is None:
+ displayval = ""
+ else:
+ displayval = str(val)
- select.Heading("Utility"),
- select.Option(
- "Anti-Cache",
- "a",
- checker("anticache", master.options),
- master.options.toggler("anticache")
- ),
- select.Option(
- "Anti-Compression",
- "o",
- checker("anticomp", master.options),
- master.options.toggler("anticomp")
- ),
- select.Option(
- "Kill Extra",
- "x",
- checker("replay_kill_extra", master.options),
- master.options.toggler("replay_kill_extra")
- ),
- select.Option(
- "No Refresh",
- "f",
- checker("refresh_server_playback", master.options),
- master.options.toggler("refresh_server_playback")
- ),
- select.Option(
- "Sticky Auth",
- "A",
- checker("stickyauth", master.options),
- self.sticky_auth
- ),
- select.Option(
- "Sticky Cookies",
- "t",
- checker("stickycookie", master.options),
- self.sticky_cookie
+ changed = self.master.options.has_changed(self.opt.name)
+ namestyle = "option_selected" if self.focused else "title"
+ valstyle = "option_active" if changed else "text"
+ return urwid.Columns(
+ [
+ (
+ self.namewidth,
+ urwid.Text([(namestyle, self.opt.name.ljust(self.namewidth))])
),
- ]
- )
- title = urwid.Text("Options")
- title = urwid.Padding(title, align="left", width=("relative", 100))
- title = urwid.AttrWrap(title, "heading")
- w = urwid.Frame(
- self.lb,
- header = title
- )
- super().__init__(w)
-
- self.master.loop.widget.footer.update("")
- signals.update_settings.connect(self.sig_update_settings)
- master.options.changed.connect(self.sig_update_settings)
-
- def sig_update_settings(self, sender, updated=None):
- self.lb.walker._modified()
-
- def keypress(self, size, key):
- if key == "C":
- self.clearall()
- return None
- if key == "W":
- self.save()
- return None
- return super().keypress(size, key)
-
- def do_save(self, path):
- optmanager.save(self.master.options, path)
- return "Saved"
-
- def save(self):
- signals.status_prompt_path.send(
- prompt = "Save options to file",
- callback = self.do_save
+ urwid.Text([(valstyle, displayval)])
+ ],
+ dividechars=2
)
- def clearall(self):
- self.master.options.reset()
- signals.update_settings.send(self)
- signals.status_message.send(
- message = "Options cleared",
- expire = 1
- )
+ def selectable(self):
+ return True
- def setheaders(self):
- data = []
- for d in self.master.options.setheaders:
- if isinstance(d, str):
- data.append(setheaders.parse_setheader(d))
- else:
- data.append(d)
- self.master.view_grideditor(
- grideditor.SetHeadersEditor(
- self.master,
- data,
- self.master.options.setter("setheaders")
- )
- )
+ def keypress(self, xxx_todo_changeme, key):
+ key = common.shortcuts(key)
+ return key
- def tcp_hosts(self):
- self.master.view_grideditor(
- grideditor.HostPatternEditor(
- self.master,
- self.master.options.tcp_hosts,
- self.master.options.setter("tcp_hosts")
- )
- )
- def ignore_hosts(self):
- self.master.view_grideditor(
- grideditor.HostPatternEditor(
- self.master,
- self.master.options.ignore_hosts,
- self.master.options.setter("ignore_hosts")
- )
- )
+class OptionListWalker(urwid.ListWalker):
+ def __init__(self, master):
+ self.master = master
+ self.index = 0
+ self.opts = sorted(master.options.keys())
+ self.maxlen = max(len(i) for i in self.opts)
+
+ # Trigger a help text update for the first selected item
+ first = self.master.options._options[self.opts[0]]
+ option_focus_change.send(first.help)
+
+ def _get(self, pos):
+ name = self.opts[pos]
+ opt = self.master.options._options[name]
+ return OptionItem(self.master, opt, pos == self.index, self.maxlen)
+
+ def get_focus(self):
+ return self._get(self.index), self.index
+
+ def set_focus(self, index):
+ name = self.opts[index]
+ opt = self.master.options._options[name]
+ self.index = index
+ option_focus_change.send(opt.help)
+
+ def get_next(self, pos):
+ if pos >= len(self.opts) - 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 OptionsList(urwid.ListBox):
+ def __init__(self, master):
+ self.master = master
+ super().__init__(OptionListWalker(master))
- def replacepatterns(self):
- data = []
- for d in self.master.options.replacements:
- if isinstance(d, str):
- data.append(replace.parse_hook(d))
- else:
- data.append(d)
- self.master.view_grideditor(
- grideditor.ReplaceEditor(
- self.master,
- data,
- self.master.options.setter("replacements")
- )
- )
- def scripts(self):
- def edit_scripts(scripts):
- self.master.options.scripts = [x[0] for x in scripts]
- self.master.view_grideditor(
- grideditor.ScriptEditor(
- self.master,
- [[i] for i in self.master.options.scripts],
- edit_scripts
- )
- )
+class OptionHelp(urwid.Frame):
+ def __init__(self):
+ h = urwid.Text("Option Help")
+ h = urwid.Padding(h, align="left", width=("relative", 100))
+ h = urwid.AttrWrap(h, "heading")
+ super().__init__(self.widget(""), header=h)
+ option_focus_change.connect(self.sig_mod)
- def default_displaymode(self):
- signals.status_prompt_onekey.send(
- prompt = "Global default display mode",
- keys = contentviews.view_prompts,
- callback = self.change_default_display_mode
- )
+ def selectable(self):
+ return False
- def change_default_display_mode(self, t):
- v = contentviews.get_by_shortcut(t)
- self.master.options.default_contentview = v.name
- if self.master.view.focus.flow:
- signals.flow_change.send(self, flow = self.master.view.focus.flow)
-
- def sticky_auth(self):
- signals.status_prompt.send(
- prompt = "Sticky auth filter",
- text = self.master.options.stickyauth,
- callback = self.master.options.setter("stickyauth")
+ def widget(self, txt):
+ return urwid.ListBox(
+ [urwid.Text(i) for i in textwrap.wrap(txt)]
)
- def sticky_cookie(self):
- signals.status_prompt.send(
- prompt = "Sticky cookie filter",
- text = self.master.options.stickycookie,
- callback = self.master.options.setter("stickycookie")
- )
+ def sig_mod(self, txt):
+ self.set_body(self.widget(txt))
+
- def palette(self):
- self.master.view_palette_picker()
+class Options(urwid.Pile):
+ def __init__(self, master):
+ oh = OptionHelp()
+ super().__init__(
+ [
+ OptionsList(master),
+ (5, oh),
+ ]
+ )
+ self.master = master