Commit graph

7087 commits

Author SHA1 Message Date
Paul Gauthier
29ca124f5f Fixed persisting ident cache 2023-05-30 16:52:28 -07:00
Paul Gauthier
311fc1d6e1 aider: Persist the IDENT_CACHE to .aider.ident.cache whenever it is updated.
# Context:
USER: persist the `IDENT_CACHE` to .aider.ident.cache whenever it is updated
ASSISTANT: To persist the `IDENT_CACHE` to `.aider.ident.cache` whenever it is updated, we need to modify the `get_name_identifiers` method in the `RepoMap` class. Here are the changes:

```python
aider/repomap.py
<<<<<<< ORIGINAL
    def get_name_identifiers(self, fname, uniq=True):
        file_mtime = os.path.getmtime(fname)
        cache_key = fname
        if cache_key in self.IDENT_CACHE and self.IDENT_CACHE[cache_key]["mtime"] == file_mtime:
            idents = self.IDENT_CACHE[cache_key]["data"]
        else:
            idents = self.get_name_identifiers_uncached(fname)
            self.IDENT_CACHE[cache_key] = {"mtime": file_mtime, "data": idents}
=======
import json

class RepoMap:
    # ...
    IDENT_CACHE_FILE = ".aider.ident.cache"

    def __init__(self, use_ctags=None, root=None, main_model="gpt-4"):
        # ...
        self.load_ident_cache()

    def load_ident_cache(self):
        if os.path.exists(self.IDENT_CACHE_FILE):
            with open(self.IDENT_CACHE_FILE, "r") as f:
                self.IDENT_CACHE = json.load(f)
        else:
            self.IDENT_CACHE = dict()

    def save_ident_cache(self):
        with open(self.IDENT_CACHE_FILE, "w") as f:
            json.dump(self.IDENT_CACHE, f)

    def get_name_identifiers(self, fname, uniq=True):
        file_mtime = os.path.getmtime(fname)
        cache_key = fname
        if cache_key in self.IDENT_CACHE and self.IDENT_CACHE[cache_key]["mtime"] == file_mtime:
            idents = self.IDENT_CACHE[cache_key]["data"]
        else:
            idents = self.get_name_identifiers_uncached(fname)
            self.IDENT_CACHE[cache_key] = {"mtime": file_mtime, "data": idents}
            self.save_ident_cache()
>>>>>>> UPDATED
```

This will load the `IDENT_CACHE` from the `.aider.ident.cache` file when the `RepoMap` class is initialized and save the cache to the file whenever it is updated.
2023-05-30 16:50:56 -07:00
Paul Gauthier
49374d04b5 aider: Made IDENT_CACHE use mtime like TAGS_CACHE.
# Context:
USER: make `IDENT_CACHE` use mtime like `TAGS_CACHE`
ASSISTANT: To make `IDENT_CACHE` use mtime like `TAGS_CACHE`, we need to modify the `get_name_identifiers` and `get_name_identifiers_uncached` methods in the `RepoMap` class. Here are the changes:

```python
aider/repomap.py
<<<<<<< ORIGINAL
    def get_name_identifiers(self, fname, uniq=True):
        idents = self.IDENT_CACHE.get(fname)
        if idents is None:
            idents = self.get_name_identifiers_uncached(fname)
            self.IDENT_CACHE[fname] = idents
=======
    def get_name_identifiers(self, fname, uniq=True):
        file_mtime = os.path.getmtime(fname)
        cache_key = fname
        if cache_key in self.IDENT_CACHE and self.IDENT_CACHE[cache_key]["mtime"] == file_mtime:
            idents = self.IDENT_CACHE[cache_key]["data"]
        else:
            idents = self.get_name_identifiers_uncached(fname)
            self.IDENT_CACHE[cache_key] = {"mtime": file_mtime, "data": idents}
>>>>>>> UPDATED

```
2023-05-30 16:49:12 -07:00
Paul Gauthier
a7ca584859 refac 2023-05-30 16:47:50 -07:00
Paul Gauthier
4a1e252bfc noop 2023-05-30 14:25:55 -07:00
Paul Gauthier
313968415a wip 2023-05-30 14:15:29 -07:00
Paul Gauthier
2353e54628 moved get_name_identifiers 2023-05-30 14:07:05 -07:00
Paul Gauthier
497b04acd3 Merge branch 'main' into call-graph 2023-05-30 13:57:16 -07:00
Paul Gauthier
77d20b6819 Fixed TAGS_CACHE 2023-05-30 13:54:56 -07:00
Paul Gauthier
5801bd9ca4 aider: Moved TAGS_CACHE into the RepoMap class.
# Context:
USER: move `TAGS_CACHE` into the class
ASSISTANT: To move the `TAGS_CACHE` into the `RepoMap` class, I will make the following changes:

```python
aider/repomap.py
<<<<<<< ORIGINAL
# Global cache for tags
TAGS_CACHE = {}
=======
>>>>>>> UPDATED
```

```python
aider/repomap.py
<<<<<<< ORIGINAL
class RepoMap:
    ctags_cmd = ["ctags", "--fields=+S", "--extras=-F", "--output-format=json"]

    def __init__(self, use_ctags=None, root=None, main_model="gpt-4"):
=======
    class RepoMap:
        ctags_cmd = ["ctags", "--fields=+S", "--extras=-F", "--output-format=json"]
        TAGS_CACHE = {}

        def __init__(self, use_ctags=None, root=None, main_model="gpt-4"):
>>>>>>> UPDATED
```

Now, the `TAGS_CACHE` is a class attribute of the `RepoMap` class.
2023-05-30 13:53:31 -07:00
Paul Gauthier
6b4c54d117 Merge branch 'main' into call-graph 2023-05-30 11:45:39 -07:00
Paul Gauthier
ca74eee2f9 Allow GPT to omit the filename from edit blocks, if an earlier block provided it 2023-05-30 11:45:21 -07:00
Paul Gauthier
9cb793c82d reverted c9ebbdf0 2023-05-30 07:58:54 -07:00
Paul Gauthier
b359134f86 reverted a4e57e17b5 2023-05-30 07:58:31 -07:00
Paul Gauthier
a4e57e17b5 aider: Added completions_height parameter to InputOutput class and passed it from aider/main.py.
# Context:
USER: pass it to `InputOutput` and store as a self. var
ASSISTANT: I will modify the `InputOutput` class in `aider/io.py` to accept the `completions_height` parameter and store it as an instance variable.

Here's the change to add the `completions_height` parameter to the `InputOutput` class:

```python
aider/io.py

^C KeyboardInterrupt
USER: `aider/io.py`
ASSISTANT: I will modify the `InputOutput` class in `aider/io.py` to accept the `completions_height` parameter and store it as an instance variable.

Here's the change to add the `completions_height` parameter to the `InputOutput` class:

```python
aider/io.py
<<<<<<< ORIGINAL
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
        user_input_color="blue",
        tool_output_color=None,
        tool_error_color="red",
    ):
=======
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
        user_input_color="blue",
        tool_output_color=None,
        tool_error_color="red",
        completions_height=10,
    ):
        self.completions_height = completions_height
>>>>>>> UPDATED
```

Now, you need to pass the `completions_height` value from `aider/main.py` to the `InputOutput` class when creating an instance:

```python
aider/main.py
<<<<<<< ORIGINAL
    io = InputOutput(
        args.pretty,
        args.yes,
        args.input_history_file,
        args.chat_history_file,
        input=input,
        output=output,
        user_input_color=args.user_input_color,
        tool_output_color=args.tool_output_color,
        tool_error_color=args.tool_error_color,
    )
=======
    io = InputOutput(
        args.pretty,
        args.yes,
        args.input_history_file,
        args.chat_history_file,
        input=input,
        output=output,
        user_input_color=args.user_input_color,
        tool_output_color=args.tool_output_color,
        tool_error_color=args.tool_error_color,
        completions_height=args.completions_height,
    )
>>>>>>> UPDATED
```

Now, the `completions_height` value is passed to the `InputOutput` class and stored as an instance variable.
2023-05-29 17:33:39 -07:00
Paul Gauthier
c9ebbdf0c0 aider: Added a --completions-height command line parameter to aider/main.py.
# Context:
USER: add a --completions-height cmd line param to `aider/main.py`
ASSISTANT: I will add a `--completions-height` command line parameter to `aider/main.py`. This parameter will allow users to set the height of the completions displayed in the terminal.

Here's the change to add the `--completions-height` parameter:

```python
aider/main.py
<<<<<<< ORIGINAL
    parser.add_argument(
        "--no-dirty-commits",
        action="store_false",
        dest="dirty_commits",
        help="Disable dirty commit of changes",
    )
