Merge pull request #59 from paul-gauthier/glob-add

Updated the /add and /drop commands to glob files
This commit is contained in:
paul-gauthier 2023-07-07 09:19:27 -07:00 committed by GitHub
commit 6e8695999d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 106 additions and 28 deletions

View file

@ -954,6 +954,8 @@ class Coder:
return full_path
def get_tracked_files(self):
if not self.repo:
return []
# convert to appropriate os.sep, since git always normalizes to /
files = set(self.repo.git.ls_files().splitlines())
res = set(str(Path(PurePosixPath(path))) for path in files)

View file

@ -11,6 +11,8 @@ from prompt_toolkit.completion import Completion
from aider import prompts
from .dump import dump # noqa: F401
class Commands:
def __init__(self, io, coder):
@ -219,39 +221,40 @@ class Commands:
if partial.lower() in fname.lower():
yield Completion(fname, start_position=-len(partial))
def glob_filtered_to_repo(self, pattern):
matched_files = Path(self.coder.root).glob(pattern)
# if repo, filter against it
if self.coder.repo:
git_files = self.coder.get_tracked_files()
matched_files = [fn for fn in matched_files if str(fn) in git_files]
return list(map(str, matched_files))
def cmd_add(self, args):
"Add matching files to the chat session"
"Add matching files to the chat session using glob patterns"
added_fnames = []
files = self.coder.get_all_relative_files()
git_added = []
git_files = self.coder.get_tracked_files()
for word in args.split():
matched_files = [file for file in files if word in file]
matched_files = self.glob_filtered_to_repo(word)
if not matched_files:
if self.coder.repo is not None:
create_file = self.io.confirm_ask(
(
f"No files matched '{word}'. Do you want to create the file and add it"
" to git?"
),
)
else:
create_file = self.io.confirm_ask(
f"No files matched '{word}'. Do you want to create the file?"
)
if create_file:
if any(char in word for char in "*?[]"):
self.io.tool_error(f"No files matched pattern: {word}")
elif self.io.confirm_ask(
f"No files matched '{word}'. Do you want to create the file?"
):
(Path(self.coder.root) / word).touch()
matched_files = [word]
if self.coder.repo is not None:
self.coder.repo.git.add(os.path.join(self.coder.root, word))
commit_message = f"aider: Created and added {word} to git."
self.coder.repo.git.commit("-m", commit_message, "--no-verify")
else:
self.io.tool_error(f"No files matched '{word}'")
for matched_file in matched_files:
if self.coder.repo and matched_file not in git_files:
self.coder.repo.git.add(os.path.join(self.coder.root, matched_file))
git_added.append(matched_file)
abs_file_path = os.path.abspath(os.path.join(self.coder.root, matched_file))
if abs_file_path not in self.coder.abs_fnames:
content = self.io.read_text(abs_file_path)
@ -262,6 +265,13 @@ class Commands:
else:
self.io.tool_error(f"{matched_file} is already in the chat")
if self.coder.repo and git_added:
git_added = " ".join(git_added)
commit_message = f"aider: Created {git_added}"
self.coder.repo.git.commit("-m", commit_message, "--no-verify")
commit_hash = self.coder.repo.head.commit.hexsha[:7]
self.io.tool_output(f"Commit {commit_hash} {commit_message}")
if not added_fnames:
return
@ -287,11 +297,8 @@ class Commands:
self.coder.abs_fnames = set()
for word in args.split():
matched_files = [
file
for file in self.coder.abs_fnames
if word.lower() in os.path.relpath(file, self.coder.root).lower()
]
matched_files = self.glob_filtered_to_repo(word)
if not matched_files:
self.io.tool_error(f"No files matched '{word}'")

View file

@ -4,6 +4,7 @@ import shutil
import sys
import tempfile
from io import StringIO
from pathlib import Path
from unittest import TestCase
from aider import models
@ -38,6 +39,74 @@ class TestCommands(TestCase):
self.assertTrue(os.path.exists("foo.txt"))
self.assertTrue(os.path.exists("bar.txt"))
def test_cmd_add_with_glob_patterns(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Create some test files
with open("test1.py", "w") as f:
f.write("print('test1')")
with open("test2.py", "w") as f:
f.write("print('test2')")
with open("test.txt", "w") as f:
f.write("test")
# Call the cmd_add method with a glob pattern
commands.cmd_add("*.py")
# Check if the Python files have been added to the chat session
self.assertIn(os.path.abspath("test1.py"), coder.abs_fnames)
self.assertIn(os.path.abspath("test2.py"), coder.abs_fnames)
# Check if the text file has not been added to the chat session
self.assertNotIn(os.path.abspath("test.txt"), coder.abs_fnames)
def test_cmd_add_no_match(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
# Call the cmd_add method with a non-existent file pattern
commands.cmd_add("*.nonexistent")
# Check if no files have been added to the chat session
self.assertEqual(len(coder.abs_fnames), 0)
def test_cmd_drop_with_glob_patterns(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)
from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io, openai_api_key="deadbeef")
commands = Commands(io, coder)
subdir = Path("subdir")
subdir.mkdir()
(subdir / "subtest1.py").touch()
(subdir / "subtest2.py").touch()
Path("test1.py").touch()
Path("test2.py").touch()
# Add some files to the chat session
commands.cmd_add("*.py")
self.assertEqual(len(coder.abs_fnames), 2)
# Call the cmd_drop method with a glob pattern
commands.cmd_drop("*2.py")
# Check if the Python files have been removed from the chat session
self.assertIn(os.path.abspath("test1.py"), coder.abs_fnames)
self.assertNotIn(os.path.abspath("test2.py"), coder.abs_fnames)
def test_cmd_add_bad_encoding(self):
# Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True)