Skip to content

Commit e8aa4a9

Browse files
committed
fix: improved tabcomplete and added tests
1 parent b658aa9 commit e8aa4a9

File tree

2 files changed

+44
-20
lines changed

2 files changed

+44
-20
lines changed

gptme/tabcomplete.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
logger = logging.getLogger(__name__)
99

1010

11-
def register_tabcomplete() -> None:
11+
def register_tabcomplete() -> None: # pragma: no cover
1212
"""Register tab completion for readline."""
1313

1414
# set up tab completion
@@ -26,7 +26,7 @@ def register_tabcomplete() -> None:
2626
readline.parse_and_bind("tab: complete")
2727

2828

29-
def _completer(text: str, state: int) -> str | None:
29+
def _completer(text: str, state: int) -> str | None: # pragma: no cover
3030
"""
3131
Tab completion for readline.
3232
@@ -38,41 +38,40 @@ def _completer(text: str, state: int) -> str | None:
3838
return _matches(text)[state]
3939

4040

41+
def _process_completion(p: Path) -> str:
42+
# Strip cwd from path
43+
p = Path(str(p).replace(str(Path.cwd()) + "/", ""))
44+
45+
# If path is a directory, add trailing slash
46+
if p.exists() and p.is_dir():
47+
return str(p) + "/"
48+
else:
49+
return str(p)
50+
51+
4152
@lru_cache(maxsize=1)
4253
def _matches(text: str) -> list[str]:
4354
"""Returns a list of matches for text to complete."""
4455

4556
# if text starts with /, complete with commands or files as absolute paths
4657
if text.startswith("/"):
4758
# if no text, list all commands
48-
all_commands = [f"{CMDFIX}{cmd}" for cmd in COMMANDS if cmd != "help"]
59+
all_commands = [f"{CMDFIX}{cmd}" for cmd in COMMANDS]
4960
if not text[1:]:
5061
return all_commands
5162
# else, filter commands with text
5263
else:
53-
matching_files = [str(p) for p in Path("/").glob(text[1:] + "*")]
64+
matching_files = [
65+
_process_completion(p) for p in Path("/").glob(text[1:] + "*")
66+
]
5467
return [
5568
cmd for cmd in all_commands if cmd.startswith(text)
5669
] + matching_files
5770

58-
# if text starts with ., complete with current dir
59-
elif text.startswith("."):
60-
if not text[1:]:
61-
return [str(Path.cwd())]
62-
else:
63-
all_files = [str(p) for p in Path.cwd().glob("*")]
64-
return [f for f in all_files if f.startswith(text)]
65-
6671
# if text starts with ../, complete with parent dir
6772
elif text.startswith(".."):
68-
if not text[2:]:
69-
return [str(Path.cwd().parent)]
70-
else:
71-
return [str(p) for p in Path.cwd().parent.glob(text[2:] + "*")]
73+
return [_process_completion(p) for p in Path("..").glob(text[3:] + "*")]
7274

7375
# else, complete with files in current dir
7476
else:
75-
if not text:
76-
return [str(Path.cwd())]
77-
else:
78-
return [str(p) for p in Path.cwd().glob(text + "*")]
77+
return [_process_completion(p) for p in Path.cwd().glob(text + "*")]

tests/test_tabcomplete.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import os
2+
import sys
3+
4+
from gptme.tabcomplete import _matches
5+
6+
7+
def test_matches():
8+
# echo cwd
9+
print(os.getcwd())
10+
11+
# dirs
12+
assert ".git/" in _matches("")
13+
assert _matches(".githu") == [".github/"]
14+
assert _matches(".github") == [".github/"]
15+
assert _matches(".github/") == [".github/workflows/"]
16+
17+
# files
18+
assert _matches("README") == ["README.md"]
19+
assert _matches("./README") == ["README.md"]
20+
assert _matches("../gptme/README") == ["../gptme/README.md"]
21+
if sys.platform != "win32":
22+
assert _matches("/etc/pass") == ["/etc/passwd"]
23+
24+
# commands
25+
assert _matches("/hel") == ["/help"]

0 commit comments

Comments
 (0)