aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmproxy/console.py83
-rw-r--r--test/test_console.py32
2 files changed, 110 insertions, 5 deletions
diff --git a/libmproxy/console.py b/libmproxy/console.py
index a986cc1c..d0213249 100644
--- a/libmproxy/console.py
+++ b/libmproxy/console.py
@@ -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)
diff --git a/test/test_console.py b/test/test_console.py
index c5c856f8..cfafed96 100644
--- a/test/test_console.py
+++ b/test/test_console.py
@@ -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()
]