Completion & Snippets
Completion Engine
LazyVim supports two completion engines. The variable vim.g.lazyvim_cmp controls which one to use:
| Value | Engine | Default? |
|---|---|---|
"auto" | Auto-detect via :LazyExtras | Default |
"nvim-cmp" | nvim-cmp (traditional) | Installed by default |
"blink.cmp" | blink.cmp (faster, newer) | Enable via coding.blink extra |
Switch Between Engines
-- Force nvim-cmp
vim.g.lazyvim_cmp = "nvim-cmp"
-- Or force blink.cmp (after enabling the extra)
vim.g.lazyvim_cmp = "blink.cmp"
nvim-cmp (Default)
nvim-cmp is the traditional completion engine that ships with LazyVim by default.
Keymaps (Insert Mode)
| Key | Action |
|---|---|
<C-space> | Manually trigger completion |
<C-n> / <C-p> | Next / previous item in menu |
<C-y> | Confirm selection |
<C-e> | Cancel / close menu |
<C-d> | Scroll documentation down |
<C-f> | Scroll documentation up |
<CR> | Confirm selected item |
<Tab> | Select next item (if configured via Supertab recipe) |
Completion Sources
nvim-cmp fetches suggestions from these sources:
| Source | Provides |
|---|---|
| LSP | Variables, functions, types from language server |
| Snippets (LuaSnip) | Code snippets |
| Buffer | Words already in current buffer |
| Path | File paths (./, ../) |
| Treesitter | Context-aware tokens |
| LazyDev | Lua APIs for Neovim config files |
Add a Custom Source
return {
"hrsh7th/nvim-cmp",
dependencies = { "hrsh7th/cmp-emoji" },
opts = function(_, opts)
table.insert(opts.sources, { name = "emoji" })
end,
}
Supertab (Tab for Completion)
Enable Tab to cycle completions and expand snippets:
return {
"hrsh7th/nvim-cmp",
opts = function(_, opts)
local has_words_before = function()
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil
end
local cmp = require("cmp")
opts.mapping = vim.tbl_extend("force", opts.mapping, {
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif vim.snippet.active({ direction = 1 }) then
vim.schedule(function() vim.snippet.jump(1) end)
elseif has_words_before() then
cmp.complete()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif vim.snippet.active({ direction = -1 }) then
vim.schedule(function() vim.snippet.jump(-1) end)
else
fallback()
end
end, { "i", "s" }),
})
end,
}
blink.cmp (Alternative)
Faster, more modern completion engine. Enable it:
return {
{ import = "lazyvim.plugins.extras.coding.blink" },
}
blink.cmp keymaps are similar — C-space triggers, C-n/C-p navigate, C-y/CR confirm.
Snippets (LuaSnip)
LazyVim uses LuaSnip for snippet expansion with nvim-cmp.
Default Snippet Keymaps
| Key | Mode | Action |
|---|---|---|
<C-k> | Insert | Jump forward through snippet placeholders |
<C-j> | Insert | Jump backward through snippet placeholders |
Built-in Snippets
LazyVim includes snippets for common languages via friendly-snippets:
- Lua:
fun,if,for,while,req(require) - JavaScript/TypeScript:
fun,arrow,class,import,export - Python:
def,class,if,for,print - HTML:
div,a,img,link,script - Markdown:
code,link,img,table
Trigger a Snippet
Type a snippet trigger word and press <C-space> to trigger completion, then select the snippet from the menu.
Example in a Python file:
- Type
def - Press
<C-space> - Select
defsnippet from menu - Fill in function name, parameters, body — press
<C-k>to jump between placeholders
Create Custom Snippets
Create ~/.config/nvim/snippets/ directory:
return {
"L3MON4D3/LuaSnip",
opts = function(_, opts)
local ls = require("luasnip")
-- Add a simple snippet
ls.add_snippets("lua", {
ls.snippet("log", {
ls.text_node('print("DEBUG: " .. '),
ls.insert_node(1),
ls.text_node(")"),
}),
})
-- Or load from snipmate format
-- require("luasnip.loaders.from_snipmate").load({ paths = "~/.config/nvim/snippets" })
end,
}
Snippet File Format (SnipMate)
~/.config/nvim/snippets/lua.json:
{
"log": {
"prefix": "log",
"body": "print(\"DEBUG: \" .. ${1:text})",
"description": "Print debug log"
}
}
Or ~/.config/nvim/snippets/lua.snippets:
snippet log "Print debug log"
print("DEBUG: " .. $1)
endsnippet
Completion Flow (Keyboard-Only)
1. Type code normally ← LSP sources show suggestions automatically
2. Press <C-space> to trigger ← Forces completion menu to appear
3. <C-n> / <C-p> to navigate ← Up/down through suggestions
4. <C-y> to accept ← Completes the word
5. If snippet: press <C-k> ← Jump to next placeholder
6. Type the placeholder value
7. <C-k> again when done ← Moves to next field or finishes
8. <C-e> to close menu ← Cancel if you changed your mind