console options: add an overlay grid editor for sequence options
This commit is contained in:
parent
4e24c95a61
commit
49b0a67eb9
|
@ -182,12 +182,12 @@ class GridWalker(urwid.ListWalker):
|
||||||
self.edit_row = GridRow(
|
self.edit_row = GridRow(
|
||||||
self.focus_col, True, self.editor, self.lst[self.focus]
|
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()
|
self._modified()
|
||||||
|
|
||||||
def stop_edit(self):
|
def stop_edit(self):
|
||||||
if self.edit_row:
|
if self.edit_row:
|
||||||
self.editor.master.loop.widget.footer.update(FOOTER)
|
signals.footer_help.send(self, helptext=FOOTER)
|
||||||
try:
|
try:
|
||||||
val = self.edit_row.edit_col.get_data()
|
val = self.edit_row.edit_col.get_data()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -276,9 +276,11 @@ class GridEditor(urwid.WidgetWrap):
|
||||||
first_width = max(len(r), first_width)
|
first_width = max(len(r), first_width)
|
||||||
self.first_width = min(first_width, FIRST_WIDTH_MAX)
|
self.first_width = min(first_width, FIRST_WIDTH_MAX)
|
||||||
|
|
||||||
title = urwid.Text(self.title)
|
title = None
|
||||||
title = urwid.Padding(title, align="left", width=("relative", 100))
|
if self.title:
|
||||||
title = urwid.AttrWrap(title, "heading")
|
title = urwid.Text(self.title)
|
||||||
|
title = urwid.Padding(title, align="left", width=("relative", 100))
|
||||||
|
title = urwid.AttrWrap(title, "heading")
|
||||||
|
|
||||||
headings = []
|
headings = []
|
||||||
for i, col in enumerate(self.columns):
|
for i, col in enumerate(self.columns):
|
||||||
|
@ -297,10 +299,10 @@ class GridEditor(urwid.WidgetWrap):
|
||||||
self.lb = GridListBox(self.walker)
|
self.lb = GridListBox(self.walker)
|
||||||
w = urwid.Frame(
|
w = urwid.Frame(
|
||||||
self.lb,
|
self.lb,
|
||||||
header=urwid.Pile([title, h])
|
header=urwid.Pile([title, h]) if title else None
|
||||||
)
|
)
|
||||||
super().__init__(w)
|
super().__init__(w)
|
||||||
self.master.loop.widget.footer.update("")
|
signals.footer_help.send(self, helptext="")
|
||||||
self.show_empty_msg()
|
self.show_empty_msg()
|
||||||
|
|
||||||
def show_empty_msg(self):
|
def show_empty_msg(self):
|
||||||
|
|
|
@ -245,3 +245,20 @@ class SetCookieEditor(base.GridEditor):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return vals
|
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
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import urwid
|
import urwid
|
||||||
import blinker
|
import blinker
|
||||||
import textwrap
|
import textwrap
|
||||||
from typing import Optional
|
from typing import Optional, Sequence
|
||||||
|
|
||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy.tools.console import common
|
from mitmproxy.tools.console import common
|
||||||
|
@ -213,6 +213,16 @@ class OptionsList(urwid.ListBox):
|
||||||
self.master.options.setter(foc.opt.name)
|
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)
|
return super().keypress(size, key)
|
||||||
|
|
||||||
|
|
||||||
|
@ -269,4 +279,3 @@ class Options(urwid.Pile):
|
||||||
i = self.widget_list.index(self.focus_item)
|
i = self.widget_list.index(self.focus_item)
|
||||||
tsize = self.get_item_size(size, i, True, item_rows)
|
tsize = self.get_item_size(size, i, True, item_rows)
|
||||||
return self.focus_item.keypress(tsize, key)
|
return self.focus_item.keypress(tsize, key)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
import math
|
||||||
|
|
||||||
|
import urwid
|
||||||
|
|
||||||
from mitmproxy.tools.console import common
|
from mitmproxy.tools.console import common
|
||||||
from mitmproxy.tools.console import signals
|
from mitmproxy.tools.console import signals
|
||||||
import urwid
|
from mitmproxy.tools.console import grideditor
|
||||||
|
|
||||||
|
|
||||||
class SimpleOverlay(urwid.Overlay):
|
class SimpleOverlay(urwid.Overlay):
|
||||||
|
@ -15,9 +19,11 @@ class SimpleOverlay(urwid.Overlay):
|
||||||
)
|
)
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
|
key = super().keypress(size, key)
|
||||||
if key == "esc":
|
if key == "esc":
|
||||||
signals.pop_view_state.send(self)
|
signals.pop_view_state.send(self)
|
||||||
return super().keypress(size, key)
|
else:
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
class Choice(urwid.WidgetWrap):
|
class Choice(urwid.WidgetWrap):
|
||||||
|
@ -97,4 +103,22 @@ class Chooser(urwid.WidgetWrap):
|
||||||
if key == "enter":
|
if key == "enter":
|
||||||
self.callback(self.choices[self.walker.index])
|
self.callback(self.choices[self.walker.index])
|
||||||
signals.pop_view_state.send(self)
|
signals.pop_view_state.send(self)
|
||||||
return super().keypress(size, key)
|
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)
|
||||||
|
|
|
@ -30,6 +30,9 @@ call_in = blinker.Signal()
|
||||||
# Focus the body, footer or header of the main window
|
# Focus the body, footer or header of the main window
|
||||||
focus = blinker.Signal()
|
focus = blinker.Signal()
|
||||||
|
|
||||||
|
# Focus the body, footer or header of the main window
|
||||||
|
footer_help = blinker.Signal()
|
||||||
|
|
||||||
# Fired when settings change
|
# Fired when settings change
|
||||||
update_settings = blinker.Signal()
|
update_settings = blinker.Signal()
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import urwid
|
||||||
from mitmproxy.tools.console import common
|
from mitmproxy.tools.console import common
|
||||||
from mitmproxy.tools.console import pathedit
|
from mitmproxy.tools.console import pathedit
|
||||||
from mitmproxy.tools.console import signals
|
from mitmproxy.tools.console import signals
|
||||||
from mitmproxy.utils import human
|
|
||||||
|
|
||||||
|
|
||||||
class PromptPath:
|
class PromptPath:
|
||||||
|
@ -143,10 +142,15 @@ class StatusBar(urwid.WidgetWrap):
|
||||||
super().__init__(urwid.Pile([self.ib, self.master.ab]))
|
super().__init__(urwid.Pile([self.ib, self.master.ab]))
|
||||||
signals.update_settings.connect(self.sig_update)
|
signals.update_settings.connect(self.sig_update)
|
||||||
signals.flowlist_change.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.options.changed.connect(self.sig_update)
|
||||||
master.view.focus.sig_change.connect(self.sig_update)
|
master.view.focus.sig_change.connect(self.sig_update)
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
|
def sig_footer_help(self, sender, helptext):
|
||||||
|
self.helptext = helptext
|
||||||
|
self.redraw()
|
||||||
|
|
||||||
def sig_update(self, sender, updated=None):
|
def sig_update(self, sender, updated=None):
|
||||||
self.redraw()
|
self.redraw()
|
||||||
|
|
||||||
|
@ -281,10 +285,5 @@ class StatusBar(urwid.WidgetWrap):
|
||||||
]), "heading")
|
]), "heading")
|
||||||
self.ib._w = status
|
self.ib._w = status
|
||||||
|
|
||||||
def update(self, text):
|
|
||||||
self.helptext = text
|
|
||||||
self.redraw()
|
|
||||||
self.master.loop.draw_screen()
|
|
||||||
|
|
||||||
def selectable(self):
|
def selectable(self):
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -140,6 +140,18 @@ class Rec():
|
||||||
def test_subscribe():
|
def test_subscribe():
|
||||||
o = TO()
|
o = TO()
|
||||||
r = Rec()
|
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.subscribe(r, ["two"])
|
||||||
o.one = 2
|
o.one = 2
|
||||||
assert not r.called
|
assert not r.called
|
||||||
|
|
Loading…
Reference in New Issue