diff options
-rw-r--r-- | mitmproxy/tools/console/commander/commander.py | 40 | ||||
-rw-r--r-- | mitmproxy/tools/console/pathedit.py | 71 | ||||
-rw-r--r-- | test/mitmproxy/tools/console/test_commander.py | 13 | ||||
-rw-r--r-- | test/mitmproxy/tools/console/test_pathedit.py | 72 |
4 files changed, 51 insertions, 145 deletions
diff --git a/mitmproxy/tools/console/commander/commander.py b/mitmproxy/tools/console/commander/commander.py index dbbc8ff2..c79bc379 100644 --- a/mitmproxy/tools/console/commander/commander.py +++ b/mitmproxy/tools/console/commander/commander.py @@ -1,7 +1,10 @@ +import abc +import glob +import os +import typing + import urwid from urwid.text_layout import calc_coords -import typing -import abc import mitmproxy.master import mitmproxy.command @@ -34,6 +37,30 @@ class ListCompleter(Completer): return ret +# Generates the completion options for a specific starting input +def pathOptions(start: str) -> typing.Sequence[str]: + if not start: + start = "./" + path = os.path.expanduser(start) + ret = [] + if os.path.isdir(path): + files = glob.glob(os.path.join(path, "*")) + prefix = start + else: + files = glob.glob(path + "*") + prefix = os.path.dirname(start) + prefix = prefix or "./" + for f in files: + display = os.path.normpath(os.path.join(prefix, os.path.basename(f))) + if os.path.isdir(f): + display += "/" + ret.append(display) + if not ret: + ret = [start] + ret.sort() + return ret + + CompletionState = typing.NamedTuple( "CompletionState", [ @@ -93,6 +120,15 @@ class CommandBuffer(): ), parse = parts, ) + elif last.type == mitmproxy.command.Path: + self.completion = CompletionState( + completer = ListCompleter( + "", + pathOptions(parts[1].value) + ), + parse = parts, + ) + if self.completion: nxt = self.completion.completer.cycle() buf = " ".join([i.value for i in self.completion.parse[:-1]]) + " " + nxt diff --git a/mitmproxy/tools/console/pathedit.py b/mitmproxy/tools/console/pathedit.py deleted file mode 100644 index 10ee1416..00000000 --- a/mitmproxy/tools/console/pathedit.py +++ /dev/null @@ -1,71 +0,0 @@ -import glob -import os.path - -import urwid - - -class _PathCompleter: - - 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 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, prompt, last_path): - urwid.Edit.__init__(self, prompt, last_path) - _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) diff --git a/test/mitmproxy/tools/console/test_commander.py b/test/mitmproxy/tools/console/test_commander.py index 1ac4c5c6..e8974869 100644 --- a/test/mitmproxy/tools/console/test_commander.py +++ b/test/mitmproxy/tools/console/test_commander.py @@ -1,5 +1,18 @@ +import os + from mitmproxy.tools.console.commander import commander from mitmproxy.test import taddons +from mitmproxy.test import tutils + + +def test_pathOptions(): + cd = os.path.normpath(tutils.test_data.path("mitmproxy/completion")) + + ret = [x[len(cd):] for x in commander.pathOptions(cd)] + assert ret == ['/aaa', '/aab', '/aac', '/bbb/'] + + ret = [x[len(cd):] for x in commander.pathOptions(os.path.join(cd, "a"))] + assert ret == ['/aaa', '/aab', '/aac'] class TestListCompleter: diff --git a/test/mitmproxy/tools/console/test_pathedit.py b/test/mitmproxy/tools/console/test_pathedit.py deleted file mode 100644 index b9f51f5a..00000000 --- a/test/mitmproxy/tools/console/test_pathedit.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -from os.path import normpath -from unittest import mock - -from mitmproxy.tools.console import pathedit -from mitmproxy.test import tutils - - -class TestPathCompleter: - - def test_lookup_construction(self): - c = pathedit._PathCompleter() - - cd = os.path.normpath(tutils.test_data.path("mitmproxy/completion")) - ca = os.path.join(cd, "a") - assert c.complete(ca).endswith(normpath("/completion/aaa")) - assert c.complete(ca).endswith(normpath("/completion/aab")) - c.reset() - ca = os.path.join(cd, "aaa") - assert c.complete(ca).endswith(normpath("/completion/aaa")) - assert c.complete(ca).endswith(normpath("/completion/aaa")) - c.reset() - assert c.complete(cd).endswith(normpath("/completion/aaa")) - - def test_completion(self): - c = pathedit._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 = pathedit._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 - - -class TestPathEdit: - - def test_keypress(self): - - pe = pathedit.PathEdit("", "") - - with mock.patch('urwid.widget.Edit.get_edit_text') as get_text, \ - mock.patch('urwid.widget.Edit.set_edit_text') as set_text: - - cd = os.path.normpath(tutils.test_data.path("mitmproxy/completion")) - get_text.return_value = os.path.join(cd, "a") - - # Pressing tab should set completed path - pe.keypress((1,), "tab") - set_text_called_with = set_text.call_args[0][0] - assert set_text_called_with.endswith(normpath("/completion/aaa")) - - # Pressing any other key should reset - pe.keypress((1,), "a") - assert pe.lookup is None |