Merge branch 'main' into refactor-repo

This commit is contained in:
Paul Gauthier 2023-07-23 10:23:38 -03:00
commit 143ca36733
5 changed files with 118 additions and 16 deletions

View file

@ -1,5 +1,9 @@
# Release history # Release history
### main branch on GitHub
- /add and /drop always use paths relative to the git root
### v0.10.0 ### v0.10.0
- Added `/git` command to run git from inside aider chats. - Added `/git` command to run git from inside aider chats.

View file

@ -104,6 +104,7 @@ Aider also has many
additional command-line options, environment variables or configuration file additional command-line options, environment variables or configuration file
to set many options. See `aider --help` for details. to set many options. See `aider --help` for details.
## In-chat commands ## In-chat commands
Aider supports commands from within the chat, which all start with `/`. Here are some of the most useful in-chat commands: Aider supports commands from within the chat, which all start with `/`. Here are some of the most useful in-chat commands:
@ -115,6 +116,8 @@ Aider supports commands from within the chat, which all start with `/`. Here are
* `/run <command>`: Run a shell command and optionally add the output to the chat. * `/run <command>`: Run a shell command and optionally add the output to the chat.
* `/help`: Show help about all commands. * `/help`: Show help about all commands.
See the [full command docs](https://aider.chat/docs/commands.html) for more information.
## Tips ## Tips

View file

@ -236,7 +236,9 @@ class Commands:
matched_files = [] matched_files = []
for fn in raw_matched_files: for fn in raw_matched_files:
matched_files += expand_subdir(fn.relative_to(self.coder.root)) matched_files += expand_subdir(fn)
matched_files = [str(Path(fn).relative_to(self.coder.root)) for fn in matched_files]
# if repo, filter against it # if repo, filter against it
if self.coder.repo: if self.coder.repo:
@ -330,7 +332,7 @@ class Commands:
self.io.tool_error(f"No files matched '{word}'") self.io.tool_error(f"No files matched '{word}'")
for matched_file in matched_files: for matched_file in matched_files:
abs_fname = str(Path(matched_file).resolve()) abs_fname = self.coder.abs_root_path(matched_file)
if abs_fname in self.coder.abs_fnames: if abs_fname in self.coder.abs_fnames:
self.coder.abs_fnames.remove(abs_fname) self.coder.abs_fnames.remove(abs_fname)
self.io.tool_output(f"Removed {matched_file} from the chat") self.io.tool_output(f"Removed {matched_file} from the chat")
@ -430,6 +432,7 @@ def expand_subdir(file_path):
yield file_path yield file_path
return return
for file in file_path.rglob("*"): if file_path.is_dir():
if file.is_file(): for file in file_path.rglob("*"):
yield str(file) if file.is_file():
yield str(file)

37
docs/commands.md Normal file
View file

@ -0,0 +1,37 @@
# Commands
- `/help`: Show help about all commands
- `/exit`: Exit the application
## token/context management
- `/add <file>`: Add matching files to the chat session using glob patterns
- `/drop <file>`: Remove matching files from the chat session
- `/clear`: Clear the chat history
- `/ls`: List all known files and those included in the chat session
- `/tokens`: Report on the number of tokens used by the current chat context
- `/run <command>`: Run a shell command and optionally add the output to the chat
## git
- `/undo`: Undo the last git commit if it was done by aider
- `/diff`: Display the diff of the last aider commit
- `/commit <message>`: Commit edits to the repo made outside the chat (commit message optional)
- `/git <command>`: Run a git command
# Prompt Toolkit defaults
The interactive prompt is built with [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) which provides a lot of Emacs and Vi-style keyboard. Some emacs bindings you may find useful are
- `Ctrl-A` : Move cursor to the start of the line.
- `Ctrl-B` : Move cursor back one character.
- `Ctrl-D` : Delete the character under the cursor.
- `Ctrl-E` : Move cursor to the end of the line.
- `Ctrl-F` : Move cursor forward one character.
- `Ctrl-K` : Delete from the cursor to the end of the line.
- `Ctrl-L` : Clear the screen.
- `Ctrl-N` : Move down to the next history entry.
- `Ctrl-P` : Move up to the previous history entry.
- `Ctrl-R` : Reverse search in command history.
Note: aider currently exits vi normal mode after a single command, (maybe something to do with the esc keybinding?). Feel free to investigate and make a PR if you would like to see it fully supported.
Prompt toolkit also does not provide clear documentation on the bindings they support - maybe you can take aider and help them out with that and we can then link to the authoritative docs.

View file

@ -25,7 +25,10 @@ class TestCommands(TestCase):
def tearDown(self): def tearDown(self):
os.chdir(self.original_cwd) os.chdir(self.original_cwd)
shutil.rmtree(self.tempdir) try:
shutil.rmtree(self.tempdir)
except OSError:
pass # Ignore errors (Windows)
def test_cmd_add(self): def test_cmd_add(self):
# Initialize the Commands and InputOutput objects # Initialize the Commands and InputOutput objects
@ -84,21 +87,18 @@ class TestCommands(TestCase):
def test_cmd_add_drop_directory(self): def test_cmd_add_drop_directory(self):
# Initialize the Commands and InputOutput objects # Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True) io = InputOutput(pretty=False, yes=False)
from aider.coders import Coder from aider.coders import Coder
coder = Coder.create(models.GPT35, None, io) coder = Coder.create(models.GPT35, None, io)
commands = Commands(io, coder) commands = Commands(io, coder)
# Create a directory and add files to it # Create a directory and add files to it using pathlib
os.mkdir("test_dir") Path("test_dir").mkdir()
os.mkdir("test_dir/another_dir") Path("test_dir/another_dir").mkdir()
with open("test_dir/test_file1.txt", "w") as f: Path("test_dir/test_file1.txt").write_text("Test file 1")
f.write("Test file 1") Path("test_dir/test_file2.txt").write_text("Test file 2")
with open("test_dir/test_file2.txt", "w") as f: Path("test_dir/another_dir/test_file.txt").write_text("Test file 3")
f.write("Test file 2")
with open("test_dir/another_dir/test_file.txt", "w") as f:
f.write("Test file 3")
# Call the cmd_add method with a directory # Call the cmd_add method with a directory
commands.cmd_add("test_dir test_dir/test_file2.txt") commands.cmd_add("test_dir test_dir/test_file2.txt")
@ -115,6 +115,27 @@ class TestCommands(TestCase):
str(Path("test_dir/another_dir/test_file.txt").resolve()), coder.abs_fnames str(Path("test_dir/another_dir/test_file.txt").resolve()), coder.abs_fnames
) )
# Issue #139 /add problems when cwd != git_root
# remember the proper abs path to this file
abs_fname = str(Path("test_dir/another_dir/test_file.txt").resolve())
# chdir to someplace other than git_root
Path("side_dir").mkdir()
os.chdir("side_dir")
# add it via it's git_root referenced name
commands.cmd_add("test_dir/another_dir/test_file.txt")
# it should be there, but was not in v0.10.0
self.assertIn(abs_fname, coder.abs_fnames)
# drop it via it's git_root referenced name
commands.cmd_drop("test_dir/another_dir/test_file.txt")
# it should be there, but was not in v0.10.0
self.assertNotIn(abs_fname, coder.abs_fnames)
def test_cmd_drop_with_glob_patterns(self): def test_cmd_drop_with_glob_patterns(self):
# Initialize the Commands and InputOutput objects # Initialize the Commands and InputOutput objects
io = InputOutput(pretty=False, yes=True) io = InputOutput(pretty=False, yes=True)
@ -202,3 +223,37 @@ class TestCommands(TestCase):
self.assertIn("foo.txt", console_output) self.assertIn("foo.txt", console_output)
self.assertIn("bar.txt", console_output) self.assertIn("bar.txt", console_output)
def test_cmd_add_from_subdir(self):
repo = git.Repo.init()
repo.config_writer().set_value("user", "name", "Test User").release()
repo.config_writer().set_value("user", "email", "testuser@example.com").release()
# Create three empty files and add them to the git repository
filenames = ["one.py", Path("subdir") / "two.py", Path("anotherdir") / "three.py"]
for filename in filenames:
file_path = Path(filename)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.touch()
repo.git.add(str(file_path))
repo.git.commit("-m", "added")
filenames = [str(Path(fn).resolve()) for fn in filenames]
###
os.chdir("subdir")
io = InputOutput(pretty=False, yes=True)
coder = Coder.create(models.GPT35, None, io)
commands = Commands(io, coder)
# this should get added
commands.cmd_add(str(Path("anotherdir") / "three.py"))
# this should add one.py
commands.cmd_add("*.py")
self.assertIn(filenames[0], coder.abs_fnames)
self.assertNotIn(filenames[1], coder.abs_fnames)
self.assertIn(filenames[2], coder.abs_fnames)