nvim-cmp icon indicating copy to clipboard operation
nvim-cmp copied to clipboard

Select nth item in the completion list, and number items

Open benlubas opened this issue 2 years ago • 13 comments

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.

image

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_nth doesn'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.

benlubas avatar Mar 18 '23 22:03 benlubas

I think it can be supported via formatting.format function. Why do you add this to the core?

hrsh7th avatar Mar 20 '23 04:03 hrsh7th

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?

hrsh7th avatar Mar 20 '23 04:03 hrsh7th

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.

benlubas avatar Mar 20 '23 13:03 benlubas

@hrsh7th any comment here?

benlubas avatar May 18 '23 23:05 benlubas

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.

tmillr avatar Aug 06 '23 01:08 tmillr

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

benlubas avatar Oct 08 '23 15:10 benlubas

I would like to have this in the core, or through another plugin is also fine.

howarddo2208 avatar Oct 26 '23 15:10 howarddo2208

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),
         ...
      }

rwblokzijl avatar Mar 17 '24 15:03 rwblokzijl

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?

kdog3682 avatar Mar 25 '24 01:03 kdog3682

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.

CantGetRight82 avatar Apr 20 '24 05:04 CantGetRight82

Instead of leaving more comments, if you like this PR just give it a thumbs up please.

benlubas avatar Apr 20 '24 16:04 benlubas