blink.cmp icon indicating copy to clipboard operation
blink.cmp copied to clipboard

Goals for v2

Open saghen opened this issue 10 months ago • 45 comments

  • Adopt vim.async: https://github.com/neovim/neovim/pull/34473
  • Convert to library: Decouple many of the components such that the project may be used as a library
    • Pluggable triggers
    • Pluggable views
    • Pluggable fuzzy matchers
    • ~~Move snippets registry to blink.snippets~~ Use cmp.snippets.registry
  • Keymap
    • Use vim.on_key #487
    • Avoid vim.schedule so that all commands run synchronously, easier scripting
    • After V2: Commit characters with vim.on_key #536
    • Change default: <C-p>/<C-n> = { 'select_next', 'show_and_select' }
    • Rename auto_insert to preview
    • ~~Rename accept to apply~~
  • Triggers
    • ~~Support macros #1311~~
    • Rewrite to be readable
    • Try to find a better solution for auto_insert
      • Extmarks to track start/end ranges?
    • Regex configuration
  • Sources: Replace with in-process LSPs
    • Compat layer for blink.cmp sources as LSPs
    • lsp.* for LSP specific options replaces sources system
      • ~~Opt-in auto brackets~~
      • Opt-out proximity/frecency bonus (i.e. rust-analyzer sort is already excellent) or make frecency lower prio than sortText by default
    • Move hacks to LSP specific options
    • Move blink specific fields to .blink (#1778)
  • Fuzzy
    • Simplify and use build script for downloading binary
    • Explore small language model for item sorting
    • ~~Stable sorting (Lua's table.sort is unstable)~~
    • Use LSP fuzzy range
    • Drop score of anything with __
    • ~~Use 'state' directory instead of 'data' by default~~
  • Windows
    • ~~Virtual text for scrollbar (If possible with borders, primarily for neovide)~~
    • Use new scrollbar impl after it's merged: https://github.com/neovim/neovim/pull/35729
    • Simplify drawing
      • Drop treesitter label highlighting (colorful-menu.nvim is excellent, should contribute separate label_description component there for better overflow handling)
      • Redraw resolved item
    • Focusable windows
      • Open in split
      • Opt-in replace vim.lsp.buf.hover and vim.lsp.buf.signature_help
    • Multiple details/signatures
    • Icon presets (vscode, mini-icons, ascii)
  • Tooling
    • Lux #1596
    • Publish to luarocks #217
    • Fully automate release workflow
    • Change :h blink-cmp-config-* to blink-cmp-*
    • Generate reference documentation from types
    • Testing
  • Raise minimum neovim version to 0.12+
  • Consider switching cmdline defaults back: https://github.com/Saghen/blink.cmp/discussions/1668#discussioncomment-12913889
  • Support vim.g and vim.b for configuration
  • Other?

If you have any ideas, please don't hesitate to share either here or in the discussions. Many of these may also be done with v1, PRs welcome!

saghen avatar Jan 22 '25 23:01 saghen

Maybe:

appearance = {
  kind_icons = {
    preset = 'vs-code', -- 'mini-icons'
  }
}

drowning-cat avatar Jan 23 '25 15:01 drowning-cat

I also think you could add something like this:

opts = {
  keymap = {
    -- New syntax: allow to define arguments without creating a function
    ['<C-n>'] = { { 'select_next', auto_insert = true }, 'fallback' },
    ['<C-p>'] = { { 'select_prev', auto_insert = true }, 'fallback' },

    -- The option `next=true` causes both keymaps ('hide' and 'fallback') to be called sequentially.
    -- This behavior is not specific to 'hide' but applies to all { '<keymap>' }
    --[[1]] ['<Esc>'] = { { 'hide', next = true }, 'fallback' },
    --   2  ['<Esc>'] = { { 'hide', ret = false }, 'fallback' },       -- `ret` is short for `return`
    --   3  ['<Esc>'] = { 'hide', 'fallback', stop_at_first = false }, -- conform.nvim style
  }
}
Wrapper example
---@class KeymapCommandWrapper
---@field [1] blink.cmp.KeymapCommand
---@field [string] unknown
---@field next? boolean

---@alias SuperKeymapCommand KeymapCommandWrapper|blink.cmp.KeymapCommand

---@class SuperKeymapConfig
---@field preset? blink.cmp.KeymapPreset
---@field [string] SuperKeymapCommand[]

---@param key_commands SuperKeymapCommand[]
---@return blink.cmp.KeymapCommand[]
local convert = function(key_commands)
  local key_config = {}
  for i, cmd in ipairs(key_commands) do
    if type(cmd) == 'table' then
      local next = nil
      local cmd_name, args = cmd[1], {}
      for key, val in pairs(cmd) do
        if type(key) == 'number' then
          -- skip
        elseif key == 'next' then
          next = val
        else
          args[key] = val
        end
      end
      key_config[i] = function(cmp)
        local fun = cmp[cmd_name]
        local ret = fun(vim.tbl_isempty(args) and nil or args)
        -- stylua: ignore
        if next == nil then return ret end
        return not next
      end
    else
      key_config[i] = cmd
    end
  end
  return key_config
end

---@param super_keymap_config SuperKeymapConfig
---@return blink.cmp.KeymapConfig
local keymap_config = function(super_keymap_config)
  local keymap_config = {}
  for key, val in pairs(super_keymap_config) do
    if key == 'preset' then
      keymap_config[key] = val
    else
      keymap_config[key] = convert(val)
    end
  end
  return keymap_config
end
opts = {
  keymap = keymap_config {
    preset = 'none',
    -- Move
    ['<Down>'] = { 'select_next', 'fallback' },
    ['<Up>'] = { 'select_prev', 'fallback' },
    ['<C-j>'] = { 'select_next', 'fallback' },
    ['<C-k>'] = { 'select_prev', 'fallback' },
    ['<C-n>'] = { { 'select_next', auto_insert = true } }, -- no fallback
    ['<C-p>'] = { { 'select_prev', auto_insert = true } }, -- no fallback
    -- Accept
    ['<C-y>'] = { 'select_and_accept' }, -- no fallback
    ['<C-CR>'] = { 'select_and_accept', 'fallback' },
    -- Show
    ['<C-Space>'] = { 'show', 'show_documentation', 'hide_documentation' }, -- no fallback
    -- Cancel
    ['<C-c>'] = { 'cancel', 'fallback' },
    -- Hide
    ['<C-e>'] = { 'hide', 'fallback' }, -- no fallback
    ['<Esc>'] = { { 'hide', next = true }, 'fallback' },
    -- Scroll
    ['<C-d>'] = { 'scroll_documentation_down' },
    ['<C-u>'] = { 'scroll_documentation_up' },
    ['<C-]>'] = { 'scroll_documentation_down' },
    ['<C-_>'] = { 'scroll_documentation_up' },
    -- Snippet
    ['<C-l>'] = { 'snippet_forward', 'fallback' },
    ['<C-h>'] = { 'snippet_backward', 'fallback' },
  },
  cmdline = {
    completion = {
      menu = {
        auto_show = true,
      },
    },
    keymap = keymap_config {
      preset = 'none',
      -- Move
      ['<Down>'] = { { 'hide', next = true }, 'fallback' },
      ['<Up>'] = { { 'hide', next = true }, 'fallback' },
      ['<C-Down>'] = { 'select_next' },
      ['<C-Up>'] = { 'select_prev' },
      ['<Tab>'] = { 'select_next' },
      ['<S-Tab>'] = { 'select_prev' },
      ['<C-j>'] = { 'select_next' },
      ['<C-k>'] = { 'select_prev' },
      ['<C-n>'] = { { 'select_next', auto_insert = true } },
      ['<C-p>'] = { { 'select_prev', auto_insert = true } },
      -- Accept
      ['<C-y>'] = { 'select_accept_and_enter' },
      -- Show
      ['<C-Space>'] = { 'show' },
      -- Hide
      ['<C-c>'] = { nil }, -- No need to bind
      ['<C-e>'] = { 'hide' },
      -- stylua: ignore
      ['<Esc>'] = { function() vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<C-c>', true, false, true), 'n') end,
    },
  },
},

drowning-cat avatar Jan 23 '25 15:01 drowning-cat

Dot-repeat would also be amazing! Not sure if this is already scheduled as part of v1 though (I see that there are a couple of open PRs for it).

MariaSolOs avatar Feb 01 '25 18:02 MariaSolOs

Yep, that one's scheduled for v1, but it's quite tricky

saghen avatar Feb 04 '25 17:02 saghen

Smart case for matching items? Such as Parameter(a type from lsp) should be preferred over parameter~(a snippet) when P is typed. min_keyword_length and score_offset currently are not handling priorities very well, this might help for better experience in some cases

sharpchen avatar Feb 05 '25 06:02 sharpchen

@sharpchen Do you mind elaborating in a separate issue (ideally with examples)? We should already be prioritizing matching cases and snippets should have a -3 applied to their score by default. There's also #1098 for source priority

saghen avatar Feb 05 '25 16:02 saghen

@Saghen opened in #1158

Besides smart case, I think exact matching might solve more than that(currently supports fuzzy match only as far as I know? Items from sources are always grouped together by their source name), any plan for exact matching?

sharpchen avatar Feb 05 '25 20:02 sharpchen

Yep #1085

saghen avatar Feb 05 '25 20:02 saghen

When are you planning on releasing v1 - i.e. stop breaking the config? :)

MikaelElkiaer avatar Feb 07 '25 13:02 MikaelElkiaer

Inline completions seem like a good candidate #1212

@MikaelElkiaer Likely after a few patches on 0.12 which has dot complete, a bunch of small features, and one last breaking change (#1203)

saghen avatar Feb 13 '25 16:02 saghen

Inline completions seem like a good candidate #1212

Note that this might end up being supported upstream ;) https://github.com/neovim/neovim/issues/32421

MariaSolOs avatar Feb 13 '25 20:02 MariaSolOs

opts = {
  keymap = {
    preset = 'none',
    -- Keymaps
  },
  cmdline = {
    keymap = {
      preset = 'inherit',
      -- Override
    },
  },
  term = {
    keymap = {
      preset = 'inherit_cmdline',
      -- Override
    },
  },
}

drowning-cat avatar Feb 14 '25 00:02 drowning-cat

Is https://github.com/Saghen/blink.cmp/issues/206 in the backlog? Either for 1.0 or 2.0? If not, heres my request for it to be added!

ibrokemypie avatar Feb 21 '25 04:02 ibrokemypie

This plugin is working very well for me, thank you!

I am only missing two things that I had in nvim-cmp:

  1. insertReplaceSupport for LSP (#21): I use this quite a bit for tedious tasks like copying code from other places and renaming its variables.
  2. Some short document on how to write sources. I am sure I could figure something out, but getting the finer details from the plugin writer would be a great bonus.

Thanks a lot for the plugin.

dawsers avatar Feb 22 '25 11:02 dawsers

@dawsers there is some documentation available for writing sources here https://github.com/Saghen/blink.cmp/blob/main/doc/development/source-boilerplate.md

If you have questions you can also open issues here if you want https://github.com/mikavilpas/blink-ripgrep.nvim/issues (I don't care if they are not about the blink-ripgrep plugin - I just don't think github has personal messages)

mikavilpas avatar Feb 22 '25 11:02 mikavilpas

@dawsers there is some documentation available for writing sources here https://github.com/Saghen/blink.cmp/blob/main/doc/development/source-boilerplate.md

If you have questions you can also open issues here if you want https://github.com/mikavilpas/blink-ripgrep.nvim/issues (I don't care if they are not about the blink-ripgrep plugin - I just don't think github has personal messages)

This is great help, thank you!

dawsers avatar Feb 22 '25 11:02 dawsers

I would love to see something like nvim-cmp's view.entries.follow_cursor = true option (where the completion menu position follows the cursor position)

Example from the CMP issue where the feature was implemented:

https://private-user-images.githubusercontent.com/109605931/259719877-78f122ff-8c4b-4367-8818-fd4788081d8a.mp4?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDI5Mzk4NTgsIm5iZiI6MTc0MjkzOTU1OCwicGF0aCI6Ii8xMDk2MDU5MzEvMjU5NzE5ODc3LTc4ZjEyMmZmLThjNGItNDM2Ny04ODE4LWZkNDc4ODA4MWQ4YS5tcDQ_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwMzI1JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDMyNVQyMTUyMzhaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1mMzU2OGJhMTZiMDY5NjAwZTEzZjdiZWM2NjRjOWVhNjE1M2ZlYzJlNWNiODBmNWMwZDkyZTQ0NjA0NzZkMjZlJlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.wUAU5YeLHwjKiu06zexA36rzuuqsc8j69kk5voblQ8E

ptdewey avatar Mar 25 '25 21:03 ptdewey

@ptdewey completion.menu.draw.align_to = 'cursor': https://cmp.saghen.dev/configuration/reference.html#completion-menu-draw

saghen avatar Mar 25 '25 21:03 saghen

@ptdewey completion.menu.draw.align_to = 'cursor': https://cmp.saghen.dev/configuration/reference.html#completion-menu-draw

Oh sorry, I completely missed that! Sorry for the ping and thanks for the great work!

ptdewey avatar Mar 25 '25 21:03 ptdewey

No worries at all!

saghen avatar Mar 25 '25 22:03 saghen

Custom highlight for highlight component in draw. Why? One usecase that I have To change icon color based on label. Say file icon in cmdline which matches color from nvim-devicons.

aloknigam247 avatar Mar 27 '25 17:03 aloknigam247

You can already achieve this by using the menu.draw API:

https://cmp.saghen.dev/configuration/completion.html#menu-draw https://cmp.saghen.dev/configuration/reference.html#completion-menu-draw

saghen avatar Mar 27 '25 17:03 saghen

Yes, but it takes name of highlight group and not the raw parameters of nvim_set_hl. Like I can return FG, BG, and other options from the highlight = function() end option directly. I tried to return table of options but it didn't considered it.

e.g.

highlight = function() return { fg = "...", bg = "..." } end

aloknigam247 avatar Mar 31 '25 02:03 aloknigam247

Makes sense, opened a separate issue for that

saghen avatar Mar 31 '25 02:03 saghen

Thank you for the great plugin! I would like to see some more features in cmdline completion:

  • Tweak order based on history
  • File finder and icons in cmdline (wilder.nvim)

lljbash avatar Apr 01 '25 06:04 lljbash

Trigger the next completion menu instead of inserting an additional path delimiter for the first time after select_next (or select_prev) is used.

Hide

Use / or \ (windows) as a contiguous trigger for path autocompletion:

  • Implement smart_path so that it triggers the next completion menu instead of inserting an additional path delimiter for the first time after select_next/_prev is used.

  • ~~Implement a way to select the current item in the completion menu without accepting it, before moving to the next item (e.g., by exposing a select_current action).~~ Use cmdline.completion.list.selection.preselect = false

Video

https://github.com/user-attachments/assets/0a2ac96a-3809-4f29-8e3f-14742bd94ef9

drowning-cat avatar Apr 12 '25 10:04 drowning-cat

Please consider allowing to override the keyword regex, as it does not work with non-ASCII characters. Also, some sources might have completions which are not only composed of keyword characters. In that case, in the current state of the plugin, typing non-keyword characters will still cause the completion window to be hidden, which is undesirable. I would try to put my hands on this but I am afraid of messing with your code organization. Thank you for your work.

mikidep avatar May 06 '25 14:05 mikidep

Makes sense, will add that to the list! For now though, the source should define trigger characters for non-alphanumeric characters, perhaps an example could help me understand better. Also, can you elaborate on what non-ASCII characters aren't working? We match against the unicode Letter category (L) so it should be working for non-ASCII alphabets

saghen avatar May 06 '25 14:05 saghen

I write Agda, which is notoriously nasty when it comes to interacting with Vim's is_keyword. Regarding trigger characters, I can't seem to understand how to set up a source so that it only provides suggestions after a trigger character, and so that no other source appears then. In a way I would like this source to be "exclusive" when it is triggered. I set should_show_items to function(ctx) return ctx.trigger.initial_kind == "trigger_character" end, but this way the source does not appear until I type some keyword character (why??).

mikidep avatar May 06 '25 16:05 mikidep

Thanks! Not sure about the trigger character, I'll have to take a look later, but you can make a source exclusive by setting its fallbacks to all your other sources. I.e. sources.providers.agda.fallbacks = { 'lsp', 'buffer', 'path', 'snippets', ...any_other_sources }

saghen avatar May 07 '25 14:05 saghen