Commit graph

270 commits

Author SHA1 Message Date
Paul Gauthier
edc70bdf84 Handle multiline tool_error() better 2024-05-13 11:42:22 -07:00
Paul Gauthier
90c0a5b9a4 reflect multiple messages; do not strip edit error messages 2024-05-11 16:40:37 -07:00
Joshua Vial
f9ba8e7b41 Remove unnecessary comment and method call in Commands class. 2023-12-11 22:24:02 +13:00
Joshua Vial
d8f33a8124 Auto switch to gpt-4-vision-preview if image files added to context 2023-11-29 22:48:45 +13:00
Paul Gauthier
bf6cd8294e handle submodules (or other dirs) which are git tracked #336 2023-11-15 13:34:29 -08:00
Paul Gauthier
f3d3815201 Armor AutoCompleter against unicode errors #305 2023-11-03 07:26:21 -07:00
Paul Gauthier
b6b271b70c pass the input history as a prompt to whisper 2023-08-11 11:03:37 -03:00
Paul Gauthier
9815d14368 rename 2023-08-11 10:49:27 -03:00
Paul Gauthier
3ff2cb8dbe append voice messages to input history 2023-08-10 17:17:51 -03:00
Paul Gauthier
fed24aa444 lint 2023-08-10 16:53:34 -03:00
Paul Gauthier
ec91eb670e Refactor cmd_voice method to use user_input method instead of tool_output. 2023-08-10 16:23:35 -03:00
Paul Gauthier
1f07de8670 Added hint to Use --encoding to set the unicode encoding. 2023-07-17 08:19:21 -03:00
Paul Gauthier
e7f35e2cf7 Apparently prompt toolkit can not express control-enter? 2023-07-16 14:26:49 -03:00
Paul Gauthier
36af2a51af Change keybinding from ControlJ to ControlM for inserting a new line.
# Aider chat conversation:
2023-07-16 14:15:18 -03:00
Paul Gauthier
6244df8352 aider: get_input now treats control+enter as a newline with prompt toolkit KeyBindings.
# Aider chat conversation:

USER: can we have `get_input` treat control+enter as a newline with prompt toolkit KeyBindings

ASSISTANT: To implement this feature, we need to modify the `get_input` method in the `InputOutput` class in the `aider/io.py` file. We will use the `KeyBindings` class from `prompt_toolkit.keys` to bind the `Control+Enter` key combination to insert a newline.

Here are the changes:

```python
aider/io.py
<<<<<<< ORIGINAL
from prompt_toolkit.shortcuts import CompleteStyle, PromptSession, prompt
=======
from prompt_toolkit.shortcuts import CompleteStyle, PromptSession, prompt
from prompt_toolkit.keys import Keys
from prompt_toolkit.key_binding import KeyBindings
>>>>>>> UPDATED

```python
aider/io.py
<<<<<<< ORIGINAL
            session = PromptSession(**session_kwargs)
=======
            kb = KeyBindings()

            @kb.add(Keys.ControlJ, eager=True)
            def _(event):
                event.current_buffer.insert_text('\n')

            session = PromptSession(key_bindings=kb, **session_kwargs)
>>>>>>> UPDATED
```

This code creates a new `KeyBindings` instance and adds a binding for `Control+Enter` (represented by `Keys.ControlJ`) to insert a newline. Then, it passes this key bindings instance to the `PromptSession` constructor.
2023-07-16 14:12:01 -03:00
Paul Gauthier
9bc450977d Remove last naive open()s 2023-07-10 15:32:23 -07:00
Paul Gauthier
3c443d68d0 working test 2023-07-06 10:55:38 -07:00
Paul Gauthier
391088fd14 add self.dry_run 2023-07-05 21:22:12 -07:00
Paul Gauthier
4ee5c49a04 have io.write_text handle dry_run 2023-07-05 21:20:22 -07:00
Paul Gauthier
b46dffbb20 refactor to use io.write_text 2023-07-05 21:18:19 -07:00
Paul Gauthier
0ea52b412f cleanup 2023-07-05 21:11:46 -07:00
Paul Gauthier
1808c47d96 aider: Added write_text function to InputOutput class in aider/io.py.
# Context:
USER: add a write_text func
ASSISTANT: To add a `write_text` function to the `InputOutput` class in the `aider/io.py` file, we need to modify the `aider/io.py` file.

Here is the change:

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

    def read_text(self, filename):
        try:
            with open(filename, "r", encoding=self.encoding) as f:
                return f.read()
        except (FileNotFoundError, UnicodeError) as e:
            self.tool_error(f"{filename}: {e}")
            return
=======

    def read_text(self, filename):
        try:
            with open(filename, "r", encoding=self.encoding) as f:
                return f.read()
        except (FileNotFoundError, UnicodeError) as e:
            self.tool_error(f"{filename}: {e}")
            return

    def write_text(self, filename, content):
        try:
            with open(filename, "w", encoding=self.encoding) as f:
                f.write(content)
        except (FileNotFoundError, UnicodeError) as e:
            self.tool_error(f"{filename}: {e}")
            return
>>>>>>> UPDATED
```