=======
    parser.add_argument(
        "--no-dirty-commits",
        action="store_false",
        dest="dirty_commits",
        help="Disable dirty commit of changes",
    )
    parser.add_argument(
        "--completions-height",
        type=int,
        default=10,
        metavar="COMPLETIONS_HEIGHT",
        help="Set the height of the completions displayed in the terminal (default: 10)",
    )
>>>>>>> UPDATED
```

This will add a new command line argument `--completions-height` with a default value of 10. Users can now set the height of the completions displayed in the terminal by providing a value for this argument.
2023-05-29 17:32:02 -07:00
Paul Gauthier
e25cf11aff stronger prompt against editing r/o files 2023-05-29 15:02:51 -07:00
Paul Gauthier
2ff24a51dd bold italic 2023-05-29 12:13:28 -07:00
Paul Gauthier
fbb14b2823 aider: Changed pygments.literal.string to appear in inverse colors.
# Context:
USER: no. let's make pygments.literal.string be in inverse colors
ASSISTANT: To make `pygments.literal.string` appear in inverse colors, we need to modify the `aider/io.py` file. Update the `style` dictionary in the `get_input` method:

```python
aider/io.py
<<<<<<< ORIGINAL
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color, "pygments.literal.string": f"underline {self.user_input_color}"})
=======
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color, "pygments.literal.string": f"reverse {self.user_input_color}"})
>>>>>>> UPDATED
```

This change will apply the inverse color style to ticked words in the `PromptSession`.
2023-05-29 11:49:50 -07:00
Paul Gauthier
8f40f08636 aider: Updated the style dictionary in get_input method to apply underline style and self.user_input_color to ticked words.
# Context:
USER: underlined and self.user_input_color
ASSISTANT: To underline ticked words and apply the `self.user_input_color`, we need to modify the `aider/io.py` file. Update the `style` dictionary in the `get_input` method:

```python
aider/io.py
<<<<<<< ORIGINAL
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color, "pygments.literal.string": "underline"})
=======
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color, "pygments.literal.string": f"underline {self.user_input_color}"})
>>>>>>> UPDATED
```

This change will apply the underline style and the `self.user_input_color` to ticked words in the `PromptSession`.
2023-05-29 11:48:22 -07:00
Paul Gauthier
507442da3f aider: Added underline style to ticked words in PromptSession.
# Context:
USER: can we override the style for `ticked` words to just underline them, not change the color?
ASSISTANT: Yes, we can override the style for ticked words to underline them without changing the color. We need to modify the `aider/io.py` file. Update the `style` dictionary in the `InputOutput` class's `__init__` method:

```python
aider/io.py
<<<<<<< ORIGINAL
        if self.user_input_color:
            style = Style.from_dict
^C KeyboardInterrupt
USER: no, just for the markdown highlighting in the `PromptSession`
ASSISTANT: I apologize for the misunderstanding. To override the style for ticked words in the `PromptSession`, we need to modify the `aider/io.py` file. Update the `style` dictionary in the `get_input` method:

```python
aider/io.py
<<<<<<< ORIGINAL
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color})
=======
        if self.user_input_color:
            style = Style.from_dict({"": self.user_input_color, "pygments.literal.string": "underline"})
>>>>>>> UPDATED
```

This change will apply the underline style to ticked words in the `PromptSession` without changing their color.
2023-05-29 11:46:57 -07:00
Paul Gauthier
4a4d0efe89 aider: Replaced MarkdownLexer with PygmentsLexer to correctly highlight user input with markdown syntax.
# Context:
USER: AttributeError: 'MarkdownLexer' object has no attribute 'lex_document'
ASSISTANT: I apologize for the confusion. It seems I misunderstood the usage of `MarkdownLexer` with `prompt_toolkit`. Instead, we should use `PygmentsLexer` from `prompt_toolkit.lexers` to wrap the `MarkdownLexer`. Here's the updated change:

First, import `PygmentsLexer` from `prompt_toolkit.lexers`:

```python
aider/io.py
<<<<<<< ORIGINAL
from prompt_toolkit.completion import Completer, Completion
=======
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.lexers import PygmentsLexer
>>>>>>> UPDATED
```

Then, update the `PromptSession` instantiation in the `get_input` method:

