mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 02:10:59 +00:00
Add tab completion for save and load path specs.
This commit is contained in:
parent
bd6c0499fb
commit
460107589c
@ -13,7 +13,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import Queue, mailcap, mimetypes, tempfile, os, subprocess
|
import Queue, mailcap, mimetypes, tempfile, os, subprocess, glob
|
||||||
import os.path, sys
|
import os.path, sys
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import urwid.curses_display
|
import urwid.curses_display
|
||||||
@ -392,6 +392,70 @@ class ConnectionView(WWrap):
|
|||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
class _PathCompleter:
|
||||||
|
DEFAULTPATH = "/bin:/usr/bin:/usr/local/bin"
|
||||||
|
def __init__(self, _testing=False):
|
||||||
|
"""
|
||||||
|
_testing: disables reloading of the lookup table to make testing possible.
|
||||||
|
"""
|
||||||
|
self.lookup, self.offset = None, None
|
||||||
|
self.final = None
|
||||||
|
self._testing = _testing
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.lookup = None
|
||||||
|
self.offset = -1
|
||||||
|
|
||||||
|
def complete(self, txt):
|
||||||
|
"""
|
||||||
|
Returns the next completion for txt, or None if there is no completion.
|
||||||
|
"""
|
||||||
|
path = os.path.expanduser(txt)
|
||||||
|
if not self.lookup:
|
||||||
|
if not self._testing:
|
||||||
|
# Lookup is a set of (display value, actual value) tuples.
|
||||||
|
self.lookup = []
|
||||||
|
if os.path.isdir(path):
|
||||||
|
files = glob.glob(os.path.join(path, "*"))
|
||||||
|
prefix = txt
|
||||||
|
else:
|
||||||
|
files = glob.glob(path+"*")
|
||||||
|
prefix = os.path.dirname(txt)
|
||||||
|
prefix = prefix.rstrip("/") or "./"
|
||||||
|
for f in files:
|
||||||
|
display = os.path.join(prefix, os.path.basename(f))
|
||||||
|
if os.path.isdir(f):
|
||||||
|
display += "/"
|
||||||
|
self.lookup.append((display, f))
|
||||||
|
if not self.lookup:
|
||||||
|
self.final = path
|
||||||
|
return path
|
||||||
|
self.lookup.sort()
|
||||||
|
self.offset = -1
|
||||||
|
self.lookup.append((txt, txt))
|
||||||
|
self.offset += 1
|
||||||
|
if self.offset >= len(self.lookup):
|
||||||
|
self.offset = 0
|
||||||
|
ret = self.lookup[self.offset]
|
||||||
|
self.final = ret[1]
|
||||||
|
return ret[0]
|
||||||
|
|
||||||
|
|
||||||
|
class PathEdit(urwid.Edit, _PathCompleter):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
urwid.Edit.__init__(self, *args, **kwargs)
|
||||||
|
_PathCompleter.__init__(self)
|
||||||
|
|
||||||
|
def keypress(self, size, key):
|
||||||
|
if key == "tab":
|
||||||
|
comp = self.complete(self.get_edit_text())
|
||||||
|
self.set_edit_text(comp)
|
||||||
|
self.set_edit_pos(len(comp))
|
||||||
|
else:
|
||||||
|
self.reset()
|
||||||
|
return urwid.Edit.keypress(self, size, key)
|
||||||
|
|
||||||
|
|
||||||
class ActionBar(WWrap):
|
class ActionBar(WWrap):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.message("")
|
self.message("")
|
||||||
@ -399,6 +463,9 @@ class ActionBar(WWrap):
|
|||||||
def selectable(self):
|
def selectable(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def path_prompt(self, prompt):
|
||||||
|
self.w = PathEdit(prompt)
|
||||||
|
|
||||||
def prompt(self, prompt):
|
def prompt(self, prompt):
|
||||||
self.w = urwid.Edit(prompt)
|
self.w = urwid.Edit(prompt)
|
||||||
|
|
||||||
@ -436,8 +503,11 @@ class StatusBar(WWrap):
|
|||||||
def get_edit_text(self):
|
def get_edit_text(self):
|
||||||
return self.ab.w.get_edit_text()
|
return self.ab.w.get_edit_text()
|
||||||
|
|
||||||
|
def path_prompt(self, prompt):
|
||||||
|
return self.ab.path_prompt(prompt)
|
||||||
|
|
||||||
def prompt(self, prompt):
|
def prompt(self, prompt):
|
||||||
self.ab.prompt(prompt)
|
return self.ab.prompt(prompt)
|
||||||
|
|
||||||
def message(self, msg):
|
def message(self, msg):
|
||||||
self.ab.message(msg)
|
self.ab.message(msg)
|
||||||
@ -786,6 +856,11 @@ class ConsoleMaster(controller.Master):
|
|||||||
self.nested = True
|
self.nested = True
|
||||||
self.make_view()
|
self.make_view()
|
||||||
|
|
||||||
|
def path_prompt(self, prompt, callback):
|
||||||
|
self.statusbar.path_prompt(prompt)
|
||||||
|
self.view.set_focus("footer")
|
||||||
|
self.prompting = callback
|
||||||
|
|
||||||
def prompt(self, prompt, callback):
|
def prompt(self, prompt, callback):
|
||||||
self.statusbar.prompt(prompt)
|
self.statusbar.prompt(prompt)
|
||||||
self.view.set_focus("footer")
|
self.view.set_focus("footer")
|
||||||
@ -928,10 +1003,10 @@ class ConsoleMaster(controller.Master):
|
|||||||
else:
|
else:
|
||||||
raise Stop
|
raise Stop
|
||||||
elif k == "S":
|
elif k == "S":
|
||||||
self.prompt("Save flows: ", self.save_flows)
|
self.path_prompt("Save flows: ", self.save_flows)
|
||||||
k = None
|
k = None
|
||||||
elif k == "L":
|
elif k == "L":
|
||||||
self.prompt("Load flows: ", self.load_flows)
|
self.path_prompt("Load flows: ", self.load_flows)
|
||||||
k = None
|
k = None
|
||||||
elif k == "c":
|
elif k == "c":
|
||||||
self.prompt("Sticky cookie: ", self.set_stickycookie)
|
self.prompt("Sticky cookie: ", self.set_stickycookie)
|
||||||
|
@ -288,9 +288,39 @@ class uformat_keyvals(libpry.AutoTree):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class uPathCompleter(libpry.AutoTree):
|
||||||
|
def test_completion(self):
|
||||||
|
c = console._PathCompleter(True)
|
||||||
|
c.reset()
|
||||||
|
c.lookup = [
|
||||||
|
("a", "x/a"),
|
||||||
|
("aa", "x/aa"),
|
||||||
|
]
|
||||||
|
assert c.complete("a") == "a"
|
||||||
|
assert c.final == "x/a"
|
||||||
|
assert c.complete("a") == "aa"
|
||||||
|
assert c.complete("a") == "a"
|
||||||
|
|
||||||
|
c = console._PathCompleter(True)
|
||||||
|
r = c.complete("l")
|
||||||
|
assert c.final.endswith(r)
|
||||||
|
|
||||||
|
c.reset()
|
||||||
|
assert c.complete("/nonexistent") == "/nonexistent"
|
||||||
|
assert c.final == "/nonexistent"
|
||||||
|
c.reset()
|
||||||
|
assert c.complete("~") != "~"
|
||||||
|
|
||||||
|
c.reset()
|
||||||
|
s = "thisisatotallynonexistantpathforsure"
|
||||||
|
assert c.complete(s) == s
|
||||||
|
assert c.final == s
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
uFlow(),
|
uFlow(),
|
||||||
uformat_keyvals(),
|
uformat_keyvals(),
|
||||||
uState()
|
uState(),
|
||||||
|
uPathCompleter()
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user