Skip to content

Instantly share code, notes, and snippets.

@MariaSolOs
Last active June 18, 2025 19:24
Show Gist options
  • Save MariaSolOs/2e44a86f569323c478e5a078d0cf98cc to your computer and use it in GitHub Desktop.
Save MariaSolOs/2e44a86f569323c478e5a078d0cf98cc to your computer and use it in GitHub Desktop.
Built-in completion + snippet Neovim setup
---Utility for keymap creation.
---@param lhs string
---@param rhs string|function
---@param opts string|table
---@param mode? string|string[]
local function keymap(lhs, rhs, opts, mode)
opts = type(opts) == 'string' and { desc = opts }
or vim.tbl_extend('error', opts --[[@as table]], { buffer = bufnr })
mode = mode or 'n'
vim.keymap.set(mode, lhs, rhs, opts)
end
---For replacing certain <C-x>... keymaps.
---@param keys string
local function feedkeys(keys)
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(keys, true, false, true), 'n', true)
end
---Is the completion menu open?
local function pumvisible()
return tonumber(vim.fn.pumvisible()) ~= 0
end
-- Enable completion and configure keybindings.
if client.supports_method(methods.textDocument_completion) then
vim.lsp.completion.enable(true, client.id, bufnr, { autotrigger = true })
-- Use enter to accept completions.
keymap('<cr>', function()
return pumvisible() and '<C-y>' or '<cr>'
end, { expr = true }, 'i')
-- Use slash to dismiss the completion menu.
keymap('/', function()
return pumvisible() and '<C-e>' or '/'
end, { expr = true }, 'i')
-- Use <C-n> to navigate to the next completion or:
-- - Trigger LSP completion.
-- - If there's no one, fallback to vanilla omnifunc.
keymap('<C-n>', function()
if pumvisible() then
feedkeys '<C-n>'
else
if next(vim.lsp.get_clients { bufnr = 0 }) then
vim.lsp.completion.trigger()
else
if vim.bo.omnifunc == '' then
feedkeys '<C-x><C-n>'
else
feedkeys '<C-x><C-o>'
end
end
end
end, 'Trigger/select next completion', 'i')
-- Buffer completions.
keymap('<C-u>', '<C-x><C-n>', { desc = 'Buffer completions' }, 'i')
-- Use <Tab> to accept a Copilot suggestion, navigate between snippet tabstops,
-- or select the next completion.
-- Do something similar with <S-Tab>.
keymap('<Tab>', function()
local copilot = require 'copilot.suggestion'
if copilot.is_visible() then
copilot.accept()
elseif pumvisible() then
feedkeys '<C-n>'
elseif vim.snippet.active { direction = 1 } then
vim.snippet.jump(1)
else
feedkeys '<Tab>'
end
end, {}, { 'i', 's' })
keymap('<S-Tab>', function()
if pumvisible() then
feedkeys '<C-p>'
elseif vim.snippet.active { direction = -1 } then
vim.snippet.jump(-1)
else
feedkeys '<S-Tab>'
end
end, {}, { 'i', 's' })
-- Inside a snippet, use backspace to remove the placeholder.
keymap('<BS>', '<C-o>s', {}, 's')
end
@bpingris
Copy link

is the autotrigger = true supposed to show the autocomplete menu while we are editing the buffer?

I've set it up with it, but when writing in a ts file for example nothing shows up, however pressing <c-x><c-o> does show the autocomplete menu

or do we have to do more configuration to have it working? thanks!

@mgnsk
Copy link

mgnsk commented Jun 18, 2025

Very cool! I'd like to add:

-- Autoselect the first item but don't insert it.
-- Allows quick use, just write something and enter to select the first one.
vim.opt.completeopt = { "menu", "menuone", "noinsert" }

-- Make completion menu appear whenever you type something.
-- Example from: https://neovim.io/doc/user/lsp.html#lsp-attach
-- Optional: trigger autocompletion on EVERY keypress. May be slow!
local chars = {}
for i = 32, 126 do
	table.insert(chars, string.char(i))
end
client.server_capabilities.completionProvider.triggerCharacters = chars
vim.lsp.completion.enable(true, client.id, args.buf, {
	autotrigger = true,
})

Some things that the built-in completion does not support (yet?):

  • Hover documentation next to completion item. It does however support preview if you append "preview" to completeopt.
  • Combined menu of both LSP and buffer items. You can only have either one or the other.
  • Custom snippet support? I didn't get my custom snippets working. As I understand, this completion only works on LSP server provided completions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment