prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.34k stars 716 forks source link

Using auto_suggest for copilot-like completions #1913

Open asmeurer opened 1 month ago

asmeurer commented 1 month ago

I'd like to use auto_suggest for copilot like AI auto-completions. However, there seem to be some complications with doing this:

asmeurer commented 1 month ago

I think I can work around the first and last issue by using my own processor separate from auto_suggest. However, the multiline thing seems to be a fundamental limitation in how processors work. I could just use the completion system but it's not particularly ideal for showing multiline completions, and also, I'd ideally like to have traditional tab-completions still available separately from the AI copilot completions.

asmeurer commented 1 month ago

So it turns out completions don't actually support multi-line completions either (it also just replaces them with ^J, and as far as I can tell the design is fundamentally line-based).

I realized that another issue with auto_suggest is that for AI completions you want to limit how often the suggestions are grabbed, either on a timer or based on a keyboard shortcut. The current code assumes they are cheap and grabs them with every text change.

I ended up just copying and modifying the auto_suggest code because it was too incompatible with what I need, but I have something that works pretty well except for the multi-line issue. Any suggestions on how to build a version of AppendAutoSuggestions that can actually add multiple lines would be appreciated.

nitanmarcel commented 1 month ago

Use buffer.on_text_changed and buffer.document.get_word_before_cursor()and buffer.document.insert_line_below to manage the auto completion yourself maybe

https://python-prompt-toolkit.readthedocs.io/en/stable/pages/reference.html#module-prompt_toolkit.document

asmeurer commented 1 month ago

So I found a somewhat hacky workaround for multiline suggestions. In the processor, I can replace all the newlines in the suggestion with enough spaces so that the soft wrapping automatically makes it look like a multiple lines. This works well because the soft wrapping mechanisms seem so to be fairly robust.

The only annoying thing about this is that there doesn't seem to be a way to actually get the width of a buffer in characters. The layout classes nominally has some attributes like width, but they are all set to None. So I have to manually compute the width of my prompt and pass it through (which relies on my specific prompt layout). It would be really nice if there were a way I could just directly access the width of a buffer.

The code is at https://github.com/asmeurer/mypython/blob/master/mypython/processors.py (with AI completion code itself at https://github.com/asmeurer/mypython/blob/master/mypython/ai.py and a few important pieces at https://github.com/asmeurer/mypython/blob/master/mypython/mypython.py and https://github.com/asmeurer/mypython/blob/master/mypython/keys.py as well) for anyone interested. Most of it is copied from the autosuggestion code from prompt-toolkit, but modified to generating and cycling through support multiple suggestions (a la copilot).