blink.cmp
blink.cmp copied to clipboard
WIP: First pass at terminal-mode completions
Hi :)
Following #305 I thought I'd have a crack at terminal-mode completions. This is very much at proof-of-concept stage, but I've enjoyed tinkering with it so far so would be happy to keep working on it if you don't mind feeding back on current progress and advising about design for next steps.
Key things to note:
-
I created
cmp/lib/term_events.luato listen for edits in the terminal. I usedvim.on_key()to achieve this as there's no terminal equivalent for theInsertCharPreevent. I was pretty torn about simply lifting the code fromcmp/lib/cmdline_events.lua, but decided against this as there's a few things there I didn't quite understand, e.g. the use of timers and everything being accomplished byon_cursor_moved(). If you don't mind explaining what these are doing I'll be happy to add equivalent functionality if needed :) -
AFAIK Neovim doesn't provide a convenient API for inserting text into the terminal prompt, so I had to cobble something together using
vim.feedkeys(). I also experimented withvim.paste(), but the results didn't feel good. -
Still to do:
-
Autocompletion immediately triggers after accepting a suggestion. It looks like after accepting a suggestion like
Bla, the final character in the accepted text, in this casea, is once again used to trigger a completion. Unfortunately I couldn't work out how this is avoided in cmdline/insert mode, so very grateful for any pointers here. My guess is that this has something to do with my omission ofon_cursor_moved(), but playing with this functionality hasn't (yet) led me to a fix. -
I haven't added any user-facing configuration for terminal mode. I can imagine this is something most users will want quite fine-grained control over, so I thought I'd seek some pointers on this before diving in.
-
Thanks in advance for review!
AFAIK Neovim doesn't provide a convenient API for inserting text into the terminal prompt, so I had to cobble something together using vim.feedkeys(). I also experimented with vim.paste(), but the results didn't feel good.
You can use chansend() instead.
Autocompletion immediately triggers after accepting a suggestion. It looks like after accepting a suggestion like Bla, the final character in the accepted text, in this case a, is once again used to trigger a completion. Unfortunately I couldn't work out how this is avoided in cmdline/insert mode, so very grateful for any pointers here. My guess is that this has something to do with my omission of on_cursor_moved(), but playing with this functionality hasn't (yet) led me to a fix.
It is known issue. I think auto insert feature should be disabled in terminal mode.
You can use
chansend()instead.
Thanks, done! This has also fixed the issue with completions being triggered after accepting :)
It is known issue. I think auto insert feature should be disabled in terminal mode.
Thanks, good to know. Agreed - I'll look into this.
Wow, this looks great, thank you!
I was pretty torn about simply lifting the code from
cmp/lib/cmdline_events.lua, but decided against this as there's a few things there I didn't quite understand, e.g. the use of timers and everything being accomplished byon_cursor_moved()
That code is truly cursed :joy: The idea is that when the user types, we trigger the on_text_changed(char) and when the user moves the cursor or deletes a character, we trigger on_cursor_moved(). There's no CursorMovedC event in neovim 0.10 (coming in 0.11), so for on_cursor_moved, I've written a hack that checks every 16ms if the cursor position has changed, and that the text hasn't changed (unless backspace was pressed). It's likely that with your on_key solution, you could use CursorMoved directly similar to buffer_events.lua, rather than hacking around.
I haven't added any user-facing configuration for terminal mode. I can imagine this is something most users will want quite fine-grained control over, so I thought I'd seek some pointers on this before diving in.
For now, I think it would be enough to support keymaps.term and sources.term as that would match where cmdline is at
Thanks for the review! And for explaining the cmdline code 😁
It's likely that with your
on_keysolution, you could useCursorMoveddirectly similar to buffer_events.lua, rather than hacking around.
I think things are working correctly as-is? It's possible that there are edge cases I haven't checked yet though...
For now, I think it would be enough to support
keymaps.termandsources.termas that would match where cmdline is at
Good shout :) These both seem to be working now. Looking more into what you can do with these, e.g. settings sources = { term = function() ... end }, I'd agree the existing mechanisms should support most use cases.
Thanks again, this has been a fun one!
Marked as draft again as I've discovered a few sharp edges. Will keep polishing!
Heya, finally coming back to this after getting a bit distracted over Christmas. The issue I'm having is that completions kind of flicker/stutter a bit in the terminal and I have no clue what's causing this. I'll keep digging in when I get the chance, but in the meantime @Saghen is there any chance you can suggest some avenues for exploration?
This should show you what I mean:
https://github.com/user-attachments/assets/b4760647-3586-4f03-bd9b-0664b54baf0f
Absolutely, I'll take a look as soon as I have some time
Rebased on main and it's working really well! Weirdly enough, the stuttering seems to only happen on neovim v0.10, while nightly doesn't have any stutter. It seems like the event comes before the terminal gets updated so we effectively update before the event is applied. I'm pretty comfortable making this a nightly only feature for now given we need a shell source, and v0.11 is just around the corner
Amazing work on this, tysm!
Awesome! Gives me a good excuse to finally start using the nightly builds 😄 Thanks for checking and merging 🙏