neovim icon indicating copy to clipboard operation
neovim copied to clipboard

Completion API: completion handlers and calling lua callbacks on completion events

Open chentoast opened this issue 2 years ago • 13 comments

Feature already in Vim?

No

Feature description

#13854 adds support for general-purpose fuzzy filtering of completion candidates, but I've been recently thinking about ways to make this more general, and allow plugins to have more control over the completion process beyond just filtering. More specifically, I'm proposing an API such as the following:

vim.api.nvim_completion_attach(mode, {
  on_init = function(line, index)
    -- returns the index where completion should start, like omnifunc
  end,
  on_fetch = function(prefix)
    -- returns a list of completion candidates, overriding the current completion list.
  end,
  on_fetch_chain = function(prefix)
    -- returns a list of completion candidates, which are then appended to the current completion list.
  end
  on_filter = function(prefix, match)
    -- returns a float representing the match between prefix and match.
    -- higher numbers are sorted first in the completion list.
  end,
  on_select = function(match)
    -- called when a completion candidate is selected.
  end,
  on_accept = function(match)
    -- called when a completion candidate is accepted.
  end,
  on_cancel = function() end,
})

where mode is one of the builtin completion modes, such as CTRL_X_{NORMAL, FILES, TAGS}, etc.

As follow up work, we can also allow for custom user completion modes via a new api function nvim_complete, which is also implemented in #13854:

vim.api.nvim_completion_attach("user:git", ...)
vim.api.nvim_complete(1, {"git", "files", "here"}, {completion_mode = "git"})

I'm posting this issue to try and get feedback on whether this is even a good idea or not, and general API design, before I start writing anything.

chentoast avatar Dec 01 '21 16:12 chentoast

First off, I think this is a great idea. Built-in completion is extremely underutilized. I'm curious how completion_mode intersects with the chain completion, can you provide an array of completion_modes?

mjlbach avatar Dec 01 '21 16:12 mjlbach

Quick question: should this be a general API (nvim_XXX, which comes with a rigid contract and is also potentially available through vim script or rpc), or is a Lua API (vim.completion.XXX) enough?

clason avatar Dec 01 '21 16:12 clason

Quick question: should this be a general API (nvim_XXX, which comes with a rigid contract and is also potentially available through vim script or rpc), or is a Lua API (vim.completion.XXX) enough?

Sound like a good idea to put it Lua only first. Avoiding the strict API contract while experimenting. I'm not 💯 on the internals but I'd imagine serializing completion candidates to Lua objects directly instead of going the API Objects route could speed things up and perhaps simpler to implement?

muniter avatar Dec 01 '21 17:12 muniter

I think we should care about the auto completion if we create new completion API because a lot of people loves it (Of course, I know a lot of people loves omni (manual) completion though.

hrsh7th avatar Dec 01 '21 17:12 hrsh7th

FWIW I am in favor of creating an API amenable to (auto) completion so long as it is extensible. (and would be great to have your input hrsh7th as the expert :) )

mjlbach avatar Dec 01 '21 17:12 mjlbach

I will be happy to contribute. I'm excited about the suggestion to add an "extensible completion API by registering the source" to neovim itself.

hrsh7th avatar Dec 01 '21 17:12 hrsh7th

Basically, if the proposed API on_fetch will be a callback-style API, I think it can be used for auto-completion.

It can be used by the external plugin and if the neovim core provides auto completion in the future, it also can be used.

hrsh7th avatar Dec 01 '21 17:12 hrsh7th

One of the barriers for builtin auto completion is that there is no way to add and remove completion candidates after completion is started. So we have to either expose the completion list directly to authors via another api, or refactor the code so that on_fetch is called after every keypress, not just at the beginning.

chentoast avatar Dec 01 '21 17:12 chentoast

I think outlining the problem that this solves first would help to judge the API or idea.

E.g. people now mention auto-completion (which I think is mostly orthogonal to this), and chaining completion sources (your proposal seems to attack a different problem?)

How would this interact with the existing autocmds CompleteDone, CompleteDonePre and CompleteChanged, what's the advantage of on_select, on_accept ... over the existing autocmd system?

mfussenegger avatar Dec 01 '21 18:12 mfussenegger

people now mention auto-completion (which I think is mostly orthogonal to this), and chaining completion sources (your proposal seems to attack a different problem?)

Yes, this proposal is slightly separate from auto-completion, but exposing the builtin completion mechanism as an api might allow for easier autocomplete integration and newer features. Chaining completion sources would be done via the on_fetch_chain key: the idea is that multiple plugins could attach a completion source to a particular mode so that triggering completion will fetch candidates from all of the attached sources.

How would this interact with the existing autocmds CompleteDone, CompleteDonePre and CompleteChanged, what's the advantage of on_select, on_accept ... over the existing autocmd system?

The autocommands do not allow direct control over the internal completion mechanisms used by vim. Adding a CompleteFetch or CompleteFilter autocommand is not enough, since plugins might actually need to modify the completion list themselves, or override default filtering behavior. I do agree that maybe on_accept seems mostly redundant with CompleteDone, but I think the main benefit of the proposal is the ability to distinguish different types of completion, i.e. running different code when finishing files completion versus tags completion, versus some special user defined completion mode. Doing something like that just via autocommands alone is difficult and clunky.

chentoast avatar Dec 01 '21 23:12 chentoast

I think we are in general open to adding Nvim API functions for interacting with completion, but adding a completely new system on top of the existing autocommands (which now accept native Lua callbacks) and func options (which hopefully will soon) should not be done without a very compelling reason.

A good first step would be to make a list of steps that a completion plugin would want to take and explain which of these could be handled by existing autocommands (possibly with additions to their v:event) and which can't.

clason avatar Oct 15 '22 11:10 clason

@clason I feel like custom filtering can't be accomplished currently in any way? (assuming people are not attaching to InsertChange and repeatedly calling complete() which feels a bit dumb).

Honestly I think #13854 is a good solution for that, but my understanding is that @chentoast wanted to overhaul the system a bit further.

fsouza avatar Oct 15 '22 14:10 fsouza

The point was to get a complete view of the status quo and what is missing and decide based on this information, instead of adding individual functions or start from scratch.

clason avatar Oct 15 '22 14:10 clason