A lightweight, native-first completion experience for Neovim.
Focused on leveraging Neovim's native completion infrastructure (See :h ins-completion
) and built-in LSP client, without external dependencies. The goal is to provide a lightweight and performant completion experience that feels like a natural extension of Neovim itself, while maintaining essential features.
Using lazy.nvim:
{
"brianaung/compl.nvim",
opts = {
-- Default options (no need to set them again)
completion = {
fuzzy = false,
timeout = 100,
},
info = {
enable = true,
timeout = 100,
},
snippet = {
enable = false,
paths = {},
}
},
}
-- A set of options for better completion experience. See `:h completeopt`
vim.opt.completeopt = { "menuone", "noselect", "noinsert" }
-- Hides the ins-completion-menu messages. See `:h shm-c`
vim.opt.shortmess:append "c"
By default, this plugin follows ins-completion mappings (See :h ins-completion-menu
, :h popupmenu-keys
). However, they can be easily remapped.
Below are some recipes using the vim.keymap.set()
interface. See :h vim.keymap.set()
.
Accept completion using <CR>
vim.keymap.set("i", "<CR>", function()
if vim.fn.complete_info()["selected"] ~= -1 then return "<C-y>" end
if vim.fn.pumvisible() ~= 0 then return "<C-e><CR>" end
return "<CR>"
end, { expr = true })
Change selection using <Tab>
and <Shift-Tab>
vim.keymap.set("i", "<Tab>", function()
if vim.fn.pumvisible() ~= 0 then return "<C-n>" end
return "<Tab>"
end, { expr = true })
vim.keymap.set("i", "<S-Tab>", function()
if vim.fn.pumvisible() ~= 0 then return "<C-p>" end
return "<S-Tab>"
end, { expr = true })
Snippet jumps
vim.keymap.set({ "i", "s" }, "<C-k>", function()
if vim.snippet.active { direction = 1 } then
return "<cmd>lua vim.snippet.jump(1)<cr>"
end
end, { expr = true })
vim.keymap.set({ "i", "s" }, "<C-j>", function()
if vim.snippet.active { direction = -1 } then
return "<cmd>lua vim.snippet.jump(-1)<cr>"
end
end, { expr = true })
You can seamlessly integrate custom snippets into your existing completion workflow without any additional dependencies. Snippets from the specified paths are parsed and formatted into appropriate LSP responses, and are passed into a lightweight internal LSP server, which then returns them as completion items when Neovim's LSP client sends a textDocument/completion
request.
To use a collection of snippets such as those provided in rafamadriz/friendly-snippets, install it as a dependency and point to the location of its package.json
manifest file. Here's how to configure it using lazy.nvim
:
{
"brianaung/compl.nvim",
dependencies = {
"rafamadriz/friendly-snippets"
},
opts = {
-- ...
snippet = {
enable = true,
paths = {
vim.fn.stdpath "data" .. "/lazy/friendly-snippets",
-- You can include more paths that contains the package.json manifest for your custom snippets. See below for defining your own snippets.
},
},
-- ...
},
}
If you'd like to define your own snippets for a specific language, you can create a JSON file with your snippets following this syntax.
You’ll then need to create a package.json
manifest that will describe how to retrieve snippets for each filetype.
language
: The language in the manifest should match the filetype used by Neovim (e.g., vim.bo.filetype
).path
: Provide the file path to your snippet JSON file.