Commit graph

659 commits

Author SHA1 Message Date
Paul Gauthier
919cfc2359 aider: Replaced all self.console.print() calls with self.io.tool_error() calls with [red] removed from the string.
# Context:
USER: replace all the self.console.print() calls that contain [red] with calls to self.io.tool_error() with [red] removed from the string
ASSISTANT: aider/coder.py
<<<<<<< ORIGINAL
            self.console.print(
                f"[red]This tool will almost certainly fail to work with {main_model}"
            )
=======
            self.io.tool_error(f"This tool will almost certainly fail to work with {main_model}")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            self.console.print("[red]No suitable git repo, will not automatically commit edits.")
=======
            self.io.tool_error("No suitable git repo, will not automatically commit edits.")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            self.console.print("[red]Files are not in a git repo.")
=======
            self.io.tool_error("Files are not in a git repo.")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            self.console.print("[red]Files are in different git repos.")
=======
            self.io.tool_error("Files are in different git repos.")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
                self.console.print("[red]Skipped adding new files to the git repo.")
=======
                self.io.tool_error("Skipped adding new files to the git repo.")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            self.console.print("[red]Warning: no changes found in tracked files.")
=======
            self.io.tool_error("Warning: no changes found in tracked files.")
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            self.console.print("[red]Malformed ORIGINAL/UPDATE blocks, retrying...")
            self.console.print("[red]", Text(err))
=======
            self.io.tool_error("Malformed ORIGINAL/UPDATE blocks, retrying...")
            self.io.tool_error(Text(err))
>>>>>>> UPDATED

Please note that I couldn't find the `self.io.tool_error()` method in the provided code. You may need to create this method in the appropriate class or provide the correct method name to replace the `self.console.print()` calls.
2023-05-12 13:03:34 -07:00
Paul Gauthier
b7299565f1 refac 2023-05-12 10:53:23 -07:00
Paul Gauthier
0325fc40ac roughed in switch to prompt toolkit for _ask funcs 2023-05-12 08:15:32 -07:00
Paul Gauthier
9a4dfae07a wip 2023-05-12 08:05:57 -07:00
Paul Gauthier
36b88d6933 Merge branch 'main' into pattern 2023-05-12 07:15:27 -07:00
Paul Gauthier
5490dc11d0 Updated version number to 0.2.0 in setup.py. 2023-05-11 23:26:22 -07:00
Paul Gauthier
a16f91eed1 aider: Added --no-auto-commits argument to README.md.
# Context:
USER: add the --no-auto-commit arg to readme
ASSISTANT: I will add the `--no-auto-commits` argument to the README.md file.

```markdown
README.md
<<<<<<< ORIGINAL
- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `AIDER_SHOW_DIFFS` (default: 0 for False, 1 for True).
=======
- `--show-diffs`: Show diffs when committing changes (default: False). Override the default with the environment variable `AIDER_SHOW_DIFFS` (default: 0 for False, 1 for True).
- `--no-auto-commits`: Disable auto commit of changes. Override the default with the environment variable `AIDER_AUTO_COMMITS` (default: 1 for enabled, 0 for disabled).
>>>>>>> UPDATED
```
2023-05-11 23:25:51 -07:00
Paul Gauthier
0c3b772172 prompt eng for new files 2023-05-11 23:24:38 -07:00
Paul Gauthier
596a6d1ae1 make parent dirs 2023-05-11 23:24:29 -07:00
Paul Gauthier
d45b7ae752 handle filenames above the triple quotes 2023-05-11 22:59:02 -07:00
Paul Gauthier
9ef50d8f3d make dirs for new files 2023-05-11 22:55:26 -07:00
Paul Gauthier
89149b307d aider: Changed fname.touch() to fname.touch(parents=True) to create any missing directories in the path.
# Context:
USER: when calling Path.touch() can we ask it to make missing dirs?
ASSISTANT: Yes, you can use the `parents` parameter in the `touch()` method to create any missing directories. Set `parents=True` to create any missing directories in the path. Here's the change needed in the `aider/coder.py` file:

