Skip to content

Instantly share code, notes, and snippets.

@MariaSolOs
Last active December 30, 2025 01:08
Show Gist options
  • Select an option

  • Save MariaSolOs/2e44a86f569323c478e5a078d0cf98cc to your computer and use it in GitHub Desktop.

Select an option

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?

@fedemp
Copy link

fedemp commented Dec 30, 2025

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!

Just for the record, the native autocomplete will offer suggestions after you press ., i.e. it shows properties and methods. At least in my case, when using tsgo.

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