Skip to content

Instantly share code, notes, and snippets.

@VonHeikemen
Last active December 16, 2023 08:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VonHeikemen/4e7322577fbbc4e260d420e25763a414 to your computer and use it in GitHub Desktop.
Save VonHeikemen/4e7322577fbbc4e260d420e25763a414 to your computer and use it in GitHub Desktop.
enhanced native completion to expand snippets
-- based on u/YungDaVinci work:
-- https://www.reddit.com/r/neovim/comments/ydlgzi/expand_lsp_snippets_with_luasnip_while_using/
vim.api.nvim_create_augroup('user-snippet-expand', {})
vim.api.nvim_create_autocmd('CompleteDone', {
group = 'user-snippet-expand',
desc = 'Expand LSP snippet',
pattern = '*',
callback = function(opts)
local comp = vim.v.completed_item
local item = vim.tbl_get(comp, 'user_data', 'nvim', 'lsp', 'completion_item')
-- check that we were given a snippet
if (
not item
or not item.insertTextFormat
or item.insertTextFormat == 1
) then
return
end
-- remove the inserted text
local cursor = vim.api.nvim_win_get_cursor(0)
local line = vim.api.nvim_get_current_line()
local lnum = cursor[1] - 1
local start_char = cursor[2] - #comp.word
vim.api.nvim_buf_set_text(opts.buf, lnum, start_char, lnum, #line, {''})
-- insert snippet
local snip_text = vim.tbl_get(item, 'textEdit', 'newText') or item.insertText
assert(snip_text, "Language server indicated it had a snippet, but no snippet text could be found!")
require('luasnip').lsp_expand(snip_text)
end
})
@yassinehaddoudi
Copy link

yassinehaddoudi commented Dec 16, 2023

hi, i modified ur gist to make it work for vim snippet, but i didnt work immeadieatly and i had a bug. When i would trigger omnifunc a second time after the first CompletionDone, it would expand/insert text at the wrong place. I realized if go to normal mode inbetween the completions, it does expand/insert the text at the right place, so i added this weird keymap to C-Space as hotfix. Also i changed the length of removing the inserted text from whole line (#line) to complete_item.word (start_char + #word ). I just wanted to say thanks for the code snippet and to share what i modified.

vim.keymap.set("i", "<C-Space>", "<C-x><C-o>", opts)
vim.cmd[[ imap <expr> <CR> pumvisible() ? "<C-y><Esc>a" : "<CR>" ]]
vim.keymap.set({ 'i', 's' }, '<Tab>', function()
   if vim.fn.pumvisible() == 1 then
	return "<C-n>"
   elseif vim.snippet.jumpable(1) then
	return '<cmd>lua vim.snippet.jump(1)<cr>'
   else
     return '<Tab>'
   end
 end, { expr = true })

vim.keymap.set({ 'i', 's' }, '<S-Tab>', function()
	if vim.fn.pumvisible() == 1 then
		return "<C-p>"
	elseif vim.snippet.jumpable(-1) then
		return '<cmd>lua vim.snippet.jump(-1)<cr>'
	else
		return '<S-Tab>'
	end
end, { expr = true })

vim.api.nvim_create_autocmd('CompleteDone', {
  pattern = '*',
  callback = function(opts)
    local comp = vim.v.completed_item
    local item = vim.tbl_get(comp, 'user_data', 'nvim', 'lsp', 'completion_item')
    local word = vim.tbl_get(comp, 'word')
    if (
      not item
      or not item.insertTextFormat
      or item.insertTextFormat == 1
    ) then
      return
    end

    local cursor = vim.api.nvim_win_get_cursor(0)
    local line = vim.api.nvim_get_current_line()
    local lnum = cursor[1] - 1
    local start_char = cursor[2] - #comp.word
    vim.api.nvim_buf_set_text(opts.buf, lnum, start_char, lnum, start_char + #word, {''})

    local snip_text = vim.tbl_get(item, 'textEdit', 'newText') or item.insertText
    assert(snip_text, "Language server indicated it had a snippet, but no snippet text could be found!")
    vim.snippet.expand(snip_text)
  end
})

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