console: options/help pane switching, toggle bools with enter

This commit is contained in:
Aldo Cortesi 2017-03-17 11:16:34 +13:00
parent 8130b9880a
commit d759150734
2 changed files with 77 additions and 31 deletions

View File

@ -43,8 +43,9 @@ class Options(optmanager.OptManager):
self.add_option(
"onboarding_host", str, APP_HOST,
"""
Domain to serve the onboarding app from. For transparent mode, use
an IP when a DNS entry for the app domain is not present. """
Onboarding app domain. For transparent mode, use an IP when a DNS
entry for the app domain is not present.
"""
)
self.add_option(
"onboarding_port", int, APP_PORT,
@ -72,9 +73,9 @@ class Options(optmanager.OptManager):
self.add_option(
"keepserving", bool, False,
"""
Instructs mitmdump to continue serving after client playback, server
playback or file read. This option is ignored by interactive tools,
which always keep serving.
Continue serving after client playback, server playback or file
read. This option is ignored by interactive tools, which always keep
serving.
"""
)
self.add_option(
@ -84,8 +85,8 @@ class Options(optmanager.OptManager):
self.add_option(
"server_replay_nopop", bool, False,
"""
Disable response pop from response flow. This makes it possible to
replay same response multiple times.
Don't remove flows from server replay state after use. This makes it
possible to replay same response multiple times.
"""
)
self.add_option(
@ -190,11 +191,10 @@ class Options(optmanager.OptManager):
self.add_option(
"proxyauth", Optional[str], None,
"""
Require authentication before proxying requests. If the value is
"any", we prompt for authentication, but permit any values. If it
starts with an "@", it is treated as a path to an Apache htpasswd
file. If its is of the form "username:password", it is treated as a
single-user credential.
Require proxy authentication. Value may be "any" to require
authenticaiton but accept any credentials, start with "@" to specify
a path to an Apache htpasswd file, or be of the form
"username:password".
"""
)
self.add_option(
@ -218,12 +218,12 @@ class Options(optmanager.OptManager):
self.add_option(
"certs", Sequence[str], [],
"""
SSL certificates. SPEC is of the form "[domain=]path". The
domain may include a wildcard, and is equal to "*" if not specified.
The file at path is a certificate in PEM format. If a private key is
included in the PEM, it is used, else the default key in the conf
dir is used. The PEM file should contain the full certificate chain,
with the leaf certificate as the first entry.
SSL certificates of the form "[domain=]path". The domain may include
a wildcard, and is equal to "*" if not specified. The file at path
is a certificate in PEM format. If a private key is included in the
PEM, it is used, else the default key in the conf dir is used. The
PEM file should contain the full certificate chain, with the leaf
certificate as the first entry.
"""
)
self.add_option(

View File

@ -55,15 +55,22 @@ class OptionItem(urwid.WidgetWrap):
displayval = str(val)
changed = self.master.options.has_changed(self.opt.name)
namestyle = "option_selected" if self.focused else "title"
valstyle = "option_active" if changed else "text"
if self.focused:
valstyle = "option_active_selected" if changed else "option_selected"
else:
valstyle = "option_active" if changed else "text"
return urwid.Columns(
[
(
self.namewidth,
urwid.Text([(namestyle, self.opt.name.ljust(self.namewidth))])
urwid.Text([("title", self.opt.name.ljust(self.namewidth))])
),
urwid.Text([(valstyle, displayval)])
urwid.AttrMap(
urwid.Padding(
urwid.Text([(valstyle, displayval)])
),
valstyle
)
],
dividechars=2
)
@ -72,8 +79,15 @@ class OptionItem(urwid.WidgetWrap):
return True
def keypress(self, xxx_todo_changeme, key):
key = common.shortcuts(key)
return key
if key == "enter":
if self.opt.typespec == bool:
setattr(
self.master.options,
self.opt.name,
not self.opt.current()
)
else:
return key
class OptionListWalker(urwid.ListWalker):
@ -86,6 +100,10 @@ class OptionListWalker(urwid.ListWalker):
# Trigger a help text update for the first selected item
first = self.master.options._options[self.opts[0]]
option_focus_change.send(first.help)
self.master.options.changed.connect(self.sig_mod)
def sig_mod(self, *args, **kwargs):
self._modified()
def _get(self, pos):
name = self.opts[pos]
@ -121,19 +139,28 @@ class OptionsList(urwid.ListBox):
class OptionHelp(urwid.Frame):
def __init__(self):
def __init__(self, master):
self.master = master
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)
self.inactive_header = urwid.AttrWrap(h, "heading_inactive")
self.active_header = urwid.AttrWrap(h, "heading")
super().__init__(self.widget(""), header=self.inactive_header)
option_focus_change.connect(self.sig_mod)
def selectable(self):
return False
def active(self, val):
if val:
self.header = self.active_header
else:
self.header = self.inactive_header
def widget(self, txt):
cols, _ = self.master.ui.get_cols_rows()
return urwid.ListBox(
[urwid.Text(i) for i in textwrap.wrap(txt)]
[urwid.Text(i) for i in textwrap.wrap(txt, cols)]
)
def sig_mod(self, txt):
@ -142,7 +169,7 @@ class OptionHelp(urwid.Frame):
class Options(urwid.Pile):
def __init__(self, master):
oh = OptionHelp()
oh = OptionHelp(master)
super().__init__(
[
OptionsList(master),
@ -150,3 +177,22 @@ class Options(urwid.Pile):
]
)
self.master = master
def keypress(self, size, key):
key = common.shortcuts(key)
if key == "tab":
self.focus_position = (
self.focus_position + 1
) % len(self.widget_list)
self.widget_list[1].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)