nvim-cmp
nvim-cmp copied to clipboard
Select nth item in the completion list, and number items
As discussed in #1482 being able to press alt + n to select the nth item in the completion list would be pretty cool. Unfortunately there is not a great way to implement that right now, and there's (as far as I could tell) no way to number the items in the completion menu. This PR is the result of that.
Adds a format field for numbers
formatting = {
number_options = {
start_index = 0, -- these are defaults
end_index = 9,
},
fields = { "num", "abbr", "kind", "menu" }, -- numbers on the left
-- fields = { "abbr", "kind", "num", "menu" }, -- numbers on the right
-- this still defaults to not showing the numbers
}
I've accounted for scrolling, and the completion list being flipped.

Adds cmp.select_nth(n) which selects the nth item in the completion list.
This allows for bindings to select items like the following:
for i = 0, 9, 1 do
local key = table.concat({ "<M-", i, ">" })
keys[key] = function(fallback)
if cmp.visible() and #cmp.get_entries() > i then
return cmp.select_nth(i + 1)
end
return fallback()
end
end
Important improvement here, select_nth(4) will always select the item labeled 4. Like the numbers, this works when the completion list is scrolled, and when the list is flipped.
Things this doesn't do:
- There is no highlight group for the numbers, they just show as default text
select_nthdoesn't appear to work in command line completion.- I haven't added testing yet in case I took the wrong approach to implementing this.
If this gets accepted, I plan to add a wiki page detailing how to setup binds like this, with a section for macos users, b/c alt + 1 on macos by default types some symbol or another.
I think it can be supported via formatting.format function.
Why do you add this to the core?
I really appreciate the contribution, but I'm not really a fan of this feature. . .
Can you tell us about the superiority of this function?
I think it can be supported via formatting.format function.
If you could give me an example of that, I'd love to see it. I did try that first, and couldn't come up with one that meets the following requirements:
- Correctly labels the first 10 items 0 to 9 and nothing else
- Shows the number on the far left or far right of the completion menu
- Numbers stick to the top when the menu is scrolled
- Works when inverted
Can you tell us about the superiority of this function?
The use case here is binding say "alt + 1/2/3/..." to select the 1st/2nd/3rd/... item in the completion menu so if you start typing, and see the item you want in the 5th slot just hitting "alt + 5" lets you immediately select it. Additionally, if you're on the 5th item, and want to jump to the 7th item, hitting "alt + 7" still works, this is in contrast to a solution which uses cmp.select_next_item({ count = n }). I've also had various difficulties/bugs with the count option on select_next_item. This is by far the cleaner solution to the problem.
I've found bindings like this (in conjunction with the numbers) especially useful in completing text that's already in the buffer. When typing a css class like "selectable-item", there are often other words that get suggested first, but it's very easy to pick that out from a list, identify the number, and immediately select it.
@hrsh7th any comment here?
This is an interesting idea. I see the benefit, although not sure if it's a large/necessary one. I do feel like it's possible to pull this off currently (probably via a manual "hacky" solution), but not easily. If the maintainer doesn't want this, perhaps it should be made into a plugin to save users from having to repeat the same hack.
The non-hacky solution for me is to just a branch of my fork onto main whenever I remember. Beauty of open source :P
Seriously though if you think there's a way to get this to work with an external plugin I'd be happy to hear it. The only way I could think to do it would be adding a floating window that shows up next to the completion menu to display the numbers and then you could setup some bindings that press <c-n> or <c-p> based on where you are in the completion menu (assuming that you can pull that information from somewhere)
but I'm not willing to implement that honestly
I would like to have this in the core, or through another plugin is also fine.
Personally like this as it would support my usecase of select_first_item and select_last_item.
Currently solving like this:
mapping = cmp.mapping.preset.insert {
...
-- jump to top
['<C-k>'] = cmp.mapping(function()
cmp.select_prev_item({
count = indexOf(cmp.get_entries(), cmp.get_selected_entry()) - 1
})
end),
-- jump to bottom
['<C-j>'] = cmp.mapping(function()
cmp.select_next_item({
count = (
--length of get_entries - index of selected entry
#cmp.get_entries() -
indexOf(cmp.get_entries(), cmp.get_selected_entry())
)
})
end),
...
}
I would just like to add a voice that I think this is a useful feature for beginners (like myself).
The ability to press a number, and be able to immediately get a result, is really nice.
Perhaps there would be a way of integrating the feature, without disrupting what regular users are used to?
Also very much a fan of this feature! 🔥
It is really quite good when you see the match you want, to be able to just pick it instead of figuring out which characters to type more to make it at the top.
@benlubas thank you very much for your work on this!
@hrsh7th hopefully you can reconsider adding it to the core or help on how to make a plugin for it.
Instead of leaving more comments, if you like this PR just give it a thumbs up please.