console options: add an overlay grid editor for sequence options

This commit is contained in:
Aldo Cortesi 2017-03-19 10:25:07 +13:00 committed by Aldo Cortesi
parent 4e24c95a61
commit 49b0a67eb9
7 changed files with 84 additions and 18 deletions

View File

@ -182,12 +182,12 @@ class GridWalker(urwid.ListWalker):
self.edit_row = GridRow(
self.focus_col, True, self.editor, self.lst[self.focus]
)
self.editor.master.loop.widget.footer.update(FOOTER_EDITING)
signals.footer_help.send(self, helptext=FOOTER_EDITING)
self._modified()
def stop_edit(self):
if self.edit_row:
self.editor.master.loop.widget.footer.update(FOOTER)
signals.footer_help.send(self, helptext=FOOTER)
try:
val = self.edit_row.edit_col.get_data()
except ValueError:
@ -276,6 +276,8 @@ class GridEditor(urwid.WidgetWrap):
first_width = max(len(r), first_width)
self.first_width = min(first_width, FIRST_WIDTH_MAX)
title = None
if self.title:
title = urwid.Text(self.title)
title = urwid.Padding(title, align="left", width=("relative", 100))
title = urwid.AttrWrap(title, "heading")
@ -297,10 +299,10 @@ class GridEditor(urwid.WidgetWrap):
self.lb = GridListBox(self.walker)
w = urwid.Frame(
self.lb,
header=urwid.Pile([title, h])
header=urwid.Pile([title, h]) if title else None
)
super().__init__(w)
self.master.loop.widget.footer.update("")
signals.footer_help.send(self, helptext="")
self.show_empty_msg()
def show_empty_msg(self):

View File

@ -245,3 +245,20 @@ class SetCookieEditor(base.GridEditor):
]
)
return vals
class OptionsEditor(base.GridEditor):
title = None
columns = [
col_text.Column("")
]
def __init__(self, master, name, vals):
self.name = name
super().__init__(master, [[i] for i in vals], self.callback)
def callback(self, vals):
setattr(self.master.options, self.name, [i[0] for i in vals])
def is_error(self, col, val):
pass

View File

@ -1,7 +1,7 @@
import urwid
import blinker
import textwrap
from typing import Optional
from typing import Optional, Sequence
from mitmproxy import exceptions
from mitmproxy.tools.console import common
@ -213,6 +213,16 @@ class OptionsList(urwid.ListBox):
self.master.options.setter(foc.opt.name)
)
)
elif foc.opt.typespec == Sequence[str]:
self.master.overlay(
overlay.OptionsOverlay(
self.master,
foc.opt.name,
foc.opt.current()
)
)
else:
raise NotImplementedError()
return super().keypress(size, key)
@ -269,4 +279,3 @@ class Options(urwid.Pile):
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

@ -1,6 +1,10 @@
import math
import urwid
from mitmproxy.tools.console import common
from mitmproxy.tools.console import signals
import urwid
from mitmproxy.tools.console import grideditor
class SimpleOverlay(urwid.Overlay):
@ -15,9 +19,11 @@ class SimpleOverlay(urwid.Overlay):
)
def keypress(self, size, key):
key = super().keypress(size, key)
if key == "esc":
signals.pop_view_state.send(self)
return super().keypress(size, key)
else:
return key
class Choice(urwid.WidgetWrap):
@ -98,3 +104,21 @@ class Chooser(urwid.WidgetWrap):
self.callback(self.choices[self.walker.index])
signals.pop_view_state.send(self)
return super().keypress(size, key)
class OptionsOverlay(urwid.WidgetWrap):
def __init__(self, master, name, vals):
cols, rows = master.ui.get_cols_rows()
super().__init__(
urwid.AttrWrap(
urwid.LineBox(
urwid.BoxAdapter(
grideditor.OptionsEditor(master, name, vals),
math.ceil(rows * 0.5)
),
title="text"
),
"background"
)
)
self.width = math.ceil(cols * 0.8)

View File

@ -30,6 +30,9 @@ call_in = blinker.Signal()
# Focus the body, footer or header of the main window
focus = blinker.Signal()
# Focus the body, footer or header of the main window
footer_help = blinker.Signal()
# Fired when settings change
update_settings = blinker.Signal()

View File

@ -5,7 +5,6 @@ import urwid
from mitmproxy.tools.console import common
from mitmproxy.tools.console import pathedit
from mitmproxy.tools.console import signals
from mitmproxy.utils import human
class PromptPath:
@ -143,10 +142,15 @@ class StatusBar(urwid.WidgetWrap):
super().__init__(urwid.Pile([self.ib, self.master.ab]))
signals.update_settings.connect(self.sig_update)
signals.flowlist_change.connect(self.sig_update)
signals.footer_help.connect(self.sig_footer_help)
master.options.changed.connect(self.sig_update)
master.view.focus.sig_change.connect(self.sig_update)
self.redraw()
def sig_footer_help(self, sender, helptext):
self.helptext = helptext
self.redraw()
def sig_update(self, sender, updated=None):
self.redraw()
@ -281,10 +285,5 @@ class StatusBar(urwid.WidgetWrap):
]), "heading")
self.ib._w = status
def update(self, text):
self.helptext = text
self.redraw()
self.master.loop.draw_screen()
def selectable(self):
return True

View File

@ -140,6 +140,18 @@ class Rec():
def test_subscribe():
o = TO()
r = Rec()
# pytest.raises keeps a reference here that interferes with the cleanup test
# further down.
try:
o.subscribe(r, ["unknown"])
except exceptions.OptionsError:
pass
else:
raise AssertionError
assert len(o.changed.receivers) == 0
o.subscribe(r, ["two"])
o.one = 2
assert not r.called