diff --git a/aider/coders/base_coder.py b/aider/coders/base_coder.py index 16774cac7..77463f102 100755 --- a/aider/coders/base_coder.py +++ b/aider/coders/base_coder.py @@ -167,9 +167,10 @@ class Coder: self.io.tool_output(f"Added {fname} to the chat.") def find_common_root(self): - if self.abs_fnames: - common_prefix = os.path.commonpath(list(self.abs_fnames)) - self.root = os.path.dirname(common_prefix) + if len(self.abs_fnames) == 1: + self.root = os.path.dirname(list(self.abs_fnames)[0]) + elif self.abs_fnames: + self.root = os.path.commonpath(list(self.abs_fnames)) else: self.root = os.getcwd() diff --git a/aider/coders/wholefile_coder.py b/aider/coders/wholefile_coder.py index 6ffabbd2d..9e74097e8 100644 --- a/aider/coders/wholefile_coder.py +++ b/aider/coders/wholefile_coder.py @@ -32,13 +32,15 @@ class WholeFileCoder(Coder): output = [] lines = content.splitlines(keepends=True) + saw_fname = None fname = None new_lines = [] for i, line in enumerate(lines): - dump(repr(fname), repr(line), repr(new_lines)) if line.startswith("```"): if fname is not None: # ending an existing block + saw_fname = None + full_path = (Path(self.root) / fname).absolute() if mode == "diff" and full_path.exists(): @@ -65,15 +67,24 @@ class WholeFileCoder(Coder): if i > 0: fname = lines[i - 1].strip() if not fname: # blank line? or ``` was on first line i==0 - if len(chat_files) == 1: + if saw_fname: + fname = saw_fname + elif len(chat_files) == 1: fname = chat_files[0] else: # TODO: sense which file it is by diff size - raise ValueError("No filename provided before ``` block") + raise ValueError("No filename provided before ``` in file listing") elif fname is not None: new_lines.append(line) else: + for word in line.strip().split(): + word = word.rstrip(".:,;!") + for chat_file in chat_files: + quoted_chat_file = f"`{chat_file}`" + if word == quoted_chat_file: + saw_fname = chat_file + output.append(line) if mode == "diff": diff --git a/tests/test_wholefile.py b/tests/test_wholefile.py index b0c77bd98..bc9db67c1 100644 --- a/tests/test_wholefile.py +++ b/tests/test_wholefile.py @@ -1,6 +1,7 @@ import os import tempfile import unittest +from pathlib import Path from aider import models from aider.coders.wholefile_coder import WholeFileCoder @@ -68,7 +69,7 @@ class TestWholeFileCoder(unittest.TestCase): updated_content = f.read() self.assertEqual(updated_content, "Updated content\n") - def test_update_files_earlier_filename(self): + def test_update_files_no_filename_single_file_in_chat(self): with tempfile.TemporaryDirectory() as temp_dir: os.chdir(temp_dir) @@ -104,6 +105,47 @@ class TestWholeFileCoder(unittest.TestCase): updated_content = f.read() self.assertEqual(updated_content, content) + def test_update_files_earlier_filename(self): + with tempfile.TemporaryDirectory() as temp_dir: + os.chdir(temp_dir) + print(temp_dir) + + fname_a = Path("a.txt") + fname_b = Path("b.txt") + + fname_a.write_text("before a\n") + fname_b.write_text("before b\n") + + response = """ +Here is a new version of `a.txt` for you to consider: + +``` +after a +``` + +And here is `b.txt`: + +``` +after b +``` +""" + # Initialize WholeFileCoder with the temporary directory + io = InputOutput(yes=True) + coder = WholeFileCoder(main_model=models.GPT35, io=io, fnames=[fname_a, fname_b]) + + # Set the partial response content with the updated content + coder.partial_response_content = response + + # Call update_files method + edited_files = coder.update_files() + + # Check if the sample file was updated + self.assertIn(str(fname_a), edited_files) + self.assertIn(str(fname_b), edited_files) + + self.assertEqual(fname_a.read_text(), "after a\n") + self.assertEqual(fname_b.read_text(), "after b\n") + if __name__ == "__main__": unittest.main()