```python
aider/coder.py
<<<<<<< ORIGINAL
                fname.touch()
=======
                fname.touch(parents=True)
>>>>>>> UPDATED
```
2023-05-11 22:37:59 -07:00
Paul Gauthier
5ddaf55dd2 Merge branch 'main' into pattern 2023-05-11 22:19:12 -07:00
Paul Gauthier
c9ef516bdb cleanup \[ from prompt string which was generating improper escape warnings 2023-05-11 22:19:01 -07:00
Paul Gauthier
52a7c4b786 Merge branch 'main' into pattern 2023-05-11 22:15:39 -07:00
Paul Gauthier
3ec7880dc8 added tests 2023-05-11 22:10:21 -07:00
Paul Gauthier
5444b45a93 aider: Added test for ValueError containing the word "Incomplete" in test_find_original_update_blocks_unclosed.
# Context:
USER: in test_find_original_update_blocks_unclosed, assert that it throws a valueerror containing the word "Incomplete"
ASSISTANT: To add the test for ValueError containing the word "Incomplete" in the `test_find_original_update_blocks_unclosed` function, you can use the `assertRaises` context manager and check if the exception message contains the word "Incomplete". Here's the change:

```python
tests/test_utils.py
<<<<<<< ORIGINAL
        utils.find_original_update_blocks(edit)
=======
        with self.assertRaises(ValueError) as cm:
            utils.find_original_update_blocks(edit)
        self.assertIn("Incomplete", str(cm.exception))
>>>>>>> UPDATED
```
2023-05-11 22:08:30 -07:00
Paul Gauthier
6e4f17d377 cleanup 2023-05-11 22:06:32 -07:00
Paul Gauthier
684b0e4964 Provide structured errors to GPT if it generates malformed ORIG/UPD blocks 2023-05-11 22:06:02 -07:00
Paul Gauthier
6686ea1005 Only ask to commit when dirty files are touched 2023-05-11 21:14:40 -07:00
Paul Gauthier
ae41782cb4 wip 2023-05-11 21:05:15 -07:00
Paul Gauthier
797372c69e refactor orig/upd into utils 2023-05-11 20:57:27 -07:00
Paul Gauthier
5e593eb631 handle no args properly 2023-05-11 20:56:09 -07:00
Paul Gauthier
ed6ceae544 cleanup 2023-05-11 20:45:20 -07:00
Paul Gauthier
dabda6c5ea aider: Replaced console.reset() with reset_terminal() from rich.console module to reset the terminal without clearing the screen.
# Context:
USER: AttributeError: 'Console' object has no attribute 'reset'
ASSISTANT: I apologize for the confusion. It seems I made a mistake in my previous suggestion. The `rich` library does not have a `reset()` method for the `Console` object. Instead, you can use the `reset_terminal()` function from the `rich.console` module. Here's the change for `aider/main.py`:

```python
aider/main.py
<<<<<<< ORIGINAL
from rich.console import Console
=======
from rich.console import Console, reset_terminal
>>>>>>> UPDATED

aider/main.py
<<<<<<< ORIGINAL
    console = Console()
    console.reset()
=======
    reset_terminal()
>>>>>>> UPDATED
```

This change imports the `reset_terminal()` function from the `rich.console` module and replaces the `console.reset()` call with `reset_terminal()` at the end of the `main()` function to reset the terminal without clearing the screen.
2023-05-11 20:44:46 -07:00
Paul Gauthier
0ef2790464 aider: Replaced console.clear() with console.reset() to disable funky terminal modes.
# Context:
USER: i don't want to clear the screen. just disable any funky terminal modes
ASSISTANT: I apologize for the confusion. If you want to disable any funky terminal modes without clearing the screen, you can use the `rich` library's `reset()` method. Here's the change for `aider/main.py`:

```python
aider/main.py
<<<<<<< ORIGINAL
    coder.run()
    console = Console()
    console.clear()
=======
    coder.run()
    console = Console()
    console.reset()
>>>>>>> UPDATED
```

This change replaces the `console.clear()` call with `console.reset()` at the end of the `main()` function to reset the terminal without clearing the screen.
2023-05-11 20:44:01 -07:00
Paul Gauthier
71116a771b aider: Added rich library to reset the terminal at the end of main() function.
# Context:
USER: at the end of main() reset the terminal
ASSISTANT: I need to see the contents of `aider/main.py` to make the requested changes. Please provide the content of that file.
USER: Please note that I shared content of these additional files: aider/main.py
ASSISTANT: I apologize for the oversight. I see the content of `aider/main.py` now. To reset the terminal at the end of the `main()` function, you can use the `os.system()` function with the appropriate command for your operating system. Here's the change for `aider/main.py`:

```python
aider/main.py
<<<<<<< ORIGINAL

^C KeyboardInterrupt
USER: no i need pure python. can rich do it?
ASSISTANT: Yes, you can use the `rich` library to reset the terminal using pure Python. First, you need to import the `Console` class from the `rich.console` module. Then, create a `Console` instance and call its `clear()` method at the end of the `main()` function. Here's the change for `aider/main.py`:

```python
aider/main.py
<<<<<<< ORIGINAL
import os
import sys
import argparse
from dotenv import load_dotenv
from aider.coder import Coder
=======
import os
import sys
import argparse
from dotenv import load_dotenv
from aider.coder import Coder
from rich.console import Console
>>>>>>> UPDATED

aider/main.py
<<<<<<< ORIGINAL
    coder.run()
=======
    coder.run()
    console = Console()
    console.clear()
>>>>>>> UPDATED
```

This change imports the `Console` class from the `rich.console` module and adds the `console.clear()` call at the end of the `main()` function to reset the terminal.
2023-05-11 20:43:11 -07:00
Paul Gauthier
f29eaf451b ensure the Live is stopped if exceptions occur 2023-05-11 20:40:07 -07:00
Paul Gauthier
d44f732d3b main should use argv if args not provided 2023-05-11 20:34:46 -07:00
Paul Gauthier
c368e87c9f bugfix, removed abs_fnames=set() from Coder 2023-05-11 20:21:09 -07:00
Paul Gauthier
3b0c5132f2 aider: Passed temp_dir as the cwd to subprocess in test_main_with_empty_git_dir_new_file.
# Context:
USER: pass temp_dir as the cwd to subprocess in test_main_with_empty_git_dir_new_file
ASSISTANT: Here's the change to pass `temp_dir` as the `cwd` to `subprocess` in the `test_main_with_empty_git_dir_new_file` function:

```python
tests/test_main.py
<<<<<<< ORIGINAL
            subprocess.run(["git", "init"])
=======
            subprocess.run(["git", "init"], cwd=temp_dir)
>>>>>>> UPDATED
```
2023-05-11 17:52:34 -07:00
Paul Gauthier
8a60462167 finished adding --yes 2023-05-11 17:51:50 -07:00
Paul Gauthier
4c97d4e654 Removed confirm_ask and prompt_ask methods and added new implementations with yes flag. 2023-05-11 17:46:54 -07:00
Paul Gauthier
625fd1c3a5 aider: Created new function prompt_ask in Coder class and replaced all calls to Prompt.ask with the new function.
# Context:
USER: make a new func self.prompt_ask which just calls Prompt.ask and returns the result. change all calls to use it.
ASSISTANT: I will create a new function `prompt_ask` in the `Coder` class and replace all calls to `Prompt.ask` with the new function.

```python
aider/coder.py
<<<<<<< ORIGINAL
class Coder:
    abs_fnames = set()

    def confirm_ask(self, question, default=None):
=======
class Coder:
    abs_fnames = set()

    def confirm_ask(self, question, default=None):
        return Confirm.ask(question, console=self.console, default=default)

    def prompt_ask(self, question, default=None):
        return Prompt.ask(question, console=self.console, default=default)
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            res = Prompt.ask(
=======
            res = self.prompt_ask(
>>>>>>> UPDATED
                "[bright_black]Commit before the chat proceeds? \[y/n/commit message]",  # noqa: W605 E501
                console=self.console,
                default="y",
            ).strip()
```
2023-05-11 17:46:05 -07:00
Paul Gauthier
428d6f73fc Refactored confirm_ask method to accept None as default and used it in all confirmations. 2023-05-11 17:45:06 -07:00
Paul Gauthier
34c2369380 aider: Created a new function confirm_ask in the Coder class and replaced all calls to Confirm.ask with the new function.
# Context:
USER: make a new func self.confirm_ask which just calls Confirm.ask and returns the result. change all calls to use it.
ASSISTANT: I will create a new function `confirm_ask` in the `Coder` class and replace all calls to `Confirm.ask` with the new function.

```python
aider/coder.py
<<<<<<< ORIGINAL
class Coder:
    abs_fnames = set()
=======
class Coder:
    abs_fnames = set()

    def confirm_ask(self, question, default="y"):
        return Confirm.ask(question, console=self.console, default=default)
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            if Confirm.ask("[bright_black]Add them?", console=self.console, default="y"):
=======
            if self.confirm_ask("[bright_black]Add them?"):
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
            if Confirm.ask("[bright_black]Add {path} to git?", console=self.console, default="y"):
=======
            if self.confirm_ask("[bright_black]Add {path} to git?"):
>>>>>>> UPDATED

aider/coder.py
<<<<<<< ORIGINAL
        ok = Confirm.ask("[bright_black]Add these files?", console=self.console, default="y")
=======
        ok = self.confirm_ask("[bright_black]Add these files?")
>>>>>>> UPDATED
```
2023-05-11 17:43:28 -07:00
Paul Gauthier
0dd35cdaee aider: Added a new argument --yes to always say yes to every confirmation and passed it to the Coder class.
# Context:
USER: add a new arg --yes without env. pass it to Coder and store in self.yes. "Always say yes to every confirmation"
ASSISTANT: To add a new argument `--yes` and pass it to the `Coder` class, we need to make changes in `aider/main.py` and `aider/coder.py`.

In `aider/main.py`, add the new argument `--yes` to the argument parser and pass it to the `Coder` class.

```python
aider/main.py
<<<<<<< ORIGINAL
    parser.add_argument(
        "--show-diffs",
        action="store_true",
        help=f"Show diffs when committing changes (default: False, ${env_prefix}SHOW_DIFFS)",
        default=bool(int(os.environ.get(f"{env_prefix}SHOW_DIFFS", 0))),
    )
=======
    parser.add_argument(
        "--show-diffs",
        action="store_true",
        help=f"Show diffs when committing changes (default: False, ${env_prefix}SHOW_DIFFS)",
        default=bool(int(os.environ.get(f"{env_prefix}SHOW_DIFFS", 0))),
    )
    parser.add_argument(
        "--yes",
        action="store_true",
        help="Always say yes to every confirmation",
    )
>>>>>>> UPDATED
```

```python
aider/main.py
<<<<<<< ORIGINAL
    coder = Coder(args.model, fnames, pretty, args.history_file, args.show_diffs, args.auto_commits)
=======
    coder = Coder(args.model, fnames, pretty, args.history_file, args.show_diffs, args.auto_commits, args.yes)
>>>>>>> UPDATED
```

In `aider/coder.py`, add the `yes` parameter to the `Coder` class and store it in `self.yes`.

```python
aider/coder.py
<<<<<<< ORIGINAL
    def __init__(self, main_model, fnames, pretty, history_file, show_diffs, auto_commits):
=======
    def __init__(self, main_model, fnames, pretty, history_file, show_diffs, auto_commits, yes):
>>>>>>> UPDATED
```

```python
aider/coder.py
<<<<<<< ORIGINAL
        self.show_diffs = show_diffs
=======
        self.show_diffs = show_diffs
        self.yes = yes
>>>>>>> UPDATED
```

Now, the `--yes` argument is added and passed to the `Coder` class. You can use `self.yes` in the `Coder` class to determine if the user wants to always say yes to every confirmation.
2023-05-11 17:41:23 -07:00
Paul Gauthier
09fbbc0dae wip: Added import subprocess to test_main.py. 2023-05-11 17:39:15 -07:00
Paul Gauthier
fa2f76c107 aider: Added subprocess module to run git init in the temporary directory before calling main in test_main_with_empty_git_dir_new_file.
# Context:
USER: in test_main_with_empty_git_dir_new_file, run git init in the new dir before calling main
ASSISTANT: To run `git init` in the new directory before calling `main`, you can use the `subprocess` module to execute the command. Here's the change you need to make in the `test_main_with_empty_git_dir_new_file` function:

```python
tests/test_main.py
<<<<<<< ORIGINAL
    def test_main_with_empty_git_dir_new_file(self):
        with tempfile.TemporaryDirectory() as temp_dir:
            os.chdir(temp_dir)
            with open(os.devnull, 'r') as dev_null:
                save_stdin = sys.stdin
                sys.stdin = dev_null
                main(['foo.txt'])
                sys.stdin = save_stdin
=======
    import subprocess

    def test_main_with_empty_git_dir_new_file(self):
        with tempfile.TemporaryDirectory() as temp_dir:
            os.chdir(temp_dir)
            subprocess.run(["git", "init"])
            with open(os.devnull, 'r') as dev_null:
                save_stdin = sys.stdin
                sys.stdin = dev_null
                main(['foo.txt'])
                sys.stdin = save_stdin
>>>>>>> UPDATED
```

This change imports the `subprocess` module and adds the `subprocess.run(["git", "init"])` line to run `git init` in the temporary directory before calling `main`.
2023-05-11 17:36:33 -07:00
Paul Gauthier
7a29a2911a aider: Added assertion to confirm that foo.txt exists after main exits in test_main_with_empty_dir_new_file.
# Context:
USER: in test_main_with_empty_dir_new_file, confirm that foo.txt exists after main exists
ASSISTANT: To confirm that `foo.txt` exists after `main` exits, you can add an assertion in the `test_main_with_empty_dir_new_file` test case. Here's the change:

```python
tests/test_main.py
<<<<<<< ORIGINAL
                main(['foo.txt'])
                sys.stdin = save_stdin
=======
                main(['foo.txt'])
                sys.stdin = save_stdin
                self.assertTrue(os.path.exists('foo.txt'))
>>>>>>> UPDATED
```
2023-05-11 17:34:35 -07:00
Paul Gauthier
e500f8e37f wip: Refactor main function to include tests for empty directory with no files and new file creation. 2023-05-11 17:33:59 -07:00
Paul Gauthier
490a6999fb allow main() w/o args 2023-05-11 17:28:03 -07:00
Paul Gauthier
00b0369282 aider: Replaced usage of redirect_stdin with closing stdin before calling main.
# Context:
USER: ImportError: cannot import name 'redirect_stdin' from 'contextlib'. Maybe just close stdin before calling main?
ASSISTANT: To fix the ImportError, we can replace the usage of `redirect_stdin` with closing stdin before calling `main`. Here's the change:

```python
tests/test_main.py
<<<<<<< ORIGINAL
from contextlib import redirect_stdin
=======
>>>>>>> UPDATED
```

```python
tests/test_main.py
<<<<<<< ORIGINAL
    with open(os.devnull, 'r') as dev_null:
        with redirect_stdin(dev_null):
                    main()
=======
    with open(os.devnull, 'r') as dev_null:
        sys.stdin.close()
        main()
>>>>>>> UPDATED
```
2023-05-11 17:26:48 -07:00
Paul Gauthier
ac8376c5bc wip: Changed import from redirect_stdout to redirect_stdin in test_main.py. 2023-05-11 17:25:32 -07:00
Paul Gauthier
fe5e313a75 aider: Replaced redirect_stdout with redirect_stdin and opened os.devnull in read mode ('r') instead of write mode ('w').
# Context:
USER: stdin not stdout
ASSISTANT: I apologize for the confusion. To redirect stdin instead of stdout, we need to use `contextlib.redirect_stdin` instead of `contextlib.redirect_stdout`. Here's the updated code change for tests/test_main.py:

```python
tests/test_main.py
<<<<<<< ORIGINAL
    with open(os.devnull, 'w') as dev_null:
        with redirect_stdout(dev_null):
=======
    with open(os.devnull, 'r') as dev_null:
        with redirect_stdin(dev_null):
>>>>>>> UPDATED
            main()
```

This code change replaces `redirect_stdout` with `redirect_stdin` and opens os.devnull in read mode ('r') instead of write mode ('w').
2023-05-11 17:24:57 -07:00
Paul Gauthier
4928450ccf aider: Added a test case for main which creates a temporary directory, changes the current working directory, and invokes the main function with /dev/null piped to stdout.
# Context:
USER: add a test case for main which makes a new empty dir, makes it the cwd and invokes main() with /dev/null piped to stdin.
ASSISTANT: To add a test case for main, we need to import the necessary modules, create a temporary directory, change the current working directory, and invoke the main function with /dev/null piped to stdin. Here's the code change for tests/test_main.py:

```python
tests/test_main.py
<<<<<<< ORIGINAL

=======
import os
import sys
import tempfile
from contextlib import redirect_stdout
from unittest import TestCase
from aider.main import main

class TestMain(TestCase):
    def test_main_with_dev_null(self):
        with tempfile.TemporaryDirectory() as temp_dir:
            os.chdir(temp_dir)
            with open(os.devnull, 'w') as dev_null:
                with redirect_stdout(dev_null):
                    main()
>>>>>>> UPDATED
```

This code change imports the necessary modules, creates a new test class `TestMain`, and adds a test method `test_main_with_dev_null`. The test method creates a temporary directory, changes the current working directory to the temporary directory, and invokes the `main` function with /dev/null piped to stdout.
2023-05-11 17:24:29 -07:00
Paul Gauthier
88b48bd04b noop 2023-05-11 17:22:58 -07:00
Paul Gauthier
db7aa7cdf1 aider: Created and added tests/test_main.py to git. 2023-05-11 17:17:50 -07:00
Paul Gauthier
7c50fd654a aider: Passed argv to main() and parse_args().
# Context:
USER: have __main__ pass argv to main(). then pass that into parse_args
ASSISTANT: To pass `argv` to `main()` and then pass it to `parse_args`, you need to modify the `main()` function definition to accept an argument and pass `sys.argv[1:]` to it. Then, pass the argument to `parse_args()`.

Here's the change:

```python
aider/main.py
<<<<<<< ORIGINAL
def main():
=======
def main(argv):
>>>>>>> UPDATED

aider/main.py
<<<<<<< ORIGINAL
    args = parser.parse_args()
=======
    args = parser.parse_args(argv)
>>>>>>> UPDATED

aider/main.py
<<<<<<< ORIGINAL
    status = main()
=======
    status = main(sys.argv[1:])
>>>>>>> UPDATED
```
2023-05-11 17:16:40 -07:00
Paul Gauthier
6133eb61c1 fix tests and bug 2023-05-11 17:15:19 -07:00