```python
aider/io.py
<<<<<<< ORIGINAL
            session_kwargs = {
                "message": show,
                "completer": completer_instance,
                "reserve_space_for_menu": 4,
                "complete_style": CompleteStyle.MULTI_COLUMN,
                "input": self.input,
                "output": self.output,
                "lexer": MarkdownLexer(),
            }
=======
            session_kwargs = {
                "message": show,
                "completer": completer_instance,
                "reserve_space_for_menu": 4,
                "complete_style": CompleteStyle.MULTI_COLUMN,
                "input": self.input,
                "output": self.output,
                "lexer": PygmentsLexer(MarkdownLexer),
            }
>>>>>>> UPDATED
```

These changes will correctly use the `MarkdownLexer` with `prompt_toolkit` to highlight the user input with markdown syntax.
2023-05-29 11:43:50 -07:00
Paul Gauthier
2a0761b0ce aider: Added MarkdownLexer to highlight user input with markdown syntax.
# Context:
USER: have `prompt_toolkit` highlight the user input with a markdown lexer
ASSISTANT: To highlight the user input with a markdown lexer, we need to modify the `aider/io.py` file. We will import the `MarkdownLexer` from `pygments.lexers.markup` and use it as the lexer for the `PromptSession`.

Here's the change you need to make:

```python
aider/io.py
<<<<<<< ORIGINAL
from pygments.lexers import guess_lexer_for_filename
=======
from pygments.lexers import guess_lexer_for_filename, MarkdownLexer
>>>>>>> UPDATED
```

And update the `PromptSession` instantiation in the `get_input` method:

```python
aider/io.py
<<<<<<< ORIGINAL
            session_kwargs = {
                "message": show,
                "completer": completer_instance,
                "reserve_space_for_menu": 4,
                "complete_style": CompleteStyle.MULTI_COLUMN,
                "input": self.input,
                "output": self.output,
            }
=======
            session_kwargs = {
                "message": show,
                "completer": completer_instance,
                "reserve_space_for_menu": 4,
                "complete_style": CompleteStyle.MULTI_COLUMN,
                "input": self.input,
                "output": self.output,
                "lexer": MarkdownLexer(),
            }
>>>>>>> UPDATED
```

These changes will import the `MarkdownLexer` and use it for the `PromptSession`, which will highlight the user input with markdown syntax.
2023-05-29 11:42:19 -07:00
Paul Gauthier
e4805490f5 quote autocompletions 2023-05-29 11:32:50 -07:00
Paul Gauthier
d28cb2beea noop 2023-05-29 11:27:19 -07:00
Paul Gauthier
27bd993cab Merge branch 'main' into call-graph 2023-05-29 11:18:30 -07:00
Paul Gauthier
445c253abc fixed corner case bugs in find_original_update_blocks 2023-05-29 07:12:57 -07:00
Paul Gauthier
87c902b285 aider: Fixed IndexError in find_original_update_blocks function.
# Context:
USER: I ran this command:

 pytest tests/test_utils.py

And got this output:

============================= test session starts ==============================
platform darwin -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0
rootdir: /Users/gauthier/Projects/aider
collected 11 items

tests/test_utils.py F..........                                          [100%]

=================================== FAILURES ===================================
__________________ TestUtils.test_false_incomplete_edit_block __________________

content = '\nNo problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:\n\n`...h `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.\n'

    def find_original_update_blocks(content):
        # make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
        if not content.endswith("\n"):
            content = content + "\n"

        pieces = re.split(split_re, content)

        pieces.reverse()
        processed = []

        try:
            while pieces:
                cur = pieces.pop()

                if cur in (DIVIDER, UPDATED):
                    processed.append(cur)
                    raise ValueError(f"Unexpected {cur}")

                if cur.strip() != ORIGINAL:
                    processed.append(cur)
                    continue

                processed.append(cur)  # original_marker

                filename = processed[-2].splitlines()[-1].strip()
                if not len(filename) or "`" in filename:
>                   filename = processed[-2].splitlines()[-2].strip()
E                   IndexError: list index out of range

aider/utils.py:234: IndexError

During handling of the above exception, another exception occurred:

