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
|
||||
# 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 cStringIO
|
||||
import urwid.curses_display
|
||||
@ -392,6 +392,70 @@ class ConnectionView(WWrap):
|
||||
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):
|
||||
def __init__(self):
|
||||
self.message("")
|
||||
@ -399,6 +463,9 @@ class ActionBar(WWrap):
|
||||
def selectable(self):
|
||||
return True
|
||||
|
||||
def path_prompt(self, prompt):
|
||||
self.w = PathEdit(prompt)
|
||||
|
||||
def prompt(self, prompt):
|
||||
self.w = urwid.Edit(prompt)
|
||||
|
||||
@ -436,8 +503,11 @@ class StatusBar(WWrap):
|
||||
def get_edit_text(self):
|
||||
return self.ab.w.get_edit_text()
|
||||
|
||||
def path_prompt(self, prompt):
|
||||
return self.ab.path_prompt(prompt)
|
||||
|
||||
def prompt(self, prompt):
|
||||
self.ab.prompt(prompt)
|
||||
return self.ab.prompt(prompt)
|
||||
|
||||
def message(self, msg):
|
||||
self.ab.message(msg)
|
||||
@ -786,6 +856,11 @@ class ConsoleMaster(controller.Master):
|
||||
self.nested = True
|
||||
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):
|
||||
self.statusbar.prompt(prompt)
|
||||
self.view.set_focus("footer")
|
||||
@ -928,10 +1003,10 @@ class ConsoleMaster(controller.Master):
|
||||
else:
|
||||
raise Stop
|
||||
elif k == "S":
|
||||
self.prompt("Save flows: ", self.save_flows)
|
||||
self.path_prompt("Save flows: ", self.save_flows)
|
||||
k = None
|
||||
elif k == "L":
|
||||
self.prompt("Load flows: ", self.load_flows)
|
||||
self.path_prompt("Load flows: ", self.load_flows)
|
||||
k = None
|
||||
elif k == "c":
|
||||
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 = [
|
||||
uFlow(),
|
||||
uformat_keyvals(),
|
||||
uState()
|
||||
uState(),
|
||||
uPathCompleter()
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user