nvim-lsp-compl icon indicating copy to clipboard operation
nvim-lsp-compl copied to clipboard

A fast and asynchronous auto-completion plugin for Neovim, focused on LSP.

nvim-lsp-compl

A fast and asynchronous auto-completion plugin for Neovim >= 0.7.0, focused on LSP.

For Neovim 0.5.1 support, checkout ad95138d56b7c84fb02e7c7078e8f5e61fda4596.

Motivation

Why another one?

I wrote the initial code for this within my dotfiles long before plugins like nvim-compe popped up and tuned it over time to accommodate my workflow.

There have been some voices looking for something smaller than nvim-compe, so I decided to extract the code from my dotfiles and make it re-usable for others.

Features

  • Automatically triggers completion on trigger characters advocated by the language server
  • Automatically triggers signature help on characters advocated by the language server
  • Apply additional text edits (Used to resolve imports and so on)
  • Supports lazy resolving of additional text edits if the language server has the capability
  • Optionally supports server side fuzzy matching
  • Optionally supports LSP snippet expansion if LuaSnip or vsnip is installed or a custom snippet-applier is registered

If you need anything else, you better use nvim-compe.

Opinionated behaviors:

  • Snippets are only expanded via explicit opt-in
  • The word in the completion candidates is tuned to exclude parenthesis and arguments, unless you use the snippet expansion.

Non-Goals

Installation

  • Install Neovim >= 0.7.0
  • Install nvim-lsp-compl like any other plugin
    • If using vim-plug: Plug 'mfussenegger/nvim-lsp-compl'
    • If using packer.nvim: use 'mfussenegger/nvim-lsp-compl'

Configuration

You need to call the attach method when the language server clients attaches to a buffer.

If you're using lspconfig you could do this like this:

lua require'lspconfig'.pyls.setup{on_attach=require'lsp_compl'.attach}

If you want to utilize server side fuzzy completion, you would call it like this:

lua require'lspconfig'.pyls.setup{
  on_attach = function(client, bufnr)
    require'lsp_compl'.attach(client, bufnr, { server_side_fuzzy_completion = true })
  end,
}

To expand snippets you need to explicitly accept a completion candidate:

vim.keymap.set('i', '<CR>', function()
  return require('lsp_compl').accept_pum() and '<c-y>' or '<CR>'
end, { expr = true })

Currently snippet expansion tries LuaSnip if available and otherwise falls back to use vim-vsnip, but you can override the expand_snippet function to use a different snippet engine:

require('lsp_compl').expand_snippet = vim.fn['vsnip#anonymous']

Or

require('lsp_compl').expand_snippet = require('luasnip').lsp_expand

The function takes a single argument - the snippet - and is supposed to expand it.

FAQ

Can I disable the automatic signature popup?

Yes, if you set the triggerCharacters of the server to an empty table:

on_attach = function(client, bufnr)
  if client.server_capabilities.signatureHelpProvider then
    client.server_capabilities.signatureHelpProvider.triggerCharacters = {}
  end
  require'lsp_compl'.attach(client, bufnr)
end

Can I customize the trigger characters for completion?

Yes, if you override the triggerCharacters:

on_attach = function(client, bufnr)
  client.server_capabilities.completionProvider.triggerCharacters = {'a', 'e', 'i', 'o', 'u'}
  require'lsp_compl'.attach(client, bufnr)
end

Can I trigger the completion manually?

Yes, call require'lsp_compl'.trigger_completion() while in insert mode. But this won't be much different from using the vim.lsp.omnifunc via i_CTRL-X_CTRL-O.

Can I re-trigger completion when I hit backspace or <C-w> while completion is active?

Yes, you have three options:

  1. Manually trigger the completion (see previous question)
  2. Enable trigger_on_delete:
  -- ...
  on_attach = function(client, bufnr)
    require'lsp_compl'.attach(client, bufnr, { trigger_on_delete = true })
  end
  -- ...
  1. Define a key mapping that always re-triggers it:
inoremap <expr> <BS> (pumvisible() ? "\<BS><cmd> :lua require'lsp_compl'.trigger_completion()<CR>" : "\<BS>")