self = <tests.test_utils.TestUtils testMethod=test_false_incomplete_edit_block>

        def test_false_incomplete_edit_block(self):
            edit = """
    No problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:

    ```python
    tests/test_repomap.py
    <<<<<<< ORIGINAL
        def test_check_for_ctags_failure(self):
            with patch("subprocess.run") as mock_run:
                mock_run.side_effect = Exception("ctags not found")
    =======
        def test_check_for_ctags_failure(self):
            with patch("subprocess.check_output") as mock_check_output:
                mock_check_output.side_effect = Exception("ctags not found")
    >>>>>>> UPDATED

    <<<<<<< ORIGINAL
        def test_check_for_ctags_success(self):
            with patch("subprocess.run") as mock_run:
                mock_run.return_value = CompletedProcess(args=["ctags", "--version"], returncode=0, stdout='''{
      "_type": "tag",
      "name": "status",
      "path": "aider/main.py",
      "pattern": "/^    status = main()$/",
      "kind": "variable"
    }''')
    =======
        def test_check_for_ctags_success(self):
            with patch("subprocess.check_output") as mock_check_output:
                mock_check_output.return_value = '''{
      "_type": "tag",
      "name": "status",
      "path": "aider/main.py",
      "pattern": "/^    status = main()$/",
      "kind": "variable"
    }'''
    >>>>>>> UPDATED
    ```

    These changes replace the `subprocess.run` patches with `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.
    """
            # Should not raise a ValueError
>           list(utils.find_original_update_blocks(edit))

tests/test_utils.py:199:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

content = '\nNo problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:\n\n`...h `subprocess.check_output` patches in both `test_check_for_ctags_failure` and `test_check_for_ctags_success` tests.\n'

    def find_original_update_blocks(content):
        # make sure we end with a newline, otherwise the regex will miss <<UPD on the last line
        if not content.endswith("\n"):
            content = content + "\n"

        pieces = re.split(split_re, content)

        pieces.reverse()
        processed = []

        try:
            while pieces:
                cur = pieces.pop()

                if cur in (DIVIDER, UPDATED):
                    processed.append(cur)
                    raise ValueError(f"Unexpected {cur}")

                if cur.strip() != ORIGINAL:
                    processed.append(cur)
                    continue

                processed.append(cur)  # original_marker

                filename = processed[-2].splitlines()[-1].strip()
                if not len(filename) or "`" in filename:
                    filename = processed[-2].splitlines()[-2].strip()
                    if not len(filename) or "`" in filename:
                        raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")

                original_text = pieces.pop()
                processed.append(original_text)

                divider_marker = pieces.pop()
                processed.append(divider_marker)
                if divider_marker.strip() != DIVIDER:
                    raise ValueError(f"Expected {DIVIDER}")

                updated_text = pieces.pop()

                updated_marker = pieces.pop()
                if updated_marker.strip() != UPDATED:
                    raise ValueError(f"Expected {UPDATED}")

                yield filename, original_text, updated_text
        except ValueError as e:
            processed = "".join(processed)
            err = e.args[0]
            raise ValueError(f"{processed}\n^^^ {err}")
        except IndexError:
            processed = "".join(processed)
>           raise ValueError(f"{processed}\n^^^ Incomplete ORIGINAL/UPDATED block.")
E           ValueError:
E           No problem! Here are the changes to patch `subprocess.check_output` instead of `subprocess.run` in both tests:
E
E           ```python
E           tests/test_repomap.py
E           <<<<<<< ORIGINAL
E               def test_check_for_ctags_failure(self):
E                   with patch("subprocess.run") as mock_run:
E                       mock_run.side_effect = Exception("ctags not found")
E           =======
E
E           <<<<<<< ORIGINAL
E
E           ^^^ Incomplete ORIGINAL/UPDATED block.

aider/utils.py:259: ValueError
=========================== short test summary info ============================
FAILED tests/test_utils.py::TestUtils::test_false_incomplete_edit_block - Val...
========================= 1 failed, 10 passed in 0.04s =========================

ASSISTANT: It seems that the test `test_false_incomplete_edit_block` is failing due to an IndexError in the `find_original_update_blocks` function in `aider/utils.py`. I will fix the issue by handling the IndexError properly.

```python
aider/utils.py
<<<<<<< ORIGINAL
    if not len(filename) or "`" in filename:
        filename = processed[-2].splitlines()[-2].strip()
        if not len(filename) or "`" in filename:
            raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
=======
    try:
        if not len(filename) or "`" in filename:
            filename = processed[-2].splitlines()[-2].strip()
            if not len(filename) or "`" in filename:
                raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
    except IndexError:
        raise ValueError(f"Bad/missing filename. It should go right above {ORIGINAL}")
