336 lines
8.2 KiB
Markdown
336 lines
8.2 KiB
Markdown
# nvim-cmp
|
|
|
|
A completion plugin for neovim coded by Lua.
|
|
|
|
|
|
Status
|
|
====================
|
|
|
|
not yet stable but ok to use (for testing).
|
|
|
|
|
|
Concept
|
|
====================
|
|
|
|
- Support pairs-wise plugin automatically
|
|
- Fully customizable via Lua functions
|
|
- Fully supported LSP's Completion capabilities
|
|
- Snippets
|
|
- CommitCharacters
|
|
- TriggerCharacters
|
|
- TextEdit and InsertReplaceTextEdit
|
|
- AdditionalTextEdits
|
|
- Markdown documentation
|
|
- Execute commands (Some LSP server needs it to auto-importing. e.g. `sumneko_lua` or `purescript-language-server`)
|
|
- Preselect
|
|
- CompletionItemTags
|
|
|
|
|
|
Setup
|
|
====================
|
|
|
|
First, You should install nvim-cmp itself and completion sources by your favorite plugin manager.
|
|
|
|
The `nvim-cmp` sources can be found in [here](https://github.com/topics/nvim-cmp).
|
|
|
|
```viml
|
|
Plug 'hrsh7th/nvim-cmp'
|
|
Plug 'hrsh7th/cmp-buffer'
|
|
Plug 'hrsh7th/cmp-nvim-lua'
|
|
```
|
|
|
|
Then setup configuration.
|
|
|
|
```viml
|
|
" Setup global configuration. More on configuration below.
|
|
lua <<EOF
|
|
local cmp = require('cmp')
|
|
cmp.setup {
|
|
snippet = {
|
|
expand = function(args)
|
|
-- You must install `vim-vsnip` if you use the following as-is.
|
|
vim.fn['vsnip#anonymous'](args.body)
|
|
end
|
|
},
|
|
|
|
-- You must set mapping if you want.
|
|
mapping = {
|
|
['<C-p>'] = cmp.mapping.select_prev_item(),
|
|
['<C-n>'] = cmp.mapping.select_next_item(),
|
|
['<C-d>'] = cmp.mapping.scroll_docs(-4),
|
|
['<C-f>'] = cmp.mapping.scroll_docs(4),
|
|
['<C-Space>'] = cmp.mapping.complete(),
|
|
['<C-e>'] = cmp.mapping.close(),
|
|
['<CR>'] = cmp.mapping.confirm({
|
|
behavior = cmp.ConfirmBehavior.Insert,
|
|
select = true,
|
|
})
|
|
},
|
|
|
|
-- You should specify your *installed* sources.
|
|
sources = {
|
|
{ name = 'buffer' },
|
|
},
|
|
}
|
|
EOF
|
|
|
|
" Setup buffer configuration (nvim-lua source only enables in Lua filetype).
|
|
autocmd FileType lua lua require'cmp'.setup.buffer {
|
|
\ sources = {
|
|
{ name = 'buffer' },
|
|
\ { name = 'nvim_lua' },
|
|
\ },
|
|
\ }
|
|
```
|
|
|
|
|
|
Configuration
|
|
====================
|
|
|
|
The default configuration can be found in [here](./lua/cmp/config/default.lua)
|
|
|
|
You can use your own configuration like this:
|
|
|
|
```lua
|
|
local cmp = require'cmp'
|
|
cmp.setup {
|
|
...
|
|
completion = {
|
|
autocomplete = { ... },
|
|
},
|
|
sorting = {
|
|
priority_weight = 2.,
|
|
comparators = { ... },
|
|
},
|
|
mapping = {
|
|
...
|
|
},
|
|
sources = { ... },
|
|
...
|
|
}
|
|
```
|
|
|
|
### mapping (type: table<string, fun(fallback: function)>)
|
|
|
|
Define mappings with `cmp.mapping` helper.
|
|
|
|
You can use the following functions as mapping configuration like this.
|
|
|
|
```lua
|
|
mapping = {
|
|
['<C-p>'] = cmp.mapping.select_prev_item(),
|
|
['<C-n>'] = cmp.mapping.select_next_item(),
|
|
['<C-d>'] = cmp.mapping.scroll_docs(-4),
|
|
['<C-f>'] = cmp.mapping.scroll_docs(4),
|
|
['<C-Space>'] = cmp.mapping.complete(),
|
|
['<C-e>'] = cmp.mapping.close(),
|
|
['<CR>'] = cmp.mapping.confirm({
|
|
behavior = cmp.ConfirmBehavior.Replace,
|
|
select = true,
|
|
})
|
|
}
|
|
```
|
|
|
|
- *cmp.mapping.select_prev_item()*
|
|
- *cmp.mapping.select_next_item()*
|
|
- *cmp.mapping.scroll_docs(number)*
|
|
- *cmp.mapping.complete()*
|
|
- *cmp.mapping.close()*
|
|
- *cmp.mapping.confirm({ select = bool, behavior = cmp.ConfirmBehavior.{Insert,Replace} })*
|
|
|
|
In addition, You can specify vim's mode to those mapping functions like this.
|
|
|
|
```lua
|
|
mapping = {
|
|
...
|
|
['<Tab>'] = cmp.mapping(cmp.mapping.select_next_item(), { 'i', 's' })
|
|
...
|
|
}
|
|
```
|
|
|
|
### completion.autocomplete (type: cmp.TriggerEvent[])
|
|
|
|
Which events should trigger `autocompletion`.
|
|
|
|
If you leave this empty or `nil`, `nvim-cmp` does not perform completion automatically.
|
|
You can still use manual completion though (like omni-completion).
|
|
|
|
Default: `{types.cmp.TriggerEvent.InsertEnter, types.cmp.TriggerEvent.TextChanged}`
|
|
|
|
### completion.keyword_pattern (type: string)
|
|
|
|
The default keyword pattern. This value will be used if a source does not set a source specific pattern.
|
|
|
|
Default: `[[\%(-\?\d\+\%(\.\d\+\)\?\|\h\w*\%(-\w*\)*\)]]`
|
|
|
|
### completion.keyword_length (type: number)
|
|
|
|
The minimal length of a word to complete; e.g., do not try to complete when the
|
|
length of the word to the left of the cursor is less than `keyword_length`.
|
|
|
|
Default: `1`
|
|
|
|
|
|
### completion.completeopt (type: string)
|
|
|
|
vim's `completeopt` setting. Warning: Be careful when changing this value.
|
|
|
|
Default: `menu,menuone,noselect`
|
|
|
|
|
|
### formatting.format (type: fun(entry: cmp.Entry, vim_item: vim.CompletedItem): vim.CompletedItem)
|
|
|
|
A function to customize completion menu.
|
|
|
|
You can display the fancy icons to completion-menu with [lspkind-nvim](https://github.com/onsails/lspkind-nvim).
|
|
|
|
```lua
|
|
local lspkind = require('lspkind')
|
|
cmp.setup {
|
|
formatting = {
|
|
format = function(entry, vim_item)
|
|
vim_item.kind = lspkind.presets.default[vim_item.kind]
|
|
return vim_item
|
|
end
|
|
}
|
|
}
|
|
```
|
|
|
|
### sorting.priority_weight (type: number)
|
|
|
|
When sorting completion items before displaying them, boost each item's score
|
|
based on the originating source. Each source gets a base priority of `#sources -
|
|
(source_index - 1)`, and we then multiply this by `priority_weight`:
|
|
|
|
`score = score + ((#sources - (source_index - 1)) * sorting.priority_weight)`
|
|
|
|
Default: `2`
|
|
|
|
### sorting.comparators (type: function[])
|
|
|
|
When sorting completion items, the sort logic tries each function in
|
|
`sorting.comparators` consecutively when comparing two items. The first function
|
|
to return something other than `nil` takes precedence.
|
|
|
|
Each function must return `boolean|nil`.
|
|
|
|
Default:
|
|
```lua
|
|
{
|
|
compare.offset,
|
|
compare.exact,
|
|
compare.score,
|
|
compare.kind,
|
|
compare.sort_text,
|
|
compare.length,
|
|
compare.order,
|
|
}
|
|
```
|
|
|
|
|
|
FAQ
|
|
====================
|
|
|
|
#### How to set up like nvim-compe's `preselect = 'always'`?
|
|
|
|
You can use the following configuration.
|
|
|
|
```lua
|
|
cmp.setup {
|
|
completion = {
|
|
completeopt = 'menu,menuone,noinsert',
|
|
}
|
|
}
|
|
```
|
|
|
|
#### nvim-cmp is slow.
|
|
|
|
I optimized nvim-cmp as much as possible but some reason exists maybe.
|
|
|
|
|
|
Source creation
|
|
====================
|
|
|
|
If you publish `nvim-cmp` source to GitHub, please add `nvim-cmp` topic for the repo.
|
|
|
|
You should read [cmp types](/lua/cmp/types) and [LSP spec](https://microsoft.github.io/language-server-protocol/specifications/specification-current/) to create sources.
|
|
|
|
- The `complete` function is required but others can be omitted.
|
|
- The `callback` argument must always be called.
|
|
- The custom source only can use `require('cmp')`.
|
|
- The custom source can specify `word` property to CompletionItem. (It isn't an LSP specification but supported as a special case.)
|
|
|
|
```lua
|
|
local source = {}
|
|
|
|
---Source constructor.
|
|
source.new = function()
|
|
local self = setmetatable({}, { __index = source })
|
|
self.your_awesome_variable = 1
|
|
return self
|
|
end
|
|
|
|
---Return the source name for some information.
|
|
source.get_debug_name = function()
|
|
return 'example'
|
|
end
|
|
|
|
---Return the source is available or not.
|
|
---@return boolean
|
|
function source:is_available()
|
|
return true
|
|
end
|
|
|
|
---Return keyword pattern which will be used...
|
|
--- 1. Trigger keyword completion
|
|
--- 2. Detect menu start offset
|
|
--- 3. Reset completion state
|
|
---@return string
|
|
function source:get_keyword_pattern()
|
|
return '???'
|
|
end
|
|
|
|
---Return trigger characters.
|
|
---@return string[]
|
|
function source:get_trigger_characters()
|
|
return { ??? }
|
|
end
|
|
|
|
---Invoke completion (required).
|
|
--- If you want to abort completion, just call the callback without arguments.
|
|
---@param request cmp.CompletionRequest
|
|
---@param callback fun(response: lsp.CompletionResponse|nil)
|
|
function source:complete(request, callback)
|
|
callback({
|
|
{ label = 'January' },
|
|
{ label = 'February' },
|
|
{ label = 'March' },
|
|
{ label = 'April' },
|
|
{ label = 'May' },
|
|
{ label = 'June' },
|
|
{ label = 'July' },
|
|
{ label = 'August' },
|
|
{ label = 'September' },
|
|
{ label = 'October' },
|
|
{ label = 'November' },
|
|
{ label = 'December' },
|
|
})
|
|
end
|
|
|
|
---Resolve completion item that will be called when the item selected or before the item confirmation.
|
|
---@param completion_item lsp.CompletionItem
|
|
---@param callback fun(completion_item: lsp.CompletionItem|nil)
|
|
function source:resolve(completion_item, callback)
|
|
callback(completion_item)
|
|
end
|
|
|
|
---Execute command that will be called when after the item confirmation.
|
|
---@param completion_item lsp.CompletionItem
|
|
---@param callback fun(completion_item: lsp.CompletionItem|nil)
|
|
function source:execute(completion_item, callback)
|
|
callback(completion_item)
|
|
end
|
|
|
|
return source
|
|
```
|