This `write_text` function takes a filename and content as arguments, opens the file in write mode, and writes the content to the file. If there is a `FileNotFoundError` or `UnicodeError`, it calls the `tool_error` method with the error message.
2023-07-05 21:11:30 -07:00
Paul Gauthier
c2c80bbd3c do not /add files that fail to decode 2023-07-05 21:00:10 -07:00
Paul Gauthier
c8fb1ddaa7 refactor to use io.read_text 2023-07-05 20:46:15 -07:00
Paul Gauthier
5f9947a727 aider: Add read_text function to InputOutput class and --encoding command-line switch.
# Context:
USER: Add a read_text function to the InputOutput class. It takes the file name as argument, and returns the text for that file. Internally, if we get a Unicode error or a FileNotFound error, it prints ToolErrorOutput to notify the user, and then returns None. Add a command-line switch, and dash-dash encoding, which defaults to UTF-8. That's the encoding which will be used by the read_text function.

ASSISTANT: To implement the requested changes, we need to modify the following files:

1. `aider/io.py`: To add the `read_text` function to the `InputOutput` class.
2. `aider/main.py`: To add the `--encoding` command-line switch.

Let's start with the changes to `aider/io.py`:

```python
aider/io.py
<<<<<<< ORIGINAL
class InputOutput:
    num_error_outputs = 0
    num_user_asks = 0

    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
        if self.output:
            self.pretty = False

        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=False, no_color=True)

        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.append_chat_history(f"\n# aider chat started at {current_time}\n\n")
=======
class InputOutput:
    num_error_outputs = 0
    num_user_asks = 0

    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",
        encoding="utf-8",
    ):
        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
        if self.output:
            self.pretty = False

        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.encoding = encoding

        if pretty:
            self.console = Console()
        else:
            self.console = Console(force_terminal=False, no_color=True)

        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.append_chat_history(f"\n# aider chat started at {current_time}\n\n")

    def read_text(self, filename):
        try:
            with open(filename, "r", encoding=self.encoding) as f:
                return f.read()
        except (FileNotFoundError, UnicodeError) as e:
            self.tool_error(str(e))
            return None
>>>>>>> UPDATED
```

Now, let's add the `--encoding` command-line switch to `aider/main.py`:

```python
aider/main.py
<<<<<<< ORIGINAL
    parser.add_argument(
        "--no-dirty-commits",
        action="store_false",
        dest="dirty_commits",
        help="Disable commits when repo is found dirty",
    )
    parser.add_argument(
        "--openai-api-key",
        metavar="OPENAI_API_KEY",
        help="Specify the OpenAI API key",
        env_var="OPENAI_API_KEY",
    )
    parser.add_argument(
        "--openai-api-base",
        metavar="OPENAI_API_BASE",
        default="https://api.openai.com/v1",
        help="Specify the OpenAI API base endpoint (default: https://api.openai.com/v1)",
    )
=======
    parser.add_argument(
        "--no-dirty-commits",
        action="store_false",
        dest="dirty_commits",
        help="Disable commits when repo is found dirty",
    )
    parser.add_argument(
        "--encoding",
        default="utf-8",
        help="Specify the encoding to use when reading files (default: utf-8)",
    )
    parser.add_argument(
        "--openai-api-key",
        metavar="OPENAI_API_KEY",
        help="Specify the OpenAI API key",
        env_var="OPENAI_API_KEY",
    )
    parser.add_argument(
        "--openai-api-base",
        metavar="OPENAI_API_BASE",
        default="https://api.openai.com/v1",
        help="Specify the OpenAI API base endpoint (default: https://api.openai.com/v1)",
    )
>>>>>>> UPDATED
```

These changes should implement the requested functionality. Please review and let me know if any further changes are needed.
2023-07-05 19:33:59 -07:00
Paul Gauthier
43103978b5 cleanup 2023-07-05 14:44:45 -07:00
Paul Gauthier
640a463a9c no pretty when output 2023-07-05 14:42:42 -07:00
Paul Gauthier
e34078da04 force_terminal=False 2023-07-05 14:38:35 -07:00
Paul Gauthier
e1e8e8e10a Turn off fancy Console if self.output 2023-07-05 14:36:13 -07:00
Paul Gauthier
5d18ebd724 fixed file not found in autocompleter, issue #30 2023-07-04 12:38:36 -07:00
Paul Gauthier
1370da14fb track and report errors/asks during benchmarking 2023-06-26 10:33:16 -07:00
Paul Gauthier
146efe3278 Allow yes to be False 2023-06-24 13:38:54 -07:00
Paul Gauthier
9e506cccb0 log with_message 2023-06-23 19:09:39 -07:00
Paul Gauthier
c21ef8dd92 more flexible multiline invocation 2023-06-23 14:00:22 -07:00
Paul Gauthier
b6f682151d Fix issue with quoting /commands 2023-06-05 11:49:27 -07:00
Paul Gauthier
579fc39d61 rename 2023-06-05 11:32:26 -07:00
Paul Gauthier
6b4c54d117 Merge branch 'main' into call-graph 2023-05-30 11:45:39 -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
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
27bd993cab Merge branch 'main' into call-graph 2023-05-29 11:18:30 -07:00
Paul Gauthier
92cd2f3ce6 isort 2023-05-28 22:47:38 -07:00
Paul Gauthier
d2284447c3 Only no_color, not force_term 2023-05-28 06:12:06 -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