>>>>>>> UPDATED
```

Now, the IndexError should be handled properly, and the test should pass. Please run the tests again to confirm the fix.
2023-05-29 07:09:09 -07:00
Paul Gauthier
92cd2f3ce6 isort 2023-05-28 22:47:38 -07:00
Paul Gauthier
f6197fac40 cleanup 2023-05-28 22:29:21 -07:00
Paul Gauthier
346eb7a834 aider: Replaced string with bytes object in test_check_for_ctags_success to fix 'decode' method issue.
# Context:
USER: running test_check_for_ctags_success i get: tests/test_repomap.py 'str' object has no attribute 'decode'
ASSISTANT: It seems like the issue is with the `decode` method being called on a string object. I'll fix this issue for you. Here's the change you need to make in the `tests/test_repomap.py` file:

```python
tests/test_repomap.py
<<<<<<< ORIGINAL
            mock_run.return_value = CompletedProcess(args=["ctags", "--version"], returncode=0, stdout='''{
  "_type": "tag",
  "name": "status",
  "path": "aider/main.py",
  "pattern": "/^    status = main()$/",
  "kind": "variable"
}''')
=======
            mock_run.return_value = CompletedProcess(args=["ctags", "--version"], returncode=0, stdout=b'''{
  "_type": "tag",
  "name": "status",
  "path": "aider/main.py",
  "pattern": "/^    status = main()$/",
  "kind": "variable"
}''')
>>>>>>> UPDATED
```

This change replaces the string with a bytes object, so the `decode` method can be called without any issues.
2023-05-28 22:18:18 -07:00
Paul Gauthier
37e3e561f0 Fixed /run output to log 2023-05-28 11:20:08 -07:00
Paul Gauthier
67a1d7231c aider: Updated cmd_run method to ask for user approval before adding the output to the chat.
# Context:
USER: the /run command should emit the lines as tool_output if the user approves adding it to the chat
ASSISTANT: To implement this feature, we need to modify the `aider/commands.py` file. Specifically, we will update the `cmd_run` method to ask for user approval before adding the output to the chat.

Please make the `aider/commands.py` file *read-write* so I can provide the necessary changes.
USER: I added these *read-write* files: aider/commands.py
ASSISTANT: Great! Now, I will provide the necessary changes to the `aider/commands.py` file to implement the requested feature.

```python
aider/commands.py
<<<<<<< ORIGINAL
        print(combined_output)

        ok = self.io.confirm_ask("Add the output to the chat?", default="y")
        if not ok:
            return

        msg = prompts.run_output.format(
            command=args,
            output=combined_output,
        )
        return msg
=======
        if self.io.confirm_ask("Add the output to the chat?", default="y"):
            msg = prompts.run_output.format(
                command=args,
                output=combined_output,
            )
            self.io.tool_output(msg, log_only=False)
        else:
            print(combined_output)
>>>>>>> UPDATED
```

This change will ask the user for approval before adding the output to the chat. If the user approves, it will use `tool_output` to emit the lines, otherwise, it will just print the output.
2023-05-28 11:16:08 -07:00
Paul Gauthier
d2284447c3 Only no_color, not force_term 2023-05-28 06:12:06 -07:00
Paul Gauthier
4b8fff69cb copy 2023-05-27 18:01:58 -07:00
Paul Gauthier
321824299a aider: Added check for NO_COLOR environment variable to disable ANSI color.
# Context:
USER: Command-line software which adds ANSI color to its output by default should check for a NO_COLOR environment variable that, when present and not an empty string (regardless of its value), prevents the addition of ANSI color.
ASSISTANT: To implement this feature, we need to modify the `aider/io.py` file. Please make it *read-write* so I can provide the necessary changes.
USER: I added these *read-write* files: aider/io.py
ASSISTANT: Great! Now, I will make the necessary changes to check for the `NO_COLOR` environment variable and disable ANSI color when it is present and not an empty string.

```python
aider/io.py
<<<<<<< ORIGINAL
import os
=======
import os
import os.path
>>>>>>> UPDATED
```

```python
aider/io.py
<<<<<<< ORIGINAL
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
        user_input_color="blue",
        tool_output_color=None,
        tool_error_color="red",
    ):
        self.user_input_color = user_input_color
        self.tool_output_color = tool_output_color
        self.tool_error_color = tool_error_color
        self.input = input
        self.output = output
        self.pretty = pretty
        self.yes = yes
        self.input_history_file = input_history_file
        if chat_history_file is not None:
            self.chat_history_file = Path(chat_history_file)
        else:
            self.chat_history_file = None

        if pretty:
            self.console = Console()
        else:
            self.console = Console(force_terminal=True, no_color=True)
