Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select nth item in the completion list, and number items #1491

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

benlubas
Copy link

@benlubas benlubas commented Mar 18, 2023

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 benlubas changed the title Select nth item in the completion list, and number first ten items Select nth item in the completion list, and number items Mar 19, 2023
@hrsh7th
Copy link
Owner

hrsh7th commented Mar 20, 2023

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

@hrsh7th
Copy link
Owner

hrsh7th commented Mar 20, 2023

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?

@benlubas
Copy link
Author

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
Copy link
Author

@hrsh7th any comment here?

@tmillr
Copy link
Contributor

tmillr commented Aug 6, 2023

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.

@benlubas
Copy link
Author

benlubas commented Oct 8, 2023

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

@howarddo2208
Copy link

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

@rwblokzijl
Copy link

rwblokzijl commented Mar 17, 2024

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

@kdog3682
Copy link

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?

@CantGetRight82
Copy link

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.

@benlubas
Copy link
Author

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

@theol0403
Copy link

theol0403 commented Oct 8, 2024

At the risk of more noise - this PR is also very useful for implementing "supertab"- like functionality (ala sublime text)!

With supertab bindings (LazyVim/lazyvim.github.io#113), I can quickly look at the number next to the completion I want to select (start_index = 1) and simply hit TAB that many times! The muscle memory can develop very fast this way, where I can quickly navigate the completions just by spamming TAB 1-4 times to get to where I need.

Would be great to have this merged :)

Also, this feature was requested a while ago for screen readers but hasn't been mentioned yet in this thread -- another usecase for this feature 👍 #1112

wezterm-gui_08RbGRlUNa.mp4

@schester44
Copy link

Using select_next_item and count makes it trivial to select by index but i'm not seeing an easy way of rendering the index of each entry within the formatting function.

Does anyone know how to get the index of the entry?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants