Goals for v2
- 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~~ Usecmp.snippets.registry
- Keymap
- Use
vim.on_key#487 - Avoid
vim.scheduleso 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_inserttopreview - ~~Rename
accepttoapply~~
- Use
- 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-analyzersort 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.sortis 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_descriptioncomponent there for better overflow handling) - Redraw resolved item
- Drop treesitter label highlighting (colorful-menu.nvim is excellent, should contribute separate
- Focusable windows
- Open in split
- Opt-in replace
vim.lsp.buf.hoverandvim.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-*toblink-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.gandvim.bfor 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!
Maybe:
appearance = {
kind_icons = {
preset = 'vs-code', -- 'mini-icons'
}
}
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,
},
},
},
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).
Yep, that one's scheduled for v1, but it's quite tricky
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 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 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?
Yep #1085
When are you planning on releasing v1 - i.e. stop breaking the config? :)
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)
Inline completions seem like a good candidate #1212
Note that this might end up being supported upstream ;) https://github.com/neovim/neovim/issues/32421
opts = {
keymap = {
preset = 'none',
-- Keymaps
},
cmdline = {
keymap = {
preset = 'inherit',
-- Override
},
},
term = {
keymap = {
preset = 'inherit_cmdline',
-- Override
},
},
}
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!
This plugin is working very well for me, thank you!
I am only missing two things that I had in nvim-cmp:
insertReplaceSupportfor LSP (#21): I use this quite a bit for tedious tasks like copying code from other places and renaming its variables.- 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 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)
@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!
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 completion.menu.draw.align_to = 'cursor': https://cmp.saghen.dev/configuration/reference.html#completion-menu-draw
@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!
No worries at all!
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.
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
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
Makes sense, opened a separate issue for that
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)
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_pathso that it triggers the next completion menu instead of inserting an additional path delimiter for the first time afterselect_next/_previs 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_currentaction).~~ Usecmdline.completion.list.selection.preselect = false
Video
https://github.com/user-attachments/assets/0a2ac96a-3809-4f29-8e3f-14742bd94ef9
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.
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
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??).
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 }