=======
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
        user_input_color="blue",
        tool_output_color=None,
        tool_error_color="red",
    ):
        no_color = os.environ.get("NO_COLOR")
        if no_color is not None and no_color != "":
            pretty = False

        self.user_input_color = user_input_color if pretty else None
        self.tool_output_color = tool_output_color if pretty else None
        self.tool_error_color = tool_error_color if pretty else None
        self.input = input
        self.output = output
        self.pretty = pretty
        self.yes = yes
        self.input_history_file = input_history_file
        if chat_history_file is not None:
            self.chat_history_file = Path(chat_history_file)
        else:
            self.chat_history_file = None

        self.console = Console(force_terminal=not pretty, no_color=not pretty)
>>>>>>> UPDATED
```

These changes will make the software check for the `NO_COLOR` environment variable and disable ANSI color when it is present and not an empty string.
2023-05-27 17:57:32 -07:00
Paul Gauthier
bd78789bd2 Fixed quote stripping of gpt3.5 commit messages 2023-05-27 17:05:57 -07:00
Paul Gauthier
2ec6757f86 aider: Added new arguments --user-input-color, --tool-output-color, and --tool-error-color to main function and passed them to InputOutput class.
# Context:
USER: add args --user-input-color default green, --tool-output-color default None and --tool-error-color default red. pass them to InputOutput
ASSISTANT: I will add the new arguments to the `main` function and pass them to the `InputOutput` class.

```python
aider/main.py
<<<<<<< ORIGINAL
    parser.add_argument(
        "--pretty",
        action="store_true",
        default=True,
        help="Enable pretty, colorized output (default: True)",
    )
    parser.add_argument(
        "--no-pretty",
        action="store_false",
        dest="pretty",
        help="Disable pretty, colorized output",
    )
=======
    parser.add_argument(
        "--pretty",
        action="store_true",
        default=True,
        help="Enable pretty, colorized output (default: True)",
    )
    parser.add_argument(
        "--no-pretty",
        action="store_false",
        dest="pretty",
        help="Disable pretty, colorized output",
    )
    parser.add_argument(
        "--user-input-color",
        default="green",
        help="Set the color for user input (default: green)",
    )
    parser.add_argument(
        "--tool-output-color",
        default=None,
        help="Set the color for tool output (default: None)",
    )
    parser.add_argument(
        "--tool-error-color",
        default="red",
        help="Set the color for tool error messages (default: red)",
    )
>>>>>>> UPDATED
```

```python
aider/main.py
<<<<<<< ORIGINAL
    io = InputOutput(
        args.pretty,
        args.yes,
        args.input_history_file,
        args.chat_history_file,
        input=input,
        output=output,
    )
=======
    io = InputOutput(
        args.pretty,
        args.yes,
        args.input_history_file,
        args.chat_history_file,
        input=input,
        output=output,
        user_input_color=args.user_input_color,
        tool_output_color=args.tool_output_color,
        tool_error_color=args.tool_error_color,
    )
>>>>>>> UPDATED
```

Now the new arguments are added and passed to the `InputOutput` class.
2023-05-27 15:21:57 -07:00
Paul Gauthier
0fa660066f color the hrule 2023-05-27 15:19:53 -07:00
Paul Gauthier
70b912250a rename 2023-05-27 15:18:31 -07:00
Paul Gauthier
b8e480d699 rename 2023-05-27 15:18:13 -07:00
Paul Gauthier
cc9b21df06 renamed io.tool() -> io.tool_output() 2023-05-27 15:17:33 -07:00
Paul Gauthier
f6d07d9849 Accept colors for various prompts 2023-05-27 15:14:56 -07:00
Paul Gauthier
03cc679a5b aider: Added tool_color and tool_error_color properties to InputOutput class and updated style and console print accordingly.
# Context:
USER: move the red and green colors for tool and tool_error into self. properties. add args to init with red and green defaults.
ASSISTANT: To make the changes, I will modify the `aider/io.py` file. Here are the changes:

```python
aider/io.py
<<<<<<< ORIGINAL
class InputOutput:
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
    ):
=======
class InputOutput:
    def __init__(
        self,
        pretty=True,
        yes=False,
        input_history_file=None,
        chat_history_file=None,
        input=None,
        output=None,
        tool_color="green",
        tool_error_color="red",
    ):
        self.tool_color = tool_color
        self.tool_error_color = tool_error_color
>>>>>>> UPDATED
```

```python
aider/io.py
<<<<<<< ORIGINAL
        style = Style.from_dict({"": "green"})
=======
        style = Style.from_dict({"": self.tool_color})
>>>>>>> UPDATED
```

```python
aider/io.py
<<<<<<< ORIGINAL
        self.console.print(message, style="red")
=======
        self.console.print(message, style=self.tool_error_color)
>>>>>>> UPDATED
```
2023-05-27 14:54:04 -07:00
Paul Gauthier
db4fc2fe23 autocomplete file paths by (unique) basenames 2023-05-27 09:09:33 -07:00
Paul Gauthier
5ba084edec auto-complete filenames 2023-05-27 08:54:10 -07:00
Paul Gauthier
40d764e9f8 removed wip: prefix from dirty commits 2023-05-27 08:49:16 -07:00
Paul Gauthier
767c241e95 Refactor rel_fnames assignment in coder.py. 2023-05-27 08:48:39 -07:00
Paul Gauthier
4bc4e6f611 aider: Updated Coder class in aider/coder.py to call the new get_input function with root parameter and rel_fnames instead of absolute file names.
# Context:
USER: update coder.py to call the new get_input
ASSISTANT: I will update the `Coder` class in the `aider/coder.py` file to call the new `get_input` function.

```python
aider/coder.py
<<<<<<< ORIGINAL
        inp = self.io.get_input(self.abs_fnames, self.commands)
=======
        rel_fnames = [os.path.relpath(fname, self.root) for fname in self.abs_fnames]
        inp = self.io.get_input(self.root, rel_fnames, self.commands)
>>>>>>> UPDATED
```

This change updates the `run_loop` method in the `Coder` class to call the new `get_input` function with the `root` parameter and the `rel_fnames` instead of the absolute file names.
2023-05-27 08:47:21 -07:00
Paul Gauthier
487040203e aider: Updated get_input to take a root param and receive rel_fnames not abs fnames, and updated FileContentCompleter to work with them.
# Context:
USER: change get_input to take a root param and receive rel_fnames not abs fnames. don't compute short_fnames, just use rel_fnames. also update FileContentCompleter to take root and rel_fnames and work with them.
ASSISTANT: To make the requested changes, I need you to provide me with *read-write* access to the following files:

1. `aider/io.py`
2. `aider/prompts.py`

Once you've granted me access to these files, I can provide you with the necessary code modifications.
USER: I added these *read-write* files: aider/io.py
ASSISTANT: Great! I will now make the changes to the `get_input` function and the `FileContentCompleter` class in the `aider/io.py` file.

```python
aider/io.py
<<<<<<< ORIGINAL
class FileContentCompleter(Completer):
    def __init__(self, fnames, commands):
        self.commands = commands

        self.words = set()
        for fname in fnames:
            with open(fname, "r") as f:
                content = f.read()
=======
class FileContentCompleter(Completer):
    def __init__(self, root, rel_fnames, commands):
        self.commands = commands

        self.words = set()
        for rel_fname in rel_fnames:
            fname = os.path.join(root, rel_fname)
            with open(fname, "r") as f:
                content = f.read()
>>>>>>> UPDATED

```python
aider/io.py
<<<<<<< ORIGINAL
    def get_input(self, fnames, commands):
        if self.pretty:
            self.console.rule()
        else:
            print()

        fnames = list(fnames)
        if len(fnames) > 1:
            common_prefix = os.path.commonpath(fnames)
            if not common_prefix.endswith(os.path.sep):
                common_prefix += os.path.sep
            short_fnames = [fname.replace(common_prefix, "", 1) for fname in fnames]
        elif len(fnames):
            short_fnames = [os.path.basename(fnames[0])]
        else:
            short_fnames = []

        show = " ".join(short_fnames)
=======
    def get_input(self, root, rel_fnames, commands):
        if self.pretty:
            self.console.rule()
        else:
            print()

        rel_fnames = list(rel_fnames)
        show = " ".join(rel_fnames)
>>>>>>> UPDATED

```python
aider/io.py
<<<<<<< ORIGINAL
            completer_instance = FileContentCompleter(fnames, commands)
=======
            completer_instance = FileContentCompleter(root, rel_fnames, commands)
>>>>>>> UPDATED
```

These changes will update the `get_input` function to take a `root` parameter and receive `rel_fnames` instead of absolute file names. The `FileContentCompleter` class is also updated to take the `root` and `rel_fnames` parameters and work with them.
2023-05-27 08:46:06 -07:00