mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-23 10:30:05 +08:00
perf(cmp): update nvim-cmp
This commit is contained in:
parent
e9b5e713f9
commit
913901272d
3
bundle/nvim-cmp/.github/FUNDING.yml
vendored
3
bundle/nvim-cmp/.github/FUNDING.yml
vendored
@ -1,3 +0,0 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [hrsh7th]
|
@ -7,24 +7,17 @@ body:
|
||||
attributes:
|
||||
label: FAQ
|
||||
options:
|
||||
- label: I have checked the [FAQ](https://github.com/hrsh7th/nvim-cmp/blob/15f08a8faa22d52480cdcb9ef9ca698120f04363/doc/cmp.txt#L616) and it didn't resolve my problem.
|
||||
- label: I have checked the [FAQ](https://github.com/hrsh7th/nvim-cmp/blob/main/doc/cmp.txt) and it didn't resolve my problem.
|
||||
required: true
|
||||
|
||||
- type: checkboxes
|
||||
id: issue-prerequisite
|
||||
id: announcement-prerequisite
|
||||
attributes:
|
||||
label: Issues
|
||||
label: Announcement
|
||||
options:
|
||||
- label: I have checked [existing issues](https://github.com/hrsh7th/nvim-cmp/issues) and there are no open or closed issues with the same problem.
|
||||
- label: I have checked [Breaking change announcement](https://github.com/hrsh7th/nvim-cmp/issues/231).
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: "Neovim Version"
|
||||
description: "`nvim --version`:"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Minimal reproducible full config"
|
||||
@ -34,6 +27,10 @@ body:
|
||||
2. Edit `~/cmp-repro.vim` for reproducing the issue
|
||||
3. Open `nvim -u ~/cmp-repro.vim`
|
||||
4. Check reproduction step
|
||||
value: |
|
||||
```vim
|
||||
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
25
bundle/nvim-cmp/.github/workflows/format.yaml
vendored
Normal file
25
bundle/nvim-cmp/.github/workflows/format.yaml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: format
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- '**.lua'
|
||||
|
||||
jobs:
|
||||
postprocessing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Format with Stylua
|
||||
uses: JohnnyMorganz/stylua-action@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
version: v0.16.1
|
||||
args: ./lua
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
with:
|
||||
commit_message: "Format with stylua"
|
@ -16,13 +16,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: nightly
|
||||
default: true
|
||||
override: true
|
||||
|
||||
- name: Setup neovim
|
||||
uses: rhysd/action-setup-vim@v1
|
||||
with:
|
||||
@ -40,12 +33,9 @@ jobs:
|
||||
- name: Setup tools
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt install -y curl unzip --no-install-recommends
|
||||
bash ./utils/install_stylua.sh
|
||||
luarocks install luacheck
|
||||
luarocks install vusted
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: make integration
|
||||
|
||||
|
19
bundle/nvim-cmp/.github/workflows/release.yaml
vendored
Normal file
19
bundle/nvim-cmp/.github/workflows/release.yaml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: "release"
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
jobs:
|
||||
luarocks-upload:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: LuaRocks Upload
|
||||
uses: nvim-neorocks/luarocks-tag-release@v3
|
||||
env:
|
||||
LUAROCKS_API_KEY: ${{ secrets.LUAROCKS_API_KEY }}
|
||||
with:
|
||||
detailed_description: |
|
||||
A completion engine plugin for neovim written in Lua.
|
||||
Completion sources are installed from external repositories and "sourced".
|
||||
|
7
bundle/nvim-cmp/Makefile
vendored
7
bundle/nvim-cmp/Makefile
vendored
@ -1,7 +1,3 @@
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
stylua --config-path stylua.toml --glob 'lua/**/*.lua' -- lua
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
luacheck ./lua
|
||||
@ -12,13 +8,10 @@ test:
|
||||
|
||||
.PHONY: pre-commit
|
||||
pre-commit:
|
||||
./utils/stylua --config-path stylua.toml --glob 'lua/**/*.lua' -- lua
|
||||
luacheck lua
|
||||
vusted lua
|
||||
|
||||
.PHONY: integration
|
||||
integration:
|
||||
./utils/stylua --config-path stylua.toml --check --glob 'lua/**/*.lua' -- lua
|
||||
luacheck lua
|
||||
vusted lua
|
||||
|
||||
|
132
bundle/nvim-cmp/README.md
vendored
132
bundle/nvim-cmp/README.md
vendored
@ -3,34 +3,31 @@
|
||||
A completion engine plugin for neovim written in Lua.
|
||||
Completion sources are installed from external repositories and "sourced".
|
||||
|
||||
<video src="https://user-images.githubusercontent.com/629908/139000570-3ac39587-a88b-43c6-b35e-207489719359.mp4" width="100%"></video>
|
||||
https://github.com/hrsh7th/nvim-cmp/assets/22756295/afa70011-9121-4e42-aedd-0153b630eeab
|
||||
|
||||
Readme!
|
||||
====================
|
||||
|
||||
1. nvim-cmp's breaking changes are documented [here](https://github.com/hrsh7th/nvim-cmp/issues/231).
|
||||
1. There is a GitHub issue that documents [breaking changes](https://github.com/hrsh7th/nvim-cmp/issues/231) for nvim-cmp. Subscribe to the issue to be notified of upcoming breaking changes.
|
||||
2. This is my hobby project. You can support me via GitHub sponsors.
|
||||
3. Bug reports are welcome, but I might not fix if you don't provide a minimal reproduction configuration and steps.
|
||||
4. The nvim-cmp documents is [here](./doc/cmp.txt).
|
||||
|
||||
|
||||
3. Bug reports are welcome, but don't expect a fix unless you provide minimal configuration and steps to reproduce your issue.
|
||||
4. The `cmp.mapping.preset.*` is pre-defined configuration that aims to mimic neovim's native like behavior. It can be changed without announcement. Please manage key-mapping by yourself.
|
||||
|
||||
Concept
|
||||
====================
|
||||
|
||||
- Full support for LSP completion related capabilities
|
||||
- Powerful customizability via Lua functions
|
||||
- Smart handling of key mapping
|
||||
- Smart handling of key mappings
|
||||
- No flicker
|
||||
|
||||
|
||||
|
||||
Setup
|
||||
====================
|
||||
|
||||
### Recommended Configuration
|
||||
|
||||
This example configuration uses `vim-plug` as the plugin manager and `vim-vsnip` as snippet plugin.
|
||||
This example configuration uses `vim-plug` as the plugin manager and `vim-vsnip` as a snippet plugin.
|
||||
|
||||
```lua
|
||||
call plug#begin(s:plug_dir)
|
||||
@ -59,10 +56,8 @@ Plug 'hrsh7th/vim-vsnip'
|
||||
|
||||
call plug#end()
|
||||
|
||||
set completeopt=menu,menuone,noselect
|
||||
|
||||
lua <<EOF
|
||||
-- Setup nvim-cmp.
|
||||
-- Set up nvim-cmp.
|
||||
local cmp = require'cmp'
|
||||
|
||||
cmp.setup({
|
||||
@ -75,17 +70,17 @@ lua <<EOF
|
||||
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
|
||||
end,
|
||||
},
|
||||
mapping = {
|
||||
['<C-b>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
|
||||
['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
|
||||
['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
|
||||
['<C-y>'] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
|
||||
['<C-e>'] = cmp.mapping({
|
||||
i = cmp.mapping.abort(),
|
||||
c = cmp.mapping.close(),
|
||||
}),
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
|
||||
window = {
|
||||
-- completion = cmp.config.window.bordered(),
|
||||
-- documentation = cmp.config.window.bordered(),
|
||||
},
|
||||
mapping = cmp.mapping.preset.insert({
|
||||
['<C-b>'] = cmp.mapping.scroll_docs(-4),
|
||||
['<C-f>'] = cmp.mapping.scroll_docs(4),
|
||||
['<C-Space>'] = cmp.mapping.complete(),
|
||||
['<C-e>'] = cmp.mapping.abort(),
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
|
||||
}),
|
||||
sources = cmp.config.sources({
|
||||
{ name = 'nvim_lsp' },
|
||||
{ name = 'vsnip' }, -- For vsnip users.
|
||||
@ -100,14 +95,15 @@ lua <<EOF
|
||||
-- Set configuration for specific filetype.
|
||||
cmp.setup.filetype('gitcommit', {
|
||||
sources = cmp.config.sources({
|
||||
{ name = 'cmp_git' }, -- You can specify the `cmp_git` source if you were installed it.
|
||||
{ name = 'git' }, -- You can specify the `git` source if [you were installed it](https://github.com/petertriho/cmp-git).
|
||||
}, {
|
||||
{ name = 'buffer' },
|
||||
})
|
||||
})
|
||||
|
||||
-- Use buffer source for `/` (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline('/', {
|
||||
-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline({ '/', '?' }, {
|
||||
mapping = cmp.mapping.preset.cmdline(),
|
||||
sources = {
|
||||
{ name = 'buffer' }
|
||||
}
|
||||
@ -115,6 +111,7 @@ lua <<EOF
|
||||
|
||||
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline(':', {
|
||||
mapping = cmp.mapping.preset.cmdline(),
|
||||
sources = cmp.config.sources({
|
||||
{ name = 'path' }
|
||||
}, {
|
||||
@ -122,8 +119,8 @@ lua <<EOF
|
||||
})
|
||||
})
|
||||
|
||||
-- Setup lspconfig.
|
||||
local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())
|
||||
-- Set up lspconfig.
|
||||
local capabilities = require('cmp_nvim_lsp').default_capabilities()
|
||||
-- Replace <YOUR_LSP_SERVER> with each lsp server you've enabled.
|
||||
require('lspconfig')['<YOUR_LSP_SERVER>'].setup {
|
||||
capabilities = capabilities
|
||||
@ -131,85 +128,12 @@ lua <<EOF
|
||||
EOF
|
||||
```
|
||||
|
||||
|
||||
### Where can I find more completion sources?
|
||||
|
||||
A list of available sources can be found in the [Wiki](https://github.com/hrsh7th/nvim-cmp/wiki/List-of-sources) or by searching for projects that match the nvim-cmp [GitHub topic](https://github.com/topics/nvim-cmp).
|
||||
Have a look at the [Wiki](https://github.com/hrsh7th/nvim-cmp/wiki/List-of-sources) and the `nvim-cmp` [GitHub topic](https://github.com/topics/nvim-cmp).
|
||||
|
||||
|
||||
### Where can I find advanced configuration examples?
|
||||
|
||||
Please see the corresponding [FAQ](#how-to-show-name-of-item-kind-and-source-like-compe) section or [Wiki pages](https://github.com/hrsh7th/nvim-cmp/wiki).
|
||||
|
||||
|
||||
Advanced configuration example
|
||||
====================
|
||||
|
||||
### Use nvim-cmp as smart omnifunc handler.
|
||||
|
||||
nvim-cmp can be used as flexible omnifunc manager.
|
||||
|
||||
```lua
|
||||
local cmp = require('cmp')
|
||||
cmp.setup {
|
||||
completion = {
|
||||
autocomplete = false, -- disable auto-completion.
|
||||
},
|
||||
}
|
||||
|
||||
_G.vimrc = _G.vimrc or {}
|
||||
_G.vimrc.cmp = _G.vimrc.cmp or {}
|
||||
_G.vimrc.cmp.lsp = function()
|
||||
cmp.complete({
|
||||
config = {
|
||||
sources = {
|
||||
{ name = 'nvim_lsp' }
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
_G.vimrc.cmp.snippet = function()
|
||||
cmp.complete({
|
||||
config = {
|
||||
sources = {
|
||||
{ name = 'vsnip' }
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
vim.cmd([[
|
||||
inoremap <C-x><C-o> <Cmd>lua vimrc.cmp.lsp()<CR>
|
||||
inoremap <C-x><C-s> <Cmd>lua vimrc.cmp.snippet()<CR>
|
||||
]])
|
||||
```
|
||||
|
||||
### Full managed completion behavior.
|
||||
|
||||
```lua
|
||||
local cmp = require('cmp')
|
||||
|
||||
cmp.setup {
|
||||
completion = {
|
||||
autocomplete = false, -- disable auto-completion.
|
||||
}
|
||||
}
|
||||
|
||||
_G.vimrc = _G.vimrc or {}
|
||||
_G.vimrc.cmp = _G.vimrc.cmp or {}
|
||||
_G.vimrc.cmp.on_text_changed = function()
|
||||
local cursor = vim.api.nvim_win_get_cursor(0)
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local before = string.sub(line, 1, cursor[2] + 1)
|
||||
if before:match('%s*$') then
|
||||
cmp.complete() -- Trigger completion only if the cursor is placed at the end of line.
|
||||
end
|
||||
end
|
||||
vim.cmd([[
|
||||
augroup vimrc
|
||||
autocmd
|
||||
autocmd TextChanged,TextChangedI,TextChangedP * call luaeval('vimrc.cmp.on_text_changed()')
|
||||
augroup END
|
||||
]])
|
||||
```
|
||||
|
||||
|
||||
|
||||
See the [Wiki](https://github.com/hrsh7th/nvim-cmp/wiki).
|
||||
|
13
bundle/nvim-cmp/autoload/cmp.vim
vendored
13
bundle/nvim-cmp/autoload/cmp.vim
vendored
@ -6,7 +6,16 @@ let s:sources = {}
|
||||
"
|
||||
function! cmp#register_source(name, source) abort
|
||||
let l:methods = []
|
||||
for l:method in ['is_available', 'get_debug_name', 'get_trigger_characters', 'get_keyword_pattern', 'complete', 'execute', 'resolve']
|
||||
for l:method in [
|
||||
\ 'is_available',
|
||||
\ 'get_debug_name',
|
||||
\ 'get_position_encoding_kind',
|
||||
\ 'get_trigger_characters',
|
||||
\ 'get_keyword_pattern',
|
||||
\ 'complete',
|
||||
\ 'execute',
|
||||
\ 'resolve'
|
||||
\ ]
|
||||
if has_key(a:source, l:method) && type(a:source[l:method]) == v:t_func
|
||||
call add(l:methods, l:method)
|
||||
endif
|
||||
@ -39,6 +48,8 @@ function! cmp#_method(bridge_id, method, args) abort
|
||||
return l:source[a:method]()
|
||||
elseif a:method ==# 'get_debug_name'
|
||||
return l:source[a:method]()
|
||||
elseif a:method ==# 'get_position_encoding_kind'
|
||||
return l:source[a:method](a:args[0])
|
||||
elseif a:method ==# 'get_keyword_pattern'
|
||||
return l:source[a:method](a:args[0])
|
||||
elseif a:method ==# 'get_trigger_characters'
|
||||
|
636
bundle/nvim-cmp/doc/cmp.txt
vendored
636
bundle/nvim-cmp/doc/cmp.txt
vendored
File diff suppressed because it is too large
Load Diff
61
bundle/nvim-cmp/lua/cmp/config.lua
vendored
61
bundle/nvim-cmp/lua/cmp/config.lua
vendored
@ -14,7 +14,7 @@ config.cache = cache.new()
|
||||
---@type cmp.ConfigSchema
|
||||
config.global = require('cmp.config.default')()
|
||||
|
||||
---@type table<number, cmp.ConfigSchema>
|
||||
---@type table<integer, cmp.ConfigSchema>
|
||||
config.buffers = {}
|
||||
|
||||
---@type table<string, cmp.ConfigSchema>
|
||||
@ -29,14 +29,14 @@ config.onetime = {}
|
||||
---Set configuration for global.
|
||||
---@param c cmp.ConfigSchema
|
||||
config.set_global = function(c)
|
||||
config.global = misc.merge(config.normalize(c), config.normalize(config.global))
|
||||
config.global = config.normalize(misc.merge(c, config.global))
|
||||
config.global.revision = config.global.revision or 1
|
||||
config.global.revision = config.global.revision + 1
|
||||
end
|
||||
|
||||
---Set configuration for buffer
|
||||
---@param c cmp.ConfigSchema
|
||||
---@param bufnr number|nil
|
||||
---@param bufnr integer
|
||||
config.set_buffer = function(c, bufnr)
|
||||
local revision = (config.buffers[bufnr] or {}).revision or 1
|
||||
config.buffers[bufnr] = c or {}
|
||||
@ -56,11 +56,13 @@ end
|
||||
|
||||
---Set configuration for cmdline
|
||||
---@param c cmp.ConfigSchema
|
||||
---@param cmdtype string
|
||||
config.set_cmdline = function(c, cmdtype)
|
||||
local revision = (config.cmdline[cmdtype] or {}).revision or 1
|
||||
config.cmdline[cmdtype] = c or {}
|
||||
config.cmdline[cmdtype].revision = revision + 1
|
||||
---@param cmdtypes string|string[]
|
||||
config.set_cmdline = function(c, cmdtypes)
|
||||
for _, cmdtype in ipairs(type(cmdtypes) == 'table' and cmdtypes or { cmdtypes }) do
|
||||
local revision = (config.cmdline[cmdtype] or {}).revision or 1
|
||||
config.cmdline[cmdtype] = c or {}
|
||||
config.cmdline[cmdtype].revision = revision + 1
|
||||
end
|
||||
end
|
||||
|
||||
---Set configuration as oneshot completion.
|
||||
@ -74,7 +76,9 @@ end
|
||||
---@return cmp.ConfigSchema
|
||||
config.get = function()
|
||||
local global_config = config.global
|
||||
if config.onetime.sources then
|
||||
|
||||
-- The config object already has `revision` key.
|
||||
if #vim.tbl_keys(config.onetime) > 1 then
|
||||
local onetime_config = config.onetime
|
||||
return config.cache:ensure({
|
||||
'get',
|
||||
@ -82,7 +86,10 @@ config.get = function()
|
||||
global_config.revision or 0,
|
||||
onetime_config.revision or 0,
|
||||
}, function()
|
||||
return misc.merge(config.normalize(onetime_config), config.normalize(global_config))
|
||||
local c = {}
|
||||
c = misc.merge(c, config.normalize(onetime_config))
|
||||
c = misc.merge(c, config.normalize(global_config))
|
||||
return c
|
||||
end)
|
||||
elseif api.is_cmdline_mode() then
|
||||
local cmdtype = vim.fn.getcmdtype()
|
||||
@ -94,7 +101,10 @@ config.get = function()
|
||||
cmdtype,
|
||||
cmdline_config.revision or 0,
|
||||
}, function()
|
||||
return misc.merge(config.normalize(cmdline_config), config.normalize(global_config))
|
||||
local c = {}
|
||||
c = misc.merge(c, config.normalize(cmdline_config))
|
||||
c = misc.merge(c, config.normalize(global_config))
|
||||
return c
|
||||
end)
|
||||
else
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
@ -111,9 +121,9 @@ config.get = function()
|
||||
buffer_config.revision or 0,
|
||||
}, function()
|
||||
local c = {}
|
||||
c = misc.merge(c, config.normalize(buffer_config))
|
||||
c = misc.merge(c, config.normalize(filetype_config))
|
||||
c = misc.merge(c, config.normalize(global_config))
|
||||
c = misc.merge(config.normalize(c), config.normalize(buffer_config))
|
||||
c = misc.merge(config.normalize(c), config.normalize(filetype_config))
|
||||
c = misc.merge(config.normalize(c), config.normalize(global_config))
|
||||
return c
|
||||
end)
|
||||
end
|
||||
@ -144,9 +154,6 @@ end
|
||||
---Return the current menu is native or not.
|
||||
config.is_native_menu = function()
|
||||
local c = config.get()
|
||||
if c.experimental and c.experimental.native_menu then
|
||||
return true
|
||||
end
|
||||
if c.view and c.view.entries then
|
||||
return c.view.entries == 'native' or c.view.entries.name == 'native'
|
||||
end
|
||||
@ -154,12 +161,14 @@ config.is_native_menu = function()
|
||||
end
|
||||
|
||||
---Normalize mapping key
|
||||
---@param c cmp.ConfigSchema
|
||||
---@param c any
|
||||
---@return cmp.ConfigSchema
|
||||
config.normalize = function(c)
|
||||
-- make sure c is not 'nil'
|
||||
---@type any
|
||||
c = c == nil and {} or c
|
||||
|
||||
-- Normalize mapping.
|
||||
if c.mapping then
|
||||
local normalized = {}
|
||||
for k, v in pairs(c.mapping) do
|
||||
@ -168,6 +177,7 @@ config.normalize = function(c)
|
||||
c.mapping = normalized
|
||||
end
|
||||
|
||||
-- Notice experimental.native_menu.
|
||||
if c.experimental and c.experimental.native_menu then
|
||||
vim.api.nvim_echo({
|
||||
{ '[nvim-cmp] ', 'Normal' },
|
||||
@ -182,6 +192,21 @@ config.normalize = function(c)
|
||||
c.view.entries = c.view.entries or 'native'
|
||||
end
|
||||
|
||||
-- Notice documentation.
|
||||
if c.documentation ~= nil then
|
||||
vim.api.nvim_echo({
|
||||
{ '[nvim-cmp] ', 'Normal' },
|
||||
{ 'documentation', 'WarningMsg' },
|
||||
{ ' is deprecated.\n', 'Normal' },
|
||||
{ '[nvim-cmp] Please use ', 'Normal' },
|
||||
{ 'window.documentation = cmp.config.window.bordered()', 'WarningMsg' },
|
||||
{ ' instead.', 'Normal' },
|
||||
}, true, {})
|
||||
c.window = c.window or {}
|
||||
c.window.documentation = c.documentation
|
||||
end
|
||||
|
||||
-- Notice sources.[n].opts
|
||||
if c.sources then
|
||||
for _, s in ipairs(c.sources) do
|
||||
if s.opts and not s.option then
|
||||
|
15
bundle/nvim-cmp/lua/cmp/config/compare.lua
vendored
15
bundle/nvim-cmp/lua/cmp/config/compare.lua
vendored
@ -1,6 +1,5 @@
|
||||
local types = require('cmp.types')
|
||||
local cache = require('cmp.utils.cache')
|
||||
local misc = require('cmp.utils.misc')
|
||||
|
||||
local compare = {}
|
||||
|
||||
@ -71,7 +70,7 @@ end
|
||||
|
||||
-- sortText
|
||||
compare.sort_text = function(entry1, entry2)
|
||||
if misc.safe(entry1.completion_item.sortText) and misc.safe(entry2.completion_item.sortText) then
|
||||
if entry1.completion_item.sortText and entry2.completion_item.sortText then
|
||||
local diff = vim.stricmp(entry1.completion_item.sortText, entry2.completion_item.sortText)
|
||||
if diff < 0 then
|
||||
return true
|
||||
@ -108,7 +107,7 @@ compare.locality = setmetatable({
|
||||
locality_map = {},
|
||||
update = function(self)
|
||||
local config = require('cmp').get_config()
|
||||
if not vim.tbl_contains(config.sorting.comparators, compare.scopes) then
|
||||
if not vim.tbl_contains(config.sorting.comparators, compare.locality) then
|
||||
return
|
||||
end
|
||||
|
||||
@ -132,7 +131,7 @@ compare.locality = setmetatable({
|
||||
local s, e = regexp:match_str(buffer)
|
||||
if s and e then
|
||||
local w = string.sub(buffer, s + 1, e)
|
||||
local d = math.abs(i - cursor_row) - (is_above and 0.1 or 0)
|
||||
local d = math.abs(i - cursor_row) - (is_above and 1 or 0)
|
||||
locality_map[w] = math.min(locality_map[w] or math.huge, d)
|
||||
buffer = string.sub(buffer, e + 1)
|
||||
else
|
||||
@ -145,7 +144,7 @@ compare.locality = setmetatable({
|
||||
self.locality_map[w] = math.min(self.locality_map[w] or d, math.abs(i - cursor_row))
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
}, {
|
||||
__call = function(self, entry1, entry2)
|
||||
local local1 = self.locality_map[entry1:get_word()]
|
||||
@ -159,7 +158,7 @@ compare.locality = setmetatable({
|
||||
end
|
||||
return local1 < local2
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- scopes
|
||||
@ -175,7 +174,6 @@ compare.scopes = setmetatable({
|
||||
if ok then
|
||||
local win, buf = vim.api.nvim_get_current_win(), vim.api.nvim_get_current_buf()
|
||||
local cursor_row = vim.api.nvim_win_get_cursor(win)[1] - 1
|
||||
local ts_utils = require('nvim-treesitter.ts_utils')
|
||||
|
||||
-- Cursor scope.
|
||||
local cursor_scope = nil
|
||||
@ -205,7 +203,8 @@ compare.scopes = setmetatable({
|
||||
for _, definition in pairs(definitions) do
|
||||
if s <= definition.node:start() and definition.node:end_() <= e then
|
||||
if scope:id() == locals.containing_scope(definition.node, buf):id() then
|
||||
local text = ts_utils.get_node_text(definition.node)[1]
|
||||
local get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text
|
||||
local text = get_node_text(definition.node, buf) or ''
|
||||
if not self.scopes_map[text] then
|
||||
self.scopes_map[text] = depth
|
||||
end
|
||||
|
67
bundle/nvim-cmp/lua/cmp/config/context.lua
vendored
67
bundle/nvim-cmp/lua/cmp/config/context.lua
vendored
@ -1,65 +1,60 @@
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
local context = {}
|
||||
|
||||
---Check if cursor is in syntax group
|
||||
---@param group string
|
||||
---@param group string | []string
|
||||
---@return boolean
|
||||
context.in_syntax_group = function(group)
|
||||
local lnum, col = vim.fn.line('.'), math.min(vim.fn.col('.'), #vim.fn.getline('.'))
|
||||
for _, syn_id in ipairs(vim.fn.synstack(lnum, col)) do
|
||||
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
if not api.is_insert_mode() then
|
||||
col = col + 1
|
||||
end
|
||||
|
||||
for _, syn_id in ipairs(vim.fn.synstack(row, col)) do
|
||||
syn_id = vim.fn.synIDtrans(syn_id) -- Resolve :highlight links
|
||||
if vim.fn.synIDattr(syn_id, 'name') == group then
|
||||
local g = vim.fn.synIDattr(syn_id, 'name')
|
||||
if type(group) == 'string' and g == group then
|
||||
return true
|
||||
elseif type(group) == 'table' and vim.tbl_contains(group, g) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
---Check if cursor is in treesitter capture
|
||||
---@param capture string
|
||||
---@param capture string | []string
|
||||
---@return boolean
|
||||
context.in_treesitter_capture = function(capture)
|
||||
local highlighter = require('vim.treesitter.highlighter')
|
||||
local ts_utils = require('nvim-treesitter.ts_utils')
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
|
||||
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
row = row - 1
|
||||
if vim.api.nvim_get_mode().mode == 'i' then
|
||||
col = col - 1
|
||||
end
|
||||
|
||||
local self = highlighter.active[buf]
|
||||
if not self then
|
||||
local get_captures_at_pos = -- See neovim/neovim#20331
|
||||
require('vim.treesitter').get_captures_at_pos -- for neovim >= 0.8 or require('vim.treesitter').get_captures_at_position -- for neovim < 0.8
|
||||
|
||||
local captures_at_cursor = vim.tbl_map(function(x)
|
||||
return x.capture
|
||||
end, get_captures_at_pos(buf, row, col))
|
||||
|
||||
if vim.tbl_isempty(captures_at_cursor) then
|
||||
return false
|
||||
end
|
||||
|
||||
local node_types = {}
|
||||
|
||||
self.tree:for_each_tree(function(tstree, tree)
|
||||
if not tstree then
|
||||
return
|
||||
end
|
||||
|
||||
local root = tstree:root()
|
||||
local root_start_row, _, root_end_row, _ = root:range()
|
||||
if root_start_row > row or root_end_row < row then
|
||||
return
|
||||
end
|
||||
|
||||
local query = self:get_query(tree:lang())
|
||||
if not query:query() then
|
||||
return
|
||||
end
|
||||
|
||||
local iter = query:query():iter_captures(root, self.bufnr, row, row + 1)
|
||||
for _, node, _ in iter do
|
||||
if ts_utils.is_in_node_range(node, row, col) then
|
||||
table.insert(node_types, node:type())
|
||||
elseif type(capture) == 'string' and vim.tbl_contains(captures_at_cursor, capture) then
|
||||
return true
|
||||
elseif type(capture) == 'table' then
|
||||
for _, v in ipairs(capture) do
|
||||
if vim.tbl_contains(captures_at_cursor, v) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end, true)
|
||||
end
|
||||
|
||||
return vim.tbl_contains(node_types, capture)
|
||||
return false
|
||||
end
|
||||
|
||||
return context
|
||||
|
117
bundle/nvim-cmp/lua/cmp/config/default.lua
vendored
117
bundle/nvim-cmp/lua/cmp/config/default.lua
vendored
@ -1,13 +1,12 @@
|
||||
local compare = require('cmp.config.compare')
|
||||
local mapping = require('cmp.config.mapping')
|
||||
local keymap = require('cmp.utils.keymap')
|
||||
local types = require('cmp.types')
|
||||
|
||||
local WIDE_HEIGHT = 40
|
||||
|
||||
---@return cmp.ConfigSchema
|
||||
return function()
|
||||
return {
|
||||
---@type cmp.ConfigSchema
|
||||
local config = {
|
||||
enabled = function()
|
||||
local disabled = false
|
||||
disabled = disabled or (vim.api.nvim_buf_get_option(0, 'buftype') == 'prompt')
|
||||
@ -16,85 +15,35 @@ return function()
|
||||
return not disabled
|
||||
end,
|
||||
|
||||
preselect = types.cmp.PreselectMode.Item,
|
||||
|
||||
mapping = {
|
||||
['<Down>'] = mapping({
|
||||
i = mapping.select_next_item({ behavior = types.cmp.SelectBehavior.Select }),
|
||||
c = function(fallback)
|
||||
local cmp = require('cmp')
|
||||
cmp.close()
|
||||
vim.schedule(cmp.suspend())
|
||||
fallback()
|
||||
end,
|
||||
}),
|
||||
['<Up>'] = mapping({
|
||||
i = mapping.select_prev_item({ behavior = types.cmp.SelectBehavior.Select }),
|
||||
c = function(fallback)
|
||||
local cmp = require('cmp')
|
||||
cmp.close()
|
||||
vim.schedule(cmp.suspend())
|
||||
fallback()
|
||||
end,
|
||||
}),
|
||||
['<Tab>'] = mapping({
|
||||
c = function()
|
||||
local cmp = require('cmp')
|
||||
if #cmp.core:get_sources() > 0 and not require('cmp.config').is_native_menu() then
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
else
|
||||
if vim.fn.pumvisible() == 0 then
|
||||
vim.api.nvim_feedkeys(keymap.t('<C-z>'), 'in', true)
|
||||
else
|
||||
vim.api.nvim_feedkeys(keymap.t('<C-n>'), 'in', true)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}),
|
||||
['<S-Tab>'] = mapping({
|
||||
c = function()
|
||||
local cmp = require('cmp')
|
||||
if #cmp.core:get_sources() > 0 and not require('cmp.config').is_native_menu() then
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item()
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
else
|
||||
if vim.fn.pumvisible() == 0 then
|
||||
vim.api.nvim_feedkeys(keymap.t('<C-z><C-p><C-p>'), 'in', true)
|
||||
else
|
||||
vim.api.nvim_feedkeys(keymap.t('<C-p>'), 'in', true)
|
||||
end
|
||||
end
|
||||
end,
|
||||
}),
|
||||
['<C-n>'] = mapping(mapping.select_next_item({ behavior = types.cmp.SelectBehavior.Insert }), { 'i', 'c' }),
|
||||
['<C-p>'] = mapping(mapping.select_prev_item({ behavior = types.cmp.SelectBehavior.Insert }), { 'i', 'c' }),
|
||||
['<C-y>'] = mapping.confirm({ select = false }),
|
||||
['<C-e>'] = mapping.abort(),
|
||||
performance = {
|
||||
debounce = 60,
|
||||
throttle = 30,
|
||||
fetching_timeout = 500,
|
||||
async_budget = 1,
|
||||
max_view_entries = 200,
|
||||
},
|
||||
|
||||
preselect = types.cmp.PreselectMode.Item,
|
||||
|
||||
mapping = {},
|
||||
|
||||
snippet = {
|
||||
expand = function()
|
||||
expand = function(_)
|
||||
error('snippet engine is not configured.')
|
||||
end,
|
||||
},
|
||||
|
||||
completion = {
|
||||
keyword_length = 1,
|
||||
keyword_pattern = [[\%(-\?\d\+\%(\.\d\+\)\?\|\h\w*\%(-\w*\)*\)]],
|
||||
autocomplete = {
|
||||
types.cmp.TriggerEvent.TextChanged,
|
||||
},
|
||||
completeopt = 'menu,menuone,noselect',
|
||||
keyword_pattern = [[\%(-\?\d\+\%(\.\d\+\)\?\|\h\w*\%(-\w*\)*\)]],
|
||||
keyword_length = 1,
|
||||
},
|
||||
|
||||
formatting = {
|
||||
expandable_indicator = true,
|
||||
fields = { 'abbr', 'kind', 'menu' },
|
||||
format = function(_, vim_item)
|
||||
return vim_item
|
||||
@ -103,6 +52,8 @@ return function()
|
||||
|
||||
matching = {
|
||||
disallow_fuzzy_matching = false,
|
||||
disallow_fullfuzzy_matching = false,
|
||||
disallow_partial_fuzzy_matching = true,
|
||||
disallow_partial_matching = false,
|
||||
disallow_prefix_unmatching = false,
|
||||
},
|
||||
@ -117,7 +68,7 @@ return function()
|
||||
compare.recently_used,
|
||||
compare.locality,
|
||||
compare.kind,
|
||||
compare.sort_text,
|
||||
-- compare.sort_text,
|
||||
compare.length,
|
||||
compare.order,
|
||||
},
|
||||
@ -125,13 +76,6 @@ return function()
|
||||
|
||||
sources = {},
|
||||
|
||||
documentation = {
|
||||
border = { '', '', '', ' ', '', '', '', ' ' },
|
||||
winhighlight = 'NormalFloat:NormalFloat,FloatBorder:NormalFloat',
|
||||
maxwidth = math.floor((WIDE_HEIGHT * 2) * (vim.o.columns / (WIDE_HEIGHT * 2 * 16 / 9))),
|
||||
maxheight = math.floor(WIDE_HEIGHT * (WIDE_HEIGHT / vim.o.lines)),
|
||||
},
|
||||
|
||||
confirmation = {
|
||||
default_behavior = types.cmp.ConfirmBehavior.Insert,
|
||||
get_commit_characters = function(commit_characters)
|
||||
@ -146,7 +90,28 @@ return function()
|
||||
},
|
||||
|
||||
view = {
|
||||
entries = { name = 'custom', selection_order = 'top_down' },
|
||||
entries = {
|
||||
name = 'custom',
|
||||
selection_order = 'top_down',
|
||||
},
|
||||
},
|
||||
|
||||
window = {
|
||||
completion = {
|
||||
border = { '', '', '', '', '', '', '', '' },
|
||||
winhighlight = 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None',
|
||||
scrolloff = 0,
|
||||
col_offset = 0,
|
||||
side_padding = 1,
|
||||
scrollbar = true,
|
||||
},
|
||||
documentation = {
|
||||
max_height = math.floor(WIDE_HEIGHT * (WIDE_HEIGHT / vim.o.lines)),
|
||||
max_width = math.floor((WIDE_HEIGHT * 2) * (vim.o.columns / (WIDE_HEIGHT * 2 * 16 / 9))),
|
||||
border = { '', '', '', ' ', '', '', '', ' ' },
|
||||
winhighlight = 'FloatBorder:NormalFloat',
|
||||
},
|
||||
},
|
||||
}
|
||||
return config
|
||||
end
|
||||
|
126
bundle/nvim-cmp/lua/cmp/config/mapping.lua
vendored
126
bundle/nvim-cmp/lua/cmp/config/mapping.lua
vendored
@ -1,5 +1,22 @@
|
||||
local mapping
|
||||
mapping = setmetatable({}, {
|
||||
local types = require('cmp.types')
|
||||
local misc = require('cmp.utils.misc')
|
||||
local keymap = require('cmp.utils.keymap')
|
||||
|
||||
local function merge_keymaps(base, override)
|
||||
local normalized_base = {}
|
||||
for k, v in pairs(base) do
|
||||
normalized_base[keymap.normalize(k)] = v
|
||||
end
|
||||
|
||||
local normalized_override = {}
|
||||
for k, v in pairs(override) do
|
||||
normalized_override[keymap.normalize(k)] = v
|
||||
end
|
||||
|
||||
return misc.merge(normalized_base, normalized_override)
|
||||
end
|
||||
|
||||
local mapping = setmetatable({}, {
|
||||
__call = function(_, invoke, modes)
|
||||
if type(invoke) == 'function' then
|
||||
local map = {}
|
||||
@ -12,8 +29,111 @@ mapping = setmetatable({}, {
|
||||
end,
|
||||
})
|
||||
|
||||
---Mapping preset configuration.
|
||||
mapping.preset = {}
|
||||
|
||||
---Mapping preset insert-mode configuration.
|
||||
mapping.preset.insert = function(override)
|
||||
return merge_keymaps(override or {}, {
|
||||
['<Down>'] = {
|
||||
i = mapping.select_next_item({ behavior = types.cmp.SelectBehavior.Select }),
|
||||
},
|
||||
['<Up>'] = {
|
||||
i = mapping.select_prev_item({ behavior = types.cmp.SelectBehavior.Select }),
|
||||
},
|
||||
['<C-n>'] = {
|
||||
i = function()
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item({ behavior = types.cmp.SelectBehavior.Insert })
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<C-p>'] = {
|
||||
i = function()
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item({ behavior = types.cmp.SelectBehavior.Insert })
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<C-y>'] = {
|
||||
i = mapping.confirm({ select = false }),
|
||||
},
|
||||
['<C-e>'] = {
|
||||
i = mapping.abort(),
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
---Mapping preset cmdline-mode configuration.
|
||||
mapping.preset.cmdline = function(override)
|
||||
return merge_keymaps(override or {}, {
|
||||
['<C-z>'] = {
|
||||
c = function()
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<Tab>'] = {
|
||||
c = function()
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<S-Tab>'] = {
|
||||
c = function()
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item()
|
||||
else
|
||||
cmp.complete()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<C-n>'] = {
|
||||
c = function(fallback)
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_next_item()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<C-p>'] = {
|
||||
c = function(fallback)
|
||||
local cmp = require('cmp')
|
||||
if cmp.visible() then
|
||||
cmp.select_prev_item()
|
||||
else
|
||||
fallback()
|
||||
end
|
||||
end,
|
||||
},
|
||||
['<C-e>'] = {
|
||||
c = mapping.abort(),
|
||||
},
|
||||
['<C-y>'] = {
|
||||
c = mapping.confirm({ select = false }),
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
---Invoke completion
|
||||
---@param option cmp.CompleteParams
|
||||
---@param option? cmp.CompleteParams
|
||||
mapping.complete = function(option)
|
||||
return function(fallback)
|
||||
if not require('cmp').complete(option) then
|
||||
|
16
bundle/nvim-cmp/lua/cmp/config/window.lua
vendored
Normal file
16
bundle/nvim-cmp/lua/cmp/config/window.lua
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
local window = {}
|
||||
|
||||
window.bordered = function(opts)
|
||||
opts = opts or {}
|
||||
return {
|
||||
border = opts.border or 'rounded',
|
||||
winhighlight = opts.winhighlight or 'Normal:Normal,FloatBorder:Normal,CursorLine:Visual,Search:None',
|
||||
zindex = opts.zindex or 1001,
|
||||
scrolloff = opts.scrolloff or 0,
|
||||
col_offset = opts.col_offset or 0,
|
||||
side_padding = opts.side_padding or 1,
|
||||
scrollbar = opts.scrollbar == nil and true or opts.scrollbar,
|
||||
}
|
||||
end
|
||||
|
||||
return window
|
16
bundle/nvim-cmp/lua/cmp/context.lua
vendored
16
bundle/nvim-cmp/lua/cmp/context.lua
vendored
@ -10,12 +10,13 @@ local api = require('cmp.utils.api')
|
||||
---@field public prev_context cmp.Context
|
||||
---@field public option cmp.ContextOption
|
||||
---@field public filetype string
|
||||
---@field public time number
|
||||
---@field public bufnr number
|
||||
---@field public time integer
|
||||
---@field public bufnr integer
|
||||
---@field public cursor vim.Position|lsp.Position
|
||||
---@field public cursor_line string
|
||||
---@field public cursor_after_line string
|
||||
---@field public cursor_before_line string
|
||||
---@field public aborted boolean
|
||||
local context = {}
|
||||
|
||||
---Create new empty context
|
||||
@ -31,8 +32,8 @@ context.empty = function()
|
||||
end
|
||||
|
||||
---Create new context
|
||||
---@param prev_context cmp.Context
|
||||
---@param option cmp.ContextOption
|
||||
---@param prev_context? cmp.Context
|
||||
---@param option? cmp.ContextOption
|
||||
---@return cmp.Context
|
||||
context.new = function(prev_context, option)
|
||||
option = option or {}
|
||||
@ -55,9 +56,14 @@ context.new = function(prev_context, option)
|
||||
self.cursor.character = misc.to_utfindex(self.cursor_line, self.cursor.col)
|
||||
self.cursor_before_line = string.sub(self.cursor_line, 1, self.cursor.col - 1)
|
||||
self.cursor_after_line = string.sub(self.cursor_line, self.cursor.col)
|
||||
self.aborted = false
|
||||
return self
|
||||
end
|
||||
|
||||
context.abort = function(self)
|
||||
self.aborted = true
|
||||
end
|
||||
|
||||
---Return context creation reason.
|
||||
---@return cmp.ContextReason
|
||||
context.get_reason = function(self)
|
||||
@ -65,7 +71,7 @@ context.get_reason = function(self)
|
||||
end
|
||||
|
||||
---Get keyword pattern offset
|
||||
---@return number|nil
|
||||
---@return integer
|
||||
context.get_offset = function(self, keyword_pattern)
|
||||
return self.cache:ensure({ 'get_offset', keyword_pattern, self.cursor_before_line }, function()
|
||||
return pattern.offset(keyword_pattern .. '\\m$', self.cursor_before_line) or self.cursor.col
|
||||
|
164
bundle/nvim-cmp/lua/cmp/core.lua
vendored
164
bundle/nvim-cmp/lua/cmp/core.lua
vendored
@ -14,10 +14,6 @@ local types = require('cmp.types')
|
||||
local api = require('cmp.utils.api')
|
||||
local event = require('cmp.utils.event')
|
||||
|
||||
local SOURCE_TIMEOUT = 500
|
||||
local DEBOUNCE_TIME = 80
|
||||
local THROTTLE_TIME = 40
|
||||
|
||||
---@class cmp.Core
|
||||
---@field public suspending boolean
|
||||
---@field public view cmp.View
|
||||
@ -36,9 +32,11 @@ core.new = function()
|
||||
self.view.event:on('keymap', function(...)
|
||||
self:on_keymap(...)
|
||||
end)
|
||||
self.view.event:on('complete_done', function(evt)
|
||||
self.event:emit('complete_done', evt)
|
||||
end)
|
||||
for _, event_name in ipairs({ 'complete_done', 'menu_opened', 'menu_closed' }) do
|
||||
self.view.event:on(event_name, function(evt)
|
||||
self.event:emit(event_name, evt)
|
||||
end)
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@ -49,17 +47,19 @@ core.register_source = function(self, s)
|
||||
end
|
||||
|
||||
---Unregister source
|
||||
---@param source_id string
|
||||
---@param source_id integer
|
||||
core.unregister_source = function(self, source_id)
|
||||
self.sources[source_id] = nil
|
||||
end
|
||||
|
||||
---Get new context
|
||||
---@param option cmp.ContextOption
|
||||
---@param option? cmp.ContextOption
|
||||
---@return cmp.Context
|
||||
core.get_context = function(self, option)
|
||||
self.context:abort()
|
||||
local prev = self.context:clone()
|
||||
prev.prev_context = nil
|
||||
prev.cache = nil
|
||||
local ctx = context.new(prev, option)
|
||||
self:set_context(ctx)
|
||||
return self.context
|
||||
@ -74,13 +74,14 @@ end
|
||||
---Suspend completion
|
||||
core.suspend = function(self)
|
||||
self.suspending = true
|
||||
return function()
|
||||
-- It's needed to avoid conflicting with autocmd debouncing.
|
||||
return vim.schedule_wrap(function()
|
||||
self.suspending = false
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---Get sources that sorted by priority
|
||||
---@param filter cmp.SourceStatus[]|fun(s: cmp.Source): boolean
|
||||
---@param filter? cmp.SourceStatus[]|fun(s: cmp.Source): boolean
|
||||
---@return cmp.Source[]
|
||||
core.get_sources = function(self, filter)
|
||||
local f = function(s)
|
||||
@ -168,7 +169,7 @@ core.on_change = function(self, trigger_event)
|
||||
if vim.tbl_contains(config.get().completion.autocomplete or {}, trigger_event) then
|
||||
self:complete(ctx)
|
||||
else
|
||||
self.filter.timeout = self.view:visible() and THROTTLE_TIME or 0
|
||||
self.filter.timeout = self.view:visible() and config.get().performance.throttle or 0
|
||||
self:filter()
|
||||
end
|
||||
else
|
||||
@ -221,7 +222,7 @@ end
|
||||
|
||||
---Complete common string for current completed entries.
|
||||
core.complete_common_string = function(self)
|
||||
if not self.view:visible() or self.view:get_active_entry() then
|
||||
if not self.view:visible() or self.view:get_selected_entry() then
|
||||
return false
|
||||
end
|
||||
|
||||
@ -240,7 +241,7 @@ core.complete_common_string = function(self)
|
||||
config.set_onetime({})
|
||||
|
||||
local cursor = api.get_cursor()
|
||||
local offset = self.view:get_offset()
|
||||
local offset = self.view:get_offset() or cursor[2]
|
||||
local common_string
|
||||
for _, e in ipairs(self.view:get_entries()) do
|
||||
local vim_item = e:get_vim_item(offset)
|
||||
@ -250,8 +251,10 @@ core.complete_common_string = function(self)
|
||||
common_string = str.get_common_string(common_string, vim_item.word)
|
||||
end
|
||||
end
|
||||
if common_string and #common_string > (1 + cursor[2] - offset) then
|
||||
feedkeys.call(keymap.backspace(string.sub(api.get_current_line(), offset, cursor[2])) .. common_string, 'n')
|
||||
local cursor_before_line = api.get_cursor_before_line()
|
||||
local pretext = cursor_before_line:sub(offset)
|
||||
if common_string and #common_string > #pretext then
|
||||
feedkeys.call(keymap.backspace(pretext) .. common_string, 'n')
|
||||
return true
|
||||
end
|
||||
return false
|
||||
@ -276,17 +279,9 @@ core.complete = function(self, ctx)
|
||||
if s_.incomplete and new:changed(s_.context) then
|
||||
s_:complete(new, callback)
|
||||
else
|
||||
for _, s__ in ipairs(self:get_sources({ source.SourceStatus.FETCHING })) do
|
||||
if s_ == s__ then
|
||||
break
|
||||
end
|
||||
if not s__.incomplete and SOURCE_TIMEOUT > s__:get_fetching_time() then
|
||||
return
|
||||
end
|
||||
end
|
||||
if not self.view:get_active_entry() then
|
||||
self.filter.stop()
|
||||
self.filter.timeout = self.view:visible() and DEBOUNCE_TIME or 0
|
||||
self.filter.timeout = config.get().performance.debounce
|
||||
self:filter()
|
||||
end
|
||||
end
|
||||
@ -296,14 +291,14 @@ core.complete = function(self, ctx)
|
||||
end
|
||||
|
||||
if not self.view:get_active_entry() then
|
||||
self.filter.timeout = self.view:visible() and THROTTLE_TIME or 0
|
||||
self.filter.timeout = self.view:visible() and config.get().performance.throttle or 1
|
||||
self:filter()
|
||||
end
|
||||
end
|
||||
|
||||
---Update completion menu
|
||||
core.filter = async.throttle(function(self)
|
||||
self.filter.timeout = self.view:visible() and THROTTLE_TIME or 0
|
||||
local async_filter = async.wrap(function(self)
|
||||
self.filter.timeout = config.get().performance.throttle
|
||||
|
||||
-- Check invalid condition.
|
||||
local ignore = false
|
||||
@ -315,11 +310,13 @@ core.filter = async.throttle(function(self)
|
||||
-- Check fetching sources.
|
||||
local sources = {}
|
||||
for _, s in ipairs(self:get_sources({ source.SourceStatus.FETCHING, source.SourceStatus.COMPLETED })) do
|
||||
if not s.incomplete and SOURCE_TIMEOUT > s:get_fetching_time() then
|
||||
-- Reserve filter call for timeout.
|
||||
self.filter.timeout = SOURCE_TIMEOUT - s:get_fetching_time()
|
||||
-- Reserve filter call for timeout.
|
||||
if not s.incomplete and config.get().performance.fetching_timeout > s:get_fetching_time() then
|
||||
self.filter.timeout = config.get().performance.fetching_timeout - s:get_fetching_time()
|
||||
self:filter()
|
||||
break
|
||||
if #sources == 0 then
|
||||
return
|
||||
end
|
||||
end
|
||||
table.insert(sources, s)
|
||||
end
|
||||
@ -327,20 +324,17 @@ core.filter = async.throttle(function(self)
|
||||
local ctx = self:get_context()
|
||||
|
||||
-- Display completion results.
|
||||
self.view:open(ctx, sources)
|
||||
local did_open = self.view:open(ctx, sources)
|
||||
local fetching = #self:get_sources(function(s)
|
||||
return s.status == source.SourceStatus.FETCHING
|
||||
end)
|
||||
|
||||
-- Check onetime config.
|
||||
if #self:get_sources(function(s)
|
||||
if s.status == source.SourceStatus.FETCHING then
|
||||
return true
|
||||
elseif #s:get_entries(ctx) > 0 then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end) == 0 then
|
||||
if not did_open and fetching == 0 then
|
||||
config.set_onetime({})
|
||||
end
|
||||
end, THROTTLE_TIME)
|
||||
end)
|
||||
core.filter = async.throttle(async_filter, config.get().performance.throttle)
|
||||
|
||||
---Confirm completion.
|
||||
---@param e cmp.Entry
|
||||
@ -348,7 +342,10 @@ end, THROTTLE_TIME)
|
||||
---@param callback function
|
||||
core.confirm = function(self, e, option, callback)
|
||||
if not (e and not e.confirmed) then
|
||||
return callback()
|
||||
if callback then
|
||||
callback()
|
||||
end
|
||||
return
|
||||
end
|
||||
e.confirmed = true
|
||||
|
||||
@ -361,33 +358,39 @@ core.confirm = function(self, e, option, callback)
|
||||
|
||||
feedkeys.call(keymap.indentkeys(), 'n')
|
||||
feedkeys.call('', 'n', function()
|
||||
-- Emulate `<C-y>` behavior to save `.` register.
|
||||
local ctx = context.new()
|
||||
local keys = {}
|
||||
table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset())))
|
||||
table.insert(keys, keymap.backspace(ctx.cursor_before_line:sub(e:get_offset())))
|
||||
table.insert(keys, e:get_word())
|
||||
table.insert(keys, keymap.undobreak())
|
||||
feedkeys.call(table.concat(keys, ''), 'int')
|
||||
feedkeys.call(table.concat(keys, ''), 'in')
|
||||
end)
|
||||
feedkeys.call('', 'n', function()
|
||||
-- Restore the line at the time of request.
|
||||
local ctx = context.new()
|
||||
if api.is_cmdline_mode() then
|
||||
local keys = {}
|
||||
table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset())))
|
||||
table.insert(keys, keymap.backspace(ctx.cursor_before_line:sub(e:get_offset())))
|
||||
table.insert(keys, string.sub(e.context.cursor_before_line, e:get_offset()))
|
||||
feedkeys.call(table.concat(keys, ''), 'in')
|
||||
else
|
||||
vim.api.nvim_buf_set_text(0, ctx.cursor.row - 1, e:get_offset() - 1, ctx.cursor.row - 1, ctx.cursor.col - 1, {
|
||||
string.sub(e.context.cursor_before_line, e:get_offset()),
|
||||
vim.cmd([[silent! undojoin]])
|
||||
-- This logic must be used nvim_buf_set_text.
|
||||
-- If not used, the snippet engine's placeholder wil be broken.
|
||||
vim.api.nvim_buf_set_text(0, e.context.cursor.row - 1, e:get_offset() - 1, ctx.cursor.row - 1, ctx.cursor.col - 1, {
|
||||
e.context.cursor_before_line:sub(e:get_offset()),
|
||||
})
|
||||
vim.api.nvim_win_set_cursor(0, { e.context.cursor.row, e.context.cursor.col - 1 })
|
||||
end
|
||||
end)
|
||||
feedkeys.call('', 'n', function()
|
||||
-- Apply additionalTextEdits.
|
||||
local ctx = context.new()
|
||||
if #(misc.safe(e:get_completion_item().additionalTextEdits) or {}) == 0 then
|
||||
if #(e:get_completion_item().additionalTextEdits or {}) == 0 then
|
||||
e:resolve(function()
|
||||
local new = context.new()
|
||||
local text_edits = misc.safe(e:get_completion_item().additionalTextEdits) or {}
|
||||
local text_edits = e:get_completion_item().additionalTextEdits or {}
|
||||
if #text_edits == 0 then
|
||||
return
|
||||
end
|
||||
@ -407,18 +410,20 @@ core.confirm = function(self, e, option, callback)
|
||||
if has_cursor_line_text_edit then
|
||||
return
|
||||
end
|
||||
vim.lsp.util.apply_text_edits(text_edits, ctx.bufnr, 'utf-16')
|
||||
vim.cmd([[silent! undojoin]])
|
||||
vim.lsp.util.apply_text_edits(text_edits, ctx.bufnr, e.source:get_position_encoding_kind())
|
||||
end)
|
||||
else
|
||||
vim.lsp.util.apply_text_edits(e:get_completion_item().additionalTextEdits, ctx.bufnr, 'utf-16')
|
||||
vim.cmd([[silent! undojoin]])
|
||||
vim.lsp.util.apply_text_edits(e:get_completion_item().additionalTextEdits, ctx.bufnr, e.source:get_position_encoding_kind())
|
||||
end
|
||||
end)
|
||||
feedkeys.call('', 'n', function()
|
||||
local ctx = context.new()
|
||||
local completion_item = misc.copy(e:get_completion_item())
|
||||
if not misc.safe(completion_item.textEdit) then
|
||||
if not completion_item.textEdit then
|
||||
completion_item.textEdit = {}
|
||||
completion_item.textEdit.newText = misc.safe(completion_item.insertText) or completion_item.word or completion_item.label
|
||||
completion_item.textEdit.newText = completion_item.insertText or completion_item.word or completion_item.label
|
||||
end
|
||||
local behavior = option.behavior or config.get().confirmation.default_behavior
|
||||
if behavior == types.cmp.ConfirmBehavior.Replace then
|
||||
@ -427,30 +432,41 @@ core.confirm = function(self, e, option, callback)
|
||||
completion_item.textEdit.range = e:get_insert_range()
|
||||
end
|
||||
|
||||
local diff_before = math.max(0, e.context.cursor.character - completion_item.textEdit.range.start.character)
|
||||
local diff_after = math.max(0, completion_item.textEdit.range['end'].character - e.context.cursor.character)
|
||||
local diff_before = math.max(0, e.context.cursor.col - (completion_item.textEdit.range.start.character + 1))
|
||||
local diff_after = math.max(0, (completion_item.textEdit.range['end'].character + 1) - e.context.cursor.col)
|
||||
local new_text = completion_item.textEdit.newText
|
||||
|
||||
completion_item.textEdit.range.start.line = ctx.cursor.line
|
||||
completion_item.textEdit.range.start.character = (ctx.cursor.col - 1) - diff_before
|
||||
completion_item.textEdit.range['end'].line = ctx.cursor.line
|
||||
completion_item.textEdit.range['end'].character = (ctx.cursor.col - 1) + diff_after
|
||||
if api.is_insert_mode() then
|
||||
if false then
|
||||
--To use complex expansion debug.
|
||||
vim.print({ -- luacheck: ignore
|
||||
item = e:get_completion_item(),
|
||||
diff_before = diff_before,
|
||||
diff_after = diff_after,
|
||||
new_text = new_text,
|
||||
text_edit_new_text = completion_item.textEdit.newText,
|
||||
range_start = completion_item.textEdit.range.start.character,
|
||||
range_end = completion_item.textEdit.range['end'].character,
|
||||
original_range_start = e:get_completion_item().textEdit.range.start.character,
|
||||
original_range_end = e:get_completion_item().textEdit.range['end'].character,
|
||||
cursor_line = ctx.cursor_line,
|
||||
cursor_col0 = ctx.cursor.col - 1,
|
||||
})
|
||||
end
|
||||
local is_snippet = completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet
|
||||
completion_item.textEdit.range.start.line = ctx.cursor.line
|
||||
completion_item.textEdit.range.start.character = ctx.cursor.character - diff_before
|
||||
completion_item.textEdit.range['end'].line = ctx.cursor.line
|
||||
completion_item.textEdit.range['end'].character = ctx.cursor.character + diff_after
|
||||
if is_snippet then
|
||||
completion_item.textEdit.newText = ''
|
||||
end
|
||||
vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, 'utf-16')
|
||||
vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, 'utf-8')
|
||||
|
||||
local texts = vim.split(completion_item.textEdit.newText, '\n')
|
||||
local position = completion_item.textEdit.range.start
|
||||
position.line = position.line + (#texts - 1)
|
||||
if #texts == 1 then
|
||||
position.character = position.character + misc.to_utfindex(texts[1])
|
||||
else
|
||||
position.character = misc.to_utfindex(texts[#texts])
|
||||
end
|
||||
local pos = types.lsp.Position.to_vim(0, position)
|
||||
vim.api.nvim_win_set_cursor(0, { pos.row, pos.col - 1 })
|
||||
vim.api.nvim_win_set_cursor(0, {
|
||||
completion_item.textEdit.range.start.line + #texts,
|
||||
(#texts == 1 and (completion_item.textEdit.range.start.character + #texts[1]) or #texts[#texts]),
|
||||
})
|
||||
if is_snippet then
|
||||
config.get().snippet.expand({
|
||||
body = new_text,
|
||||
@ -459,8 +475,8 @@ core.confirm = function(self, e, option, callback)
|
||||
end
|
||||
else
|
||||
local keys = {}
|
||||
table.insert(keys, string.rep(keymap.t('<BS>'), diff_before))
|
||||
table.insert(keys, string.rep(keymap.t('<Del>'), diff_after))
|
||||
table.insert(keys, keymap.backspace(ctx.cursor_line:sub(completion_item.textEdit.range.start.character + 1, ctx.cursor.col - 1)))
|
||||
table.insert(keys, keymap.delete(ctx.cursor_line:sub(ctx.cursor.col, completion_item.textEdit.range['end'].character)))
|
||||
table.insert(keys, new_text)
|
||||
feedkeys.call(table.concat(keys, ''), 'in')
|
||||
end
|
||||
|
77
bundle/nvim-cmp/lua/cmp/core_spec.lua
vendored
77
bundle/nvim-cmp/lua/cmp/core_spec.lua
vendored
@ -8,9 +8,19 @@ local api = require('cmp.utils.api')
|
||||
|
||||
describe('cmp.core', function()
|
||||
describe('confirm', function()
|
||||
local confirm = function(request, filter, completion_item)
|
||||
---@param request string
|
||||
---@param filter string
|
||||
---@param completion_item lsp.CompletionItem
|
||||
---@param option? { position_encoding_kind: lsp.PositionEncodingKind }
|
||||
---@return table
|
||||
local confirm = function(request, filter, completion_item, option)
|
||||
option = option or {}
|
||||
|
||||
local c = core.new()
|
||||
local s = source.new('spec', {
|
||||
get_position_encoding_kind = function()
|
||||
return option.position_encoding_kind or types.lsp.PositionEncodingKind.UTF16
|
||||
end,
|
||||
complete = function(_, _, callback)
|
||||
callback({ completion_item })
|
||||
end,
|
||||
@ -23,7 +33,7 @@ describe('cmp.core', function()
|
||||
end)
|
||||
end)
|
||||
feedkeys.call(filter, 'n', function()
|
||||
c:confirm(c.sources[s.id].entries[1], {})
|
||||
c:confirm(c.sources[s.id].entries[1], {}, function() end)
|
||||
end)
|
||||
local state = {}
|
||||
feedkeys.call('', 'x', function()
|
||||
@ -80,6 +90,29 @@ describe('cmp.core', function()
|
||||
assert.are.same(state.cursor, { 3, 3 })
|
||||
end)
|
||||
|
||||
it('#1552', function()
|
||||
local state = confirm(keymap.t('ios.'), '', {
|
||||
filterText = 'IsPermission',
|
||||
insertTextFormat = 2,
|
||||
label = 'IsPermission',
|
||||
textEdit = {
|
||||
newText = 'IsPermission($0)',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 3,
|
||||
line = 0,
|
||||
},
|
||||
start = {
|
||||
character = 3,
|
||||
line = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.are.same(state.buffer, { 'os.IsPermission()' })
|
||||
assert.are.same(state.cursor, { 1, 16 })
|
||||
end)
|
||||
|
||||
it('insertText & snippet', function()
|
||||
local state = confirm('iA', 'IU', {
|
||||
label = 'AIUEO',
|
||||
@ -111,6 +144,46 @@ describe('cmp.core', function()
|
||||
assert.are.same(state.buffer, { '***foo', 'bar', 'baz***' })
|
||||
assert.are.same(state.cursor, { 2, 2 })
|
||||
end)
|
||||
|
||||
local char = '🗿'
|
||||
for _, case in ipairs({
|
||||
{
|
||||
encoding = types.lsp.PositionEncodingKind.UTF8,
|
||||
char_size = #char,
|
||||
},
|
||||
{
|
||||
encoding = types.lsp.PositionEncodingKind.UTF16,
|
||||
char_size = select(2, vim.str_utfindex(char)),
|
||||
},
|
||||
{
|
||||
encoding = types.lsp.PositionEncodingKind.UTF32,
|
||||
char_size = select(1, vim.str_utfindex(char)),
|
||||
},
|
||||
}) do
|
||||
it('textEdit & multibyte: ' .. case.encoding, function()
|
||||
local state = confirm(keymap.t('i%s:%s%s:%s<Left><Left><Left>'):format(char, char, char, char), char, {
|
||||
label = char .. char .. char,
|
||||
textEdit = {
|
||||
range = {
|
||||
start = {
|
||||
line = 0,
|
||||
character = case.char_size + #':',
|
||||
},
|
||||
['end'] = {
|
||||
line = 0,
|
||||
character = case.char_size + #':' + case.char_size + case.char_size,
|
||||
},
|
||||
},
|
||||
newText = char .. char .. char .. char .. char,
|
||||
},
|
||||
}, {
|
||||
position_encoding_kind = case.encoding,
|
||||
})
|
||||
vim.print({ state = state, case = case })
|
||||
assert.are.same(state.buffer, { ('%s:%s%s%s%s%s:%s'):format(char, char, char, char, char, char, char) })
|
||||
assert.are.same(state.cursor, { 1, #('%s:%s%s%s%s%s'):format(char, char, char, char, char, char) })
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
describe('cmdline-mode', function()
|
||||
|
272
bundle/nvim-cmp/lua/cmp/entry.lua
vendored
272
bundle/nvim-cmp/lua/cmp/entry.lua
vendored
@ -7,15 +7,15 @@ local types = require('cmp.types')
|
||||
local matcher = require('cmp.matcher')
|
||||
|
||||
---@class cmp.Entry
|
||||
---@field public id number
|
||||
---@field public id integer
|
||||
---@field public cache cmp.Cache
|
||||
---@field public match_cache cmp.Cache
|
||||
---@field public score number
|
||||
---@field public score integer
|
||||
---@field public exact boolean
|
||||
---@field public matches table
|
||||
---@field public context cmp.Context
|
||||
---@field public source cmp.Source
|
||||
---@field public source_offset number
|
||||
---@field public source_offset integer
|
||||
---@field public source_insert_range lsp.Range
|
||||
---@field public source_replace_range lsp.Range
|
||||
---@field public completion_item lsp.CompletionItem
|
||||
@ -29,8 +29,9 @@ local entry = {}
|
||||
---@param ctx cmp.Context
|
||||
---@param source cmp.Source
|
||||
---@param completion_item lsp.CompletionItem
|
||||
---@param item_defaults? lsp.internal.CompletionItemDefaults
|
||||
---@return cmp.Entry
|
||||
entry.new = function(ctx, source, completion_item)
|
||||
entry.new = function(ctx, source, completion_item, item_defaults)
|
||||
local self = setmetatable({}, { __index = entry })
|
||||
self.id = misc.id('entry.new')
|
||||
self.cache = cache.new()
|
||||
@ -43,7 +44,7 @@ entry.new = function(ctx, source, completion_item)
|
||||
self.source_offset = source.request_offset
|
||||
self.source_insert_range = source:get_default_insert_range()
|
||||
self.source_replace_range = source:get_default_replace_range()
|
||||
self.completion_item = completion_item
|
||||
self.completion_item = self:fill_defaults(completion_item, item_defaults)
|
||||
self.resolved_completion_item = nil
|
||||
self.resolved_callbacks = {}
|
||||
self.resolving = false
|
||||
@ -52,20 +53,23 @@ entry.new = function(ctx, source, completion_item)
|
||||
end
|
||||
|
||||
---Make offset value
|
||||
---@return number
|
||||
---@return integer
|
||||
entry.get_offset = function(self)
|
||||
return self.cache:ensure({ 'get_offset', self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_offset', function()
|
||||
local offset = self.source_offset
|
||||
if misc.safe(self:get_completion_item().textEdit) then
|
||||
local range = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range)
|
||||
if self:get_completion_item().textEdit then
|
||||
local range = self:get_insert_range()
|
||||
if range then
|
||||
local c = misc.to_vimindex(self.context.cursor_line, range.start.character)
|
||||
for idx = c, self.source_offset do
|
||||
if not char.is_white(string.byte(self.context.cursor_line, idx)) then
|
||||
offset = idx
|
||||
break
|
||||
offset = self.context.cache:ensure('entry:' .. 'get_offset:' .. tostring(range.start.character), function()
|
||||
local start = math.min(range.start.character + 1, offset)
|
||||
for idx = start, self.source_offset do
|
||||
local byte = string.byte(self.context.cursor_line, idx)
|
||||
if byte == nil or not char.is_white(byte) then
|
||||
return idx
|
||||
end
|
||||
end
|
||||
end
|
||||
return offset
|
||||
end)
|
||||
end
|
||||
else
|
||||
-- NOTE
|
||||
@ -101,14 +105,14 @@ end
|
||||
---NOTE: This method doesn't clear the cache after completionItem/resolve.
|
||||
---@return string
|
||||
entry.get_word = function(self)
|
||||
return self.cache:ensure({ 'get_word' }, function()
|
||||
return self.cache:ensure('get_word', function()
|
||||
--NOTE: This is nvim-cmp specific implementation.
|
||||
if misc.safe(self:get_completion_item().word) then
|
||||
if self:get_completion_item().word then
|
||||
return self:get_completion_item().word
|
||||
end
|
||||
|
||||
local word
|
||||
if misc.safe(self:get_completion_item().textEdit) and not misc.empty(self:get_completion_item().textEdit.newText) then
|
||||
if self:get_completion_item().textEdit and not misc.empty(self:get_completion_item().textEdit.newText) then
|
||||
word = str.trim(self:get_completion_item().textEdit.newText)
|
||||
if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then
|
||||
word = vim.lsp.util.parse_snippet(word)
|
||||
@ -126,20 +130,24 @@ entry.get_word = function(self)
|
||||
word = str.trim(self:get_completion_item().label)
|
||||
end
|
||||
return str.oneline(word)
|
||||
end)
|
||||
end) --[[@as string]]
|
||||
end
|
||||
|
||||
---Get overwrite information
|
||||
---@return number, number
|
||||
---@return integer[]
|
||||
entry.get_overwrite = function(self)
|
||||
return self.cache:ensure({ 'get_overwrite', self.resolved_completion_item and 1 or 0 }, function()
|
||||
if misc.safe(self:get_completion_item().textEdit) then
|
||||
local r = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range)
|
||||
local s = misc.to_vimindex(self.context.cursor_line, r.start.character)
|
||||
local e = misc.to_vimindex(self.context.cursor_line, r['end'].character)
|
||||
local before = self.context.cursor.col - s
|
||||
local after = e - self.context.cursor.col
|
||||
return { before, after }
|
||||
return self.cache:ensure('get_overwrite', function()
|
||||
if self:get_completion_item().textEdit then
|
||||
local range = self:get_insert_range()
|
||||
if range then
|
||||
return self.context.cache:ensure('entry:' .. 'get_overwrite:' .. tostring(range.start.character) .. ':' .. tostring(range['end'].character), function()
|
||||
local vim_start = range.start.character + 1
|
||||
local vim_end = range['end'].character + 1
|
||||
local before = self.context.cursor.col - vim_start
|
||||
local after = vim_end - self.context.cursor.col
|
||||
return { before, after }
|
||||
end)
|
||||
end
|
||||
end
|
||||
return { 0, 0 }
|
||||
end)
|
||||
@ -148,9 +156,9 @@ end
|
||||
---Create filter text
|
||||
---@return string
|
||||
entry.get_filter_text = function(self)
|
||||
return self.cache:ensure({ 'get_filter_text', self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_filter_text', function()
|
||||
local word
|
||||
if misc.safe(self:get_completion_item().filterText) then
|
||||
if self:get_completion_item().filterText then
|
||||
word = self:get_completion_item().filterText
|
||||
else
|
||||
word = str.trim(self:get_completion_item().label)
|
||||
@ -162,14 +170,14 @@ end
|
||||
---Get LSP's insert text
|
||||
---@return string
|
||||
entry.get_insert_text = function(self)
|
||||
return self.cache:ensure({ 'get_insert_text', self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_insert_text', function()
|
||||
local word
|
||||
if misc.safe(self:get_completion_item().textEdit) then
|
||||
if self:get_completion_item().textEdit then
|
||||
word = str.trim(self:get_completion_item().textEdit.newText)
|
||||
if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then
|
||||
word = str.remove_suffix(str.remove_suffix(word, '$0'), '${0}')
|
||||
end
|
||||
elseif misc.safe(self:get_completion_item().insertText) then
|
||||
elseif self:get_completion_item().insertText then
|
||||
word = str.trim(self:get_completion_item().insertText)
|
||||
if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then
|
||||
word = str.remove_suffix(str.remove_suffix(word, '$0'), '${0}')
|
||||
@ -188,12 +196,12 @@ entry.is_deprecated = function(self)
|
||||
end
|
||||
|
||||
---Return view information.
|
||||
---@param suggest_offset number
|
||||
---@param entries_buf number The buffer this entry will be rendered into.
|
||||
---@return { abbr: { text: string, bytes: number, width: number, hl_group: string }, kind: { text: string, bytes: number, width: number, hl_group: string }, menu: { text: string, bytes: number, width: number, hl_group: string } }
|
||||
---@param suggest_offset integer
|
||||
---@param entries_buf integer The buffer this entry will be rendered into.
|
||||
---@return { abbr: { text: string, bytes: integer, width: integer, hl_group: string }, kind: { text: string, bytes: integer, width: integer, hl_group: string }, menu: { text: string, bytes: integer, width: integer, hl_group: string } }
|
||||
entry.get_view = function(self, suggest_offset, entries_buf)
|
||||
local item = self:get_vim_item(suggest_offset)
|
||||
return self.cache:ensure({ 'get_view', self.resolved_completion_item and 1 or 0, entries_buf }, function()
|
||||
return self.cache:ensure('get_view:' .. tostring(entries_buf), function()
|
||||
local view = {}
|
||||
-- The result of vim.fn.strdisplaywidth depends on which buffer it was
|
||||
-- called in because it reads the values of the option 'tabstop' when
|
||||
@ -221,24 +229,25 @@ entry.get_view = function(self, suggest_offset, entries_buf)
|
||||
end
|
||||
|
||||
---Make vim.CompletedItem
|
||||
---@param suggest_offset number
|
||||
---@param suggest_offset integer
|
||||
---@return vim.CompletedItem
|
||||
entry.get_vim_item = function(self, suggest_offset)
|
||||
return self.cache:ensure({ 'get_vim_item', suggest_offset, self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_vim_item:' .. tostring(suggest_offset), function()
|
||||
local completion_item = self:get_completion_item()
|
||||
local word = self:get_word()
|
||||
local abbr = str.oneline(completion_item.label)
|
||||
|
||||
-- ~ indicator
|
||||
local is_snippet = false
|
||||
if #(misc.safe(completion_item.additionalTextEdits) or {}) > 0 then
|
||||
is_snippet = true
|
||||
local is_expandable = false
|
||||
local expandable_indicator = config.get().formatting.expandable_indicator
|
||||
if #(completion_item.additionalTextEdits or {}) > 0 then
|
||||
is_expandable = true
|
||||
elseif completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then
|
||||
is_snippet = self:get_insert_text() ~= word
|
||||
is_expandable = self:get_insert_text() ~= word
|
||||
elseif completion_item.kind == types.lsp.CompletionItemKind.Snippet then
|
||||
is_snippet = true
|
||||
is_expandable = true
|
||||
end
|
||||
if is_snippet then
|
||||
if expandable_indicator and is_expandable then
|
||||
abbr = abbr .. '~'
|
||||
end
|
||||
|
||||
@ -249,19 +258,19 @@ entry.get_vim_item = function(self, suggest_offset)
|
||||
|
||||
-- labelDetails.
|
||||
local menu = nil
|
||||
if misc.safe(completion_item.labelDetails) then
|
||||
if completion_item.labelDetails then
|
||||
menu = ''
|
||||
if misc.safe(completion_item.labelDetails.detail) then
|
||||
if completion_item.labelDetails.detail then
|
||||
menu = menu .. completion_item.labelDetails.detail
|
||||
end
|
||||
if misc.safe(completion_item.labelDetails.description) then
|
||||
if completion_item.labelDetails.description then
|
||||
menu = menu .. completion_item.labelDetails.description
|
||||
end
|
||||
end
|
||||
|
||||
-- remove duplicated string.
|
||||
if self:get_offset() ~= self.context.cursor.col then
|
||||
for i = 1, #word - 1 do
|
||||
for i = 1, #word do
|
||||
if str.has_prefix(self.context.cursor_after_line, string.sub(word, i, #word)) then
|
||||
word = string.sub(word, 1, i - 1)
|
||||
break
|
||||
@ -269,10 +278,13 @@ entry.get_vim_item = function(self, suggest_offset)
|
||||
end
|
||||
end
|
||||
|
||||
local cmp_opts = self:get_completion_item().cmp or {}
|
||||
|
||||
local vim_item = {
|
||||
word = word,
|
||||
abbr = abbr,
|
||||
kind = types.lsp.CompletionItemKind[self:get_kind()] or types.lsp.CompletionItemKind[1],
|
||||
kind = cmp_opts.kind_text or types.lsp.CompletionItemKind[self:get_kind()] or types.lsp.CompletionItemKind[1],
|
||||
kind_hl_group = cmp_opts.kind_hl_group,
|
||||
menu = menu,
|
||||
dup = self:get_completion_item().dup or 1,
|
||||
}
|
||||
@ -293,24 +305,25 @@ end
|
||||
---Get commit characters
|
||||
---@return string[]
|
||||
entry.get_commit_characters = function(self)
|
||||
return misc.safe(self:get_completion_item().commitCharacters) or {}
|
||||
return self:get_completion_item().commitCharacters or {}
|
||||
end
|
||||
|
||||
---Return insert range
|
||||
---@return lsp.Range|nil
|
||||
entry.get_insert_range = function(self)
|
||||
local insert_range
|
||||
if misc.safe(self:get_completion_item().textEdit) then
|
||||
if misc.safe(self:get_completion_item().textEdit.insert) then
|
||||
if self:get_completion_item().textEdit then
|
||||
if self:get_completion_item().textEdit.insert then
|
||||
insert_range = self:get_completion_item().textEdit.insert
|
||||
else
|
||||
insert_range = self:get_completion_item().textEdit.range
|
||||
insert_range = self:get_completion_item().textEdit.range --[[@as lsp.Range]]
|
||||
end
|
||||
insert_range = self:convert_range_encoding(insert_range)
|
||||
else
|
||||
insert_range = {
|
||||
start = {
|
||||
line = self.context.cursor.row - 1,
|
||||
character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_insert_range.start.character),
|
||||
character = self:get_offset() - 1,
|
||||
},
|
||||
['end'] = self.source_insert_range['end'],
|
||||
}
|
||||
@ -321,15 +334,22 @@ end
|
||||
---Return replace range
|
||||
---@return lsp.Range|nil
|
||||
entry.get_replace_range = function(self)
|
||||
return self.cache:ensure({ 'get_replace_range', self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_replace_range', function()
|
||||
local replace_range
|
||||
if misc.safe(self:get_completion_item().textEdit) and misc.safe(self:get_completion_item().textEdit.replace) then
|
||||
replace_range = self:get_completion_item().textEdit.replace
|
||||
else
|
||||
if self:get_completion_item().textEdit then
|
||||
if self:get_completion_item().textEdit.replace then
|
||||
replace_range = self:get_completion_item().textEdit.replace
|
||||
else
|
||||
replace_range = self:get_completion_item().textEdit.range --[[@as lsp.Range]]
|
||||
end
|
||||
replace_range = self:convert_range_encoding(replace_range)
|
||||
end
|
||||
|
||||
if not replace_range or ((self.context.cursor.col - 1) == replace_range['end'].character) then
|
||||
replace_range = {
|
||||
start = {
|
||||
line = self.source_replace_range.start.line,
|
||||
character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_replace_range.start.character),
|
||||
character = self:get_offset() - 1,
|
||||
},
|
||||
['end'] = self.source_replace_range['end'],
|
||||
}
|
||||
@ -341,17 +361,12 @@ end
|
||||
---Match line.
|
||||
---@param input string
|
||||
---@param matching_config cmp.MatchingConfig
|
||||
---@return { score: number, matches: table[] }
|
||||
---@return { score: integer, matches: table[] }
|
||||
entry.match = function(self, input, matching_config)
|
||||
return self.match_cache:ensure({
|
||||
input,
|
||||
self.resolved_completion_item and 1 or 0,
|
||||
matching_config.disallow_fuzzy_matching and 1 or 0,
|
||||
matching_config.disallow_partial_matching and 1 or 0,
|
||||
matching_config.disallow_prefix_unmatching and 1 or 0,
|
||||
}, function()
|
||||
return self.match_cache:ensure(input .. ':' .. (self.resolved_completion_item and '1' or '0' .. ':') .. (matching_config.disallow_fuzzy_matching and '1' or '0') .. ':' .. (matching_config.disallow_partial_fuzzy_matching and '1' or '0') .. ':' .. (matching_config.disallow_partial_matching and '1' or '0') .. ':' .. (matching_config.disallow_prefix_unmatching and '1' or '0'), function()
|
||||
local option = {
|
||||
disallow_fuzzy_matching = matching_config.disallow_fuzzy_matching,
|
||||
disallow_partial_fuzzy_matching = matching_config.disallow_partial_fuzzy_matching,
|
||||
disallow_partial_matching = matching_config.disallow_partial_matching,
|
||||
disallow_prefix_unmatching = matching_config.disallow_prefix_unmatching,
|
||||
synonyms = {
|
||||
@ -360,27 +375,42 @@ entry.match = function(self, input, matching_config)
|
||||
},
|
||||
}
|
||||
|
||||
local score, matches, _
|
||||
score, matches = matcher.match(input, self:get_filter_text(), option)
|
||||
local score, matches, filter_text, _
|
||||
local checked = {} ---@type table<string, boolean>
|
||||
|
||||
filter_text = self:get_filter_text()
|
||||
checked[filter_text] = true
|
||||
score, matches = matcher.match(input, filter_text, option)
|
||||
|
||||
-- Support the language server that doesn't respect VSCode's behaviors.
|
||||
local prefix = ''
|
||||
if score == 0 then
|
||||
if misc.safe(self:get_completion_item().textEdit) and not misc.empty(self:get_completion_item().textEdit.newText) then
|
||||
if self:get_completion_item().textEdit and not misc.empty(self:get_completion_item().textEdit.newText) then
|
||||
local diff = self.source_offset - self:get_offset()
|
||||
if diff > 0 then
|
||||
local prefix = string.sub(self.context.cursor_line, self:get_offset(), self:get_offset() + diff)
|
||||
local accept = false
|
||||
prefix = string.sub(self.context.cursor_line, self:get_offset(), self:get_offset() + diff)
|
||||
local accept = nil
|
||||
accept = accept or string.match(prefix, '^[^%a]+$')
|
||||
accept = accept or string.find(self:get_completion_item().textEdit.newText, prefix, 1, true)
|
||||
if accept then
|
||||
score, matches = matcher.match(input, prefix .. self:get_filter_text(), option)
|
||||
filter_text = prefix .. self:get_filter_text()
|
||||
if not checked[filter_text] then
|
||||
checked[filter_text] = true
|
||||
score, matches = matcher.match(input, filter_text, option)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self:get_filter_text() ~= self:get_completion_item().label then
|
||||
_, matches = matcher.match(input, self:get_completion_item().label, { self:get_word() })
|
||||
-- Fix highlight if filterText is not the same to vim_item.abbr.
|
||||
if score > 0 then
|
||||
local vim_item = self:get_vim_item(self.source_offset)
|
||||
filter_text = vim_item.abbr or vim_item.word
|
||||
if not checked[filter_text] then
|
||||
local diff = self.source_offset - self:get_offset()
|
||||
_, matches = matcher.match(input:sub(1 + diff), filter_text, option)
|
||||
end
|
||||
end
|
||||
|
||||
return { score = score, matches = matches }
|
||||
@ -390,7 +420,7 @@ end
|
||||
---Get resolved completion item if possible.
|
||||
---@return lsp.CompletionItem
|
||||
entry.get_completion_item = function(self)
|
||||
return self.cache:ensure({ 'get_completion_item', self.resolved_completion_item and 1 or 0 }, function()
|
||||
return self.cache:ensure('get_completion_item', function()
|
||||
if self.resolved_completion_item then
|
||||
local completion_item = misc.copy(self.completion_item)
|
||||
for k, v in pairs(self.resolved_completion_item) do
|
||||
@ -410,7 +440,7 @@ entry.get_documentation = function(self)
|
||||
local documents = {}
|
||||
|
||||
-- detail
|
||||
if misc.safe(item.detail) and item.detail ~= '' then
|
||||
if item.detail and item.detail ~= '' then
|
||||
local ft = self.context.filetype
|
||||
local dot_index = string.find(ft, '%.')
|
||||
if dot_index ~= nil then
|
||||
@ -422,13 +452,23 @@ entry.get_documentation = function(self)
|
||||
})
|
||||
end
|
||||
|
||||
if type(item.documentation) == 'string' and item.documentation ~= '' then
|
||||
table.insert(documents, {
|
||||
kind = types.lsp.MarkupKind.PlainText,
|
||||
value = str.trim(item.documentation),
|
||||
})
|
||||
elseif type(item.documentation) == 'table' and item.documentation.value ~= '' then
|
||||
table.insert(documents, item.documentation)
|
||||
local documentation = item.documentation
|
||||
if type(documentation) == 'string' and documentation ~= '' then
|
||||
local value = str.trim(documentation)
|
||||
if value ~= '' then
|
||||
table.insert(documents, {
|
||||
kind = types.lsp.MarkupKind.PlainText,
|
||||
value = value,
|
||||
})
|
||||
end
|
||||
elseif type(documentation) == 'table' and not misc.empty(documentation.value) then
|
||||
local value = str.trim(documentation.value)
|
||||
if value ~= '' then
|
||||
table.insert(documents, {
|
||||
kind = documentation.kind,
|
||||
value = value,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return vim.lsp.util.convert_input_to_markdown_lines(documents)
|
||||
@ -437,7 +477,7 @@ end
|
||||
---Get completion item kind
|
||||
---@return lsp.CompletionItemKind
|
||||
entry.get_kind = function(self)
|
||||
return misc.safe(self:get_completion_item().kind) or types.lsp.CompletionItemKind.Text
|
||||
return self:get_completion_item().kind or types.lsp.CompletionItemKind.Text
|
||||
end
|
||||
|
||||
---Execute completion item's command.
|
||||
@ -457,7 +497,12 @@ entry.resolve = function(self, callback)
|
||||
if not self.resolving then
|
||||
self.resolving = true
|
||||
self.source:resolve(self.completion_item, function(completion_item)
|
||||
self.resolved_completion_item = misc.safe(completion_item) or self.completion_item
|
||||
self.resolving = false
|
||||
if not completion_item then
|
||||
return
|
||||
end
|
||||
self.resolved_completion_item = completion_item or self.completion_item
|
||||
self.cache:clear()
|
||||
for _, c in ipairs(self.resolved_callbacks) do
|
||||
c()
|
||||
end
|
||||
@ -465,4 +510,57 @@ entry.resolve = function(self, callback)
|
||||
end
|
||||
end
|
||||
|
||||
---@param completion_item lsp.CompletionItem
|
||||
---@param defaults? lsp.internal.CompletionItemDefaults
|
||||
---@return lsp.CompletionItem
|
||||
entry.fill_defaults = function(_, completion_item, defaults)
|
||||
defaults = defaults or {}
|
||||
|
||||
if defaults.data then
|
||||
completion_item.data = completion_item.data or defaults.data
|
||||
end
|
||||
|
||||
if defaults.commitCharacters then
|
||||
completion_item.commitCharacters = completion_item.commitCharacters or defaults.commitCharacters
|
||||
end
|
||||
|
||||
if defaults.insertTextFormat then
|
||||
completion_item.insertTextFormat = completion_item.insertTextFormat or defaults.insertTextFormat
|
||||
end
|
||||
|
||||
if defaults.insertTextMode then
|
||||
completion_item.insertTextMode = completion_item.insertTextMode or defaults.insertTextMode
|
||||
end
|
||||
|
||||
if defaults.editRange then
|
||||
if not completion_item.textEdit then
|
||||
if defaults.editRange.insert then
|
||||
completion_item.textEdit = {
|
||||
insert = defaults.editRange.insert,
|
||||
replace = defaults.editRange.replace,
|
||||
newText = completion_item.textEditText or completion_item.label,
|
||||
}
|
||||
else
|
||||
completion_item.textEdit = {
|
||||
range = defaults.editRange, --[[@as lsp.Range]]
|
||||
newText = completion_item.textEditText or completion_item.label,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return completion_item
|
||||
end
|
||||
|
||||
---Convert the oneline range encoding.
|
||||
entry.convert_range_encoding = function(self, range)
|
||||
local from_encoding = self.source:get_position_encoding_kind()
|
||||
return self.context.cache:ensure('entry.convert_range_encoding:' .. range.start.character .. ':' .. range['end'].character .. ':' .. from_encoding, function()
|
||||
return {
|
||||
start = types.lsp.Position.to_utf8(self.context.cursor_line, range.start, from_encoding),
|
||||
['end'] = types.lsp.Position.to_utf8(self.context.cursor_line, range['end'], from_encoding),
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
return entry
|
||||
|
98
bundle/nvim-cmp/lua/cmp/entry_spec.lua
vendored
98
bundle/nvim-cmp/lua/cmp/entry_spec.lua
vendored
@ -1,6 +1,4 @@
|
||||
local spec = require('cmp.utils.spec')
|
||||
local source = require('cmp.source')
|
||||
local async = require('cmp.utils.async')
|
||||
|
||||
local entry = require('cmp.entry')
|
||||
|
||||
@ -290,41 +288,6 @@ describe('entry', function()
|
||||
assert.are.equal(e:get_vim_item(e:get_offset()).word, 'string')
|
||||
end)
|
||||
|
||||
it('[ansiblels] 1', function()
|
||||
local item = {
|
||||
detail = 'ansible.builtin',
|
||||
filterText = 'blockinfile ansible.builtin.blockinfile',
|
||||
kind = 7,
|
||||
label = 'blockinfile',
|
||||
sortText = '2_blockinfile',
|
||||
textEdit = {
|
||||
newText = '',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 7,
|
||||
line = 15,
|
||||
},
|
||||
start = {
|
||||
character = 6,
|
||||
line = 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
local s = source.new('dummy', {
|
||||
resolve = function(_, _, callback)
|
||||
item.textEdit.newText = 'modified'
|
||||
callback(item)
|
||||
end,
|
||||
})
|
||||
local e = entry.new(spec.state('', 1, 1).manual(), s, item)
|
||||
assert.are.equal(e:get_vim_item(e:get_offset()).word, 'blockinfile')
|
||||
async.sync(function(done)
|
||||
e:resolve(done)
|
||||
end, 100)
|
||||
assert.are.equal(e:get_vim_item(e:get_offset()).word, 'blockinfile')
|
||||
end)
|
||||
|
||||
it('[#47] word should not contain \\n character', function()
|
||||
local state = spec.state('', 1, 1)
|
||||
|
||||
@ -339,4 +302,65 @@ describe('entry', function()
|
||||
assert.are.equal(e:get_vim_item(e:get_offset()).word, '__init__(self) -> None:')
|
||||
assert.are.equal(e:get_filter_text(), '__init__')
|
||||
end)
|
||||
|
||||
-- I can't understand this test case...
|
||||
-- it('[#1533] keyword pattern that include whitespace', function()
|
||||
-- local state = spec.state(' ', 1, 2)
|
||||
-- local state_source = state.source()
|
||||
|
||||
-- state_source.get_keyword_pattern = function(_)
|
||||
-- return '.'
|
||||
-- end
|
||||
|
||||
-- state.input(' ')
|
||||
-- local e = entry.new(state.manual(), state_source, {
|
||||
-- filterText = "constructor() {\n ... st = 'test';\n ",
|
||||
-- kind = 1,
|
||||
-- label = "constructor() {\n ... st = 'test';\n }",
|
||||
-- textEdit = {
|
||||
-- newText = "constructor() {\n this.test = 'test';\n }",
|
||||
-- range = {
|
||||
-- ['end'] = {
|
||||
-- character = 2,
|
||||
-- line = 2,
|
||||
-- },
|
||||
-- start = {
|
||||
-- character = 0,
|
||||
-- line = 2,
|
||||
-- },
|
||||
-- },
|
||||
-- },
|
||||
-- })
|
||||
-- assert.are.equal(e:get_offset(), 2)
|
||||
-- assert.are.equal(e:get_vim_item(e:get_offset()).word, 'constructor() {')
|
||||
-- end)
|
||||
|
||||
it('[#1533] clang regression test', function()
|
||||
local state = spec.state('jsonReader', 3, 11)
|
||||
local state_source = state.source()
|
||||
|
||||
state.input('.')
|
||||
local e = entry.new(state.manual(), state_source, {
|
||||
filterText = 'getPath()',
|
||||
kind = 1,
|
||||
label = 'getPath()',
|
||||
textEdit = {
|
||||
newText = 'getPath()',
|
||||
range = {
|
||||
['end'] = {
|
||||
character = 11,
|
||||
col = 12,
|
||||
line = 2,
|
||||
row = 3,
|
||||
},
|
||||
start = {
|
||||
character = 11,
|
||||
line = 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.are.equal(e:get_offset(), 12)
|
||||
assert.are.equal(e:get_vim_item(e:get_offset()).word, 'getPath()')
|
||||
end)
|
||||
end)
|
||||
|
109
bundle/nvim-cmp/lua/cmp/init.lua
vendored
109
bundle/nvim-cmp/lua/cmp/init.lua
vendored
@ -5,6 +5,7 @@ local feedkeys = require('cmp.utils.feedkeys')
|
||||
local autocmd = require('cmp.utils.autocmd')
|
||||
local keymap = require('cmp.utils.keymap')
|
||||
local misc = require('cmp.utils.misc')
|
||||
local async = require('cmp.utils.async')
|
||||
|
||||
local cmp = {}
|
||||
|
||||
@ -29,6 +30,7 @@ cmp.config.disable = misc.none
|
||||
cmp.config.compare = require('cmp.config.compare')
|
||||
cmp.config.sources = require('cmp.config.sources')
|
||||
cmp.config.mapping = require('cmp.config.mapping')
|
||||
cmp.config.window = require('cmp.config.window')
|
||||
|
||||
---Sync asynchronous process.
|
||||
cmp.sync = function(callback)
|
||||
@ -48,7 +50,7 @@ end
|
||||
---Register completion sources
|
||||
---@param name string
|
||||
---@param s cmp.Source
|
||||
---@return number
|
||||
---@return integer
|
||||
cmp.register_source = function(name, s)
|
||||
local src = source.new(name, s)
|
||||
cmp.core:register_source(src)
|
||||
@ -56,7 +58,7 @@ cmp.register_source = function(name, s)
|
||||
end
|
||||
|
||||
---Unregister completion source
|
||||
---@param id number
|
||||
---@param id integer
|
||||
cmp.unregister_source = function(id)
|
||||
cmp.core:unregister_source(id)
|
||||
end
|
||||
@ -106,7 +108,6 @@ cmp.close = cmp.sync(function()
|
||||
if cmp.core.view:visible() then
|
||||
local release = cmp.core:suspend()
|
||||
cmp.core.view:close()
|
||||
cmp.core:reset()
|
||||
vim.schedule(release)
|
||||
return true
|
||||
else
|
||||
@ -129,6 +130,8 @@ end)
|
||||
---Select next item if possible
|
||||
cmp.select_next_item = cmp.sync(function(option)
|
||||
option = option or {}
|
||||
option.behavior = option.behavior or cmp.SelectBehavior.Insert
|
||||
option.count = option.count or 1
|
||||
|
||||
if cmp.core.view:visible() then
|
||||
local release = cmp.core:suspend()
|
||||
@ -136,11 +139,10 @@ cmp.select_next_item = cmp.sync(function(option)
|
||||
vim.schedule(release)
|
||||
return true
|
||||
elseif vim.fn.pumvisible() == 1 then
|
||||
-- Special handling for native pum. Required to facilitate key mapping processing.
|
||||
if (option.behavior or cmp.SelectBehavior.Insert) == cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t('<C-n>'), 'in')
|
||||
if option.behavior == cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t(string.rep('<C-n>', option.count)), 'in')
|
||||
else
|
||||
feedkeys.call(keymap.t('<Down>'), 'in')
|
||||
feedkeys.call(keymap.t(string.rep('<Down>', option.count)), 'in')
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -150,6 +152,8 @@ end)
|
||||
---Select prev item if possible
|
||||
cmp.select_prev_item = cmp.sync(function(option)
|
||||
option = option or {}
|
||||
option.behavior = option.behavior or cmp.SelectBehavior.Insert
|
||||
option.count = option.count or 1
|
||||
|
||||
if cmp.core.view:visible() then
|
||||
local release = cmp.core:suspend()
|
||||
@ -157,11 +161,10 @@ cmp.select_prev_item = cmp.sync(function(option)
|
||||
vim.schedule(release)
|
||||
return true
|
||||
elseif vim.fn.pumvisible() == 1 then
|
||||
-- Special handling for native pum. Required to facilitate key mapping processing.
|
||||
if (option.behavior or cmp.SelectBehavior.Insert) == cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t('<C-p>'), 'in')
|
||||
if option.behavior == cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t(string.rep('<C-p>', option.count)), 'in')
|
||||
else
|
||||
feedkeys.call(keymap.t('<Up>'), 'in')
|
||||
feedkeys.call(keymap.t(string.rep('<Up>', option.count)), 'in')
|
||||
end
|
||||
return true
|
||||
end
|
||||
@ -170,7 +173,7 @@ end)
|
||||
|
||||
---Scrolling documentation window if possible
|
||||
cmp.scroll_docs = cmp.sync(function(delta)
|
||||
if cmp.core.view:visible() then
|
||||
if cmp.core.view.docs_view:visible() then
|
||||
cmp.core.view:scroll_docs(delta)
|
||||
return true
|
||||
else
|
||||
@ -181,25 +184,35 @@ end)
|
||||
---Confirm completion
|
||||
cmp.confirm = cmp.sync(function(option, callback)
|
||||
option = option or {}
|
||||
option.select = option.select or false
|
||||
option.behavior = option.behavior or cmp.get_config().confirmation.default_behavior or cmp.ConfirmBehavior.Insert
|
||||
callback = callback or function() end
|
||||
|
||||
local e = cmp.core.view:get_selected_entry() or (option.select and cmp.core.view:get_first_entry() or nil)
|
||||
if e then
|
||||
cmp.core:confirm(e, {
|
||||
behavior = option.behavior,
|
||||
}, function()
|
||||
callback()
|
||||
cmp.core:complete(cmp.core:get_context({ reason = cmp.ContextReason.TriggerOnly }))
|
||||
end)
|
||||
return true
|
||||
else
|
||||
-- Special handling for native puma. Required to facilitate key mapping processing.
|
||||
if vim.fn.complete_info({ 'selected' }).selected ~= -1 then
|
||||
feedkeys.call(keymap.t('<C-y>'), 'in')
|
||||
if cmp.core.view:visible() then
|
||||
local e = cmp.core.view:get_selected_entry()
|
||||
if not e and option.select then
|
||||
e = cmp.core.view:get_first_entry()
|
||||
end
|
||||
if e then
|
||||
cmp.core:confirm(e, {
|
||||
behavior = option.behavior,
|
||||
}, function()
|
||||
callback()
|
||||
cmp.core:complete(cmp.core:get_context({ reason = cmp.ContextReason.TriggerOnly }))
|
||||
end)
|
||||
return true
|
||||
end
|
||||
elseif vim.fn.pumvisible() == 1 then
|
||||
local index = vim.fn.complete_info({ 'selected' }).selected
|
||||
if index == -1 and option.select then
|
||||
index = 0
|
||||
end
|
||||
if index ~= -1 then
|
||||
vim.api.nvim_select_popupmenu_item(index, true, true, {})
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
return false
|
||||
end)
|
||||
|
||||
---Show status
|
||||
@ -282,39 +295,28 @@ cmp.setup = setmetatable({
|
||||
end,
|
||||
})
|
||||
|
||||
autocmd.subscribe('InsertEnter', function()
|
||||
feedkeys.call('', 'i', function()
|
||||
if config.enabled() then
|
||||
cmp.core:prepare()
|
||||
cmp.core:on_change('InsertEnter')
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
autocmd.subscribe('InsertLeave', function()
|
||||
cmp.core:reset()
|
||||
cmp.core.view:close()
|
||||
end)
|
||||
|
||||
autocmd.subscribe('CmdlineEnter', function()
|
||||
-- In InsertEnter autocmd, vim will detects mode=normal unexpectedly.
|
||||
local on_insert_enter = function()
|
||||
if config.enabled() then
|
||||
cmp.config.compare.scopes:update()
|
||||
cmp.config.compare.locality:update()
|
||||
cmp.core:prepare()
|
||||
cmp.core:on_change('InsertEnter')
|
||||
end
|
||||
end)
|
||||
end
|
||||
autocmd.subscribe({ 'CmdlineEnter' }, async.debounce_next_tick(on_insert_enter))
|
||||
autocmd.subscribe({ 'InsertEnter' }, async.debounce_next_tick_by_keymap(on_insert_enter))
|
||||
|
||||
autocmd.subscribe('CmdlineLeave', function()
|
||||
cmp.core:reset()
|
||||
cmp.core.view:close()
|
||||
end)
|
||||
|
||||
autocmd.subscribe('TextChanged', function()
|
||||
-- async.throttle is needed for performance. The mapping `:<C-u>...<CR>` will fire `CmdlineChanged` for each character.
|
||||
local on_text_changed = function()
|
||||
if config.enabled() then
|
||||
cmp.core:on_change('TextChanged')
|
||||
end
|
||||
end)
|
||||
end
|
||||
autocmd.subscribe({ 'TextChangedI', 'TextChangedP' }, on_text_changed)
|
||||
autocmd.subscribe('CmdlineChanged', async.debounce_next_tick(on_text_changed))
|
||||
|
||||
autocmd.subscribe('CursorMoved', function()
|
||||
autocmd.subscribe('CursorMovedI', function()
|
||||
if config.enabled() then
|
||||
cmp.core:on_moved()
|
||||
else
|
||||
@ -323,9 +325,10 @@ autocmd.subscribe('CursorMoved', function()
|
||||
end
|
||||
end)
|
||||
|
||||
autocmd.subscribe('InsertEnter', function()
|
||||
cmp.config.compare.scopes:update()
|
||||
cmp.config.compare.locality:update()
|
||||
-- If make this asynchronous, the completion menu will not close when the command output is displayed.
|
||||
autocmd.subscribe({ 'InsertLeave', 'CmdlineLeave' }, function()
|
||||
cmp.core:reset()
|
||||
cmp.core.view:close()
|
||||
end)
|
||||
|
||||
cmp.event:on('complete_done', function(evt)
|
||||
|
61
bundle/nvim-cmp/lua/cmp/matcher.lua
vendored
61
bundle/nvim-cmp/lua/cmp/matcher.lua
vendored
@ -66,14 +66,20 @@ end
|
||||
--
|
||||
-- `candlesingle` -> candle#accept#single
|
||||
-- ^^^^^^~~~~~~ ^^^^^^ ~~~~~~
|
||||
--
|
||||
-- * The `accept`'s `a` should not match to `candle`'s `a`
|
||||
--
|
||||
-- 7. Avoid false positive matching
|
||||
--
|
||||
-- `,` -> print,
|
||||
-- ~
|
||||
-- * Typically, the middle match with symbol characters only is false positive. should be ignored.
|
||||
--
|
||||
--
|
||||
---Match entry
|
||||
---@param input string
|
||||
---@param word string
|
||||
---@param option { synonyms: string[], disallow_fuzzy_matching: boolean, disallow_partial_matching: boolean, disallow_prefix_unmatching: boolean }
|
||||
---@return number
|
||||
---@param option { synonyms: string[], disallow_fullfuzzy_matching: boolean, disallow_fuzzy_matching: boolean, disallow_partial_fuzzy_matching: boolean, disallow_partial_matching: boolean, disallow_prefix_unmatching: boolean }
|
||||
---@return integer
|
||||
matcher.match = function(input, word, option)
|
||||
option = option or {}
|
||||
|
||||
@ -100,12 +106,14 @@ matcher.match = function(input, word, option)
|
||||
local input_end_index = 1
|
||||
local word_index = 1
|
||||
local word_bound_index = 1
|
||||
local no_symbol_match = false
|
||||
while input_end_index <= #input and word_index <= #word do
|
||||
local m = matcher.find_match_region(input, input_start_index, input_end_index, word, word_index)
|
||||
if m and input_end_index <= m.input_match_end then
|
||||
m.index = word_bound_index
|
||||
input_start_index = m.input_match_start + 1
|
||||
input_end_index = m.input_match_end + 1
|
||||
no_symbol_match = no_symbol_match or m.no_symbol_match
|
||||
word_index = char.get_next_semantic_index(word, m.word_match_end)
|
||||
table.insert(matches, m)
|
||||
else
|
||||
@ -120,6 +128,11 @@ matcher.match = function(input, word, option)
|
||||
end
|
||||
|
||||
if #matches == 0 then
|
||||
if not option.disallow_fuzzy_matching and not option.disallow_prefix_unmatching and not option.disallow_partial_fuzzy_matching then
|
||||
if matcher.fuzzy(input, word, matches, option) then
|
||||
return 1, matches
|
||||
end
|
||||
end
|
||||
return 0, {}
|
||||
end
|
||||
|
||||
@ -146,6 +159,10 @@ matcher.match = function(input, word, option)
|
||||
end
|
||||
end
|
||||
|
||||
if no_symbol_match and not prefix then
|
||||
return 0, {}
|
||||
end
|
||||
|
||||
-- Compute prefix match score
|
||||
local score = prefix and matcher.PREFIX_FACTOR or 0
|
||||
local offset = prefix and matches[1].index - 1 or 0
|
||||
@ -167,8 +184,10 @@ matcher.match = function(input, word, option)
|
||||
-- Check remaining input as fuzzy
|
||||
if matches[#matches].input_match_end < #input then
|
||||
if not option.disallow_fuzzy_matching then
|
||||
if prefix and matcher.fuzzy(input, word, matches) then
|
||||
return score, matches
|
||||
if not option.disallow_partial_fuzzy_matching or prefix then
|
||||
if matcher.fuzzy(input, word, matches, option) then
|
||||
return score, matches
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0, {}
|
||||
@ -178,11 +197,10 @@ matcher.match = function(input, word, option)
|
||||
end
|
||||
|
||||
--- fuzzy
|
||||
matcher.fuzzy = function(input, word, matches)
|
||||
local last_match = matches[#matches]
|
||||
matcher.fuzzy = function(input, word, matches, option)
|
||||
local input_index = matches[#matches] and (matches[#matches].input_match_end + 1) or 1
|
||||
|
||||
-- Lately specified middle of text.
|
||||
local input_index = last_match.input_match_end + 1
|
||||
for i = 1, #matches - 1 do
|
||||
local curr_match = matches[i]
|
||||
local next_match = matches[i + 1]
|
||||
@ -200,10 +218,9 @@ matcher.fuzzy = function(input, word, matches)
|
||||
end
|
||||
|
||||
-- Remaining text fuzzy match.
|
||||
local last_input_index = input_index
|
||||
local matched = false
|
||||
local word_offset = 0
|
||||
local word_index = last_match.word_match_end + 1
|
||||
local word_index = matches[#matches] and (matches[#matches].word_match_end + 1) or 1
|
||||
local input_match_start = -1
|
||||
local input_match_end = -1
|
||||
local word_match_start = -1
|
||||
@ -220,12 +237,26 @@ matcher.fuzzy = function(input, word, matches)
|
||||
input_index = input_index + 1
|
||||
strict_count = strict_count + (c1 == c2 and 1 or 0)
|
||||
match_count = match_count + 1
|
||||
elseif matched then
|
||||
input_index = last_input_index
|
||||
input_match_end = input_index - 1
|
||||
else
|
||||
if option.disallow_fullfuzzy_matching then
|
||||
break
|
||||
else
|
||||
if matched then
|
||||
table.insert(matches, {
|
||||
input_match_start = input_match_start,
|
||||
input_match_end = input_index - 1,
|
||||
word_match_start = word_match_start,
|
||||
word_match_end = word_index + word_offset - 1,
|
||||
strict_ratio = strict_count / match_count,
|
||||
fuzzy = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
matched = false
|
||||
end
|
||||
word_offset = word_offset + 1
|
||||
end
|
||||
|
||||
if input_index > #input then
|
||||
table.insert(matches, {
|
||||
input_match_start = input_match_start,
|
||||
@ -260,6 +291,7 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
|
||||
local word_offset = 0
|
||||
local strict_count = 0
|
||||
local match_count = 0
|
||||
local no_symbol_match = false
|
||||
while input_index <= #input and word_index + word_offset <= #word do
|
||||
local c1 = string.byte(input, input_index)
|
||||
local c2 = string.byte(word, word_index + word_offset)
|
||||
@ -272,6 +304,7 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
|
||||
strict_count = strict_count + (c1 == c2 and 1 or 0)
|
||||
match_count = match_count + 1
|
||||
word_offset = word_offset + 1
|
||||
no_symbol_match = no_symbol_match or char.is_symbol(c1)
|
||||
else
|
||||
-- Match end (partial region)
|
||||
if input_match_start ~= -1 then
|
||||
@ -281,6 +314,7 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
|
||||
word_match_start = word_index,
|
||||
word_match_end = word_index + word_offset - 1,
|
||||
strict_ratio = strict_count / match_count,
|
||||
no_symbol_match = no_symbol_match,
|
||||
fuzzy = false,
|
||||
}
|
||||
else
|
||||
@ -298,6 +332,7 @@ matcher.find_match_region = function(input, input_start_index, input_end_index,
|
||||
word_match_start = word_index,
|
||||
word_match_end = word_index + word_offset - 1,
|
||||
strict_ratio = strict_count / match_count,
|
||||
no_symbol_match = no_symbol_match,
|
||||
fuzzy = false,
|
||||
}
|
||||
end
|
||||
|
32
bundle/nvim-cmp/lua/cmp/matcher_spec.lua
vendored
32
bundle/nvim-cmp/lua/cmp/matcher_spec.lua
vendored
@ -28,8 +28,35 @@ describe('matcher', function()
|
||||
assert.is.truthy(matcher.match('my_', 'my_awesome_variable') > matcher.match('my_', 'completion_matching_strategy_list'))
|
||||
assert.is.truthy(matcher.match('2', '[[2021') >= 1)
|
||||
|
||||
assert.is.truthy(matcher.match(',', 'pri,') == 0)
|
||||
assert.is.truthy(matcher.match('/', '/**') >= 1)
|
||||
|
||||
assert.is.truthy(matcher.match('true', 'v:true', { synonyms = { 'true' } }) == matcher.match('true', 'true'))
|
||||
assert.is.truthy(matcher.match('g', 'get', { synonyms = { 'get' } }) > matcher.match('g', 'dein#get', { 'dein#get' }))
|
||||
|
||||
assert.is.truthy(matcher.match('Unit', 'net.UnixListener', { disallow_partial_fuzzy_matching = true }) == 0)
|
||||
assert.is.truthy(matcher.match('Unit', 'net.UnixListener', { disallow_partial_fuzzy_matching = false }) >= 1)
|
||||
|
||||
assert.is.truthy(matcher.match('emg', 'error_msg') >= 1)
|
||||
assert.is.truthy(matcher.match('sasr', 'saved_splitright') >= 1)
|
||||
|
||||
local score, matches
|
||||
score, matches = matcher.match('tail', 'HCDetails', {
|
||||
disallow_fuzzy_matching = false,
|
||||
disallow_partial_matching = false,
|
||||
disallow_prefix_unmatching = false,
|
||||
disallow_partial_fuzzy_matching = false,
|
||||
})
|
||||
assert.is.truthy(score >= 1)
|
||||
assert.equals(matches[1].word_match_start, 5)
|
||||
|
||||
score = matcher.match('tail', 'HCDetails', {
|
||||
disallow_fuzzy_matching = false,
|
||||
disallow_partial_matching = false,
|
||||
disallow_prefix_unmatching = false,
|
||||
disallow_partial_fuzzy_matching = true,
|
||||
})
|
||||
assert.is.truthy(score == 0)
|
||||
end)
|
||||
|
||||
it('disallow_fuzzy_matching', function()
|
||||
@ -37,6 +64,11 @@ describe('matcher', function()
|
||||
assert.is.truthy(matcher.match('fmodify', 'fnamemodify', { disallow_fuzzy_matching = false }) >= 1)
|
||||
end)
|
||||
|
||||
it('disallow_fullfuzzy_matching', function()
|
||||
assert.is.truthy(matcher.match('svd', 'saved_splitright', { disallow_fullfuzzy_matching = true }) == 0)
|
||||
assert.is.truthy(matcher.match('svd', 'saved_splitright', { disallow_fullfuzzy_matching = false }) >= 1)
|
||||
end)
|
||||
|
||||
it('disallow_partial_matching', function()
|
||||
assert.is.truthy(matcher.match('fb', 'foo_bar', { disallow_partial_matching = true }) == 0)
|
||||
assert.is.truthy(matcher.match('fb', 'foo_bar', { disallow_partial_matching = false }) >= 1)
|
||||
|
127
bundle/nvim-cmp/lua/cmp/source.lua
vendored
127
bundle/nvim-cmp/lua/cmp/source.lua
vendored
@ -10,23 +10,23 @@ local pattern = require('cmp.utils.pattern')
|
||||
local char = require('cmp.utils.char')
|
||||
|
||||
---@class cmp.Source
|
||||
---@field public id number
|
||||
---@field public id integer
|
||||
---@field public name string
|
||||
---@field public source any
|
||||
---@field public cache cmp.Cache
|
||||
---@field public revision number
|
||||
---@field public revision integer
|
||||
---@field public incomplete boolean
|
||||
---@field public is_triggered_by_symbol boolean
|
||||
---@field public entries cmp.Entry[]
|
||||
---@field public offset number
|
||||
---@field public request_offset number
|
||||
---@field public offset integer
|
||||
---@field public request_offset integer
|
||||
---@field public context cmp.Context
|
||||
---@field public completion_context lsp.CompletionContext|nil
|
||||
---@field public status cmp.SourceStatus
|
||||
---@field public complete_dedup function
|
||||
local source = {}
|
||||
|
||||
---@alias cmp.SourceStatus "1" | "2" | "3"
|
||||
---@alias cmp.SourceStatus 1 | 2 | 3
|
||||
source.SourceStatus = {}
|
||||
source.SourceStatus.WAITING = 1
|
||||
source.SourceStatus.FETCHING = 2
|
||||
@ -46,7 +46,6 @@ source.new = function(name, s)
|
||||
end
|
||||
|
||||
---Reset current completion state
|
||||
---@return boolean
|
||||
source.reset = function(self)
|
||||
self.cache:clear()
|
||||
self.revision = self.revision + 1
|
||||
@ -89,86 +88,92 @@ source.get_entries = function(self, ctx)
|
||||
return {}
|
||||
end
|
||||
|
||||
local target_entries = (function()
|
||||
local key = { 'get_entries', self.revision }
|
||||
for i = ctx.cursor.col, self.offset, -1 do
|
||||
key[3] = string.sub(ctx.cursor_before_line, 1, i)
|
||||
local prev_entries = self.cache:get(key)
|
||||
if prev_entries then
|
||||
return prev_entries
|
||||
end
|
||||
local target_entries = self.entries
|
||||
|
||||
local prev = self.cache:get({ 'get_entries', tostring(self.revision) })
|
||||
if prev and ctx.cursor.row == prev.ctx.cursor.row and self.offset == prev.offset then
|
||||
if ctx.cursor.col == prev.ctx.cursor.col then
|
||||
return prev.entries
|
||||
end
|
||||
return self.entries
|
||||
end)()
|
||||
-- only use prev entries when cursor is moved forward.
|
||||
-- and the pattern offset is the same.
|
||||
if prev.ctx.cursor.col <= ctx.cursor.col then
|
||||
target_entries = prev.entries
|
||||
end
|
||||
end
|
||||
|
||||
local entry_filter = self:get_entry_filter()
|
||||
|
||||
local inputs = {}
|
||||
---@type cmp.Entry[]
|
||||
local entries = {}
|
||||
local matching_config = self:get_matching_config()
|
||||
for _, e in ipairs(target_entries) do
|
||||
local o = e:get_offset()
|
||||
if not inputs[o] then
|
||||
inputs[o] = string.sub(ctx.cursor_before_line, o)
|
||||
end
|
||||
|
||||
local match = e:match(inputs[o], self:get_matching_config())
|
||||
local match = e:match(inputs[o], matching_config)
|
||||
e.score = match.score
|
||||
e.exact = false
|
||||
if e.score >= 1 then
|
||||
e.matches = match.matches
|
||||
e.exact = e:get_filter_text() == inputs[o] or e:get_word() == inputs[o]
|
||||
table.insert(entries, e)
|
||||
end
|
||||
end
|
||||
self.cache:set({ 'get_entries', self.revision, ctx.cursor_before_line }, entries)
|
||||
|
||||
local max_item_count = self:get_source_config().max_item_count or 200
|
||||
local limited_entries = {}
|
||||
for _, e in ipairs(entries) do
|
||||
table.insert(limited_entries, e)
|
||||
if max_item_count and #limited_entries >= max_item_count then
|
||||
break
|
||||
if entry_filter(e, ctx) then
|
||||
entries[#entries + 1] = e
|
||||
end
|
||||
end
|
||||
async.yield()
|
||||
if ctx.aborted then
|
||||
async.abort()
|
||||
end
|
||||
end
|
||||
return limited_entries
|
||||
|
||||
self.cache:set({ 'get_entries', tostring(self.revision) }, { entries = entries, ctx = ctx, offset = self.offset })
|
||||
|
||||
return entries
|
||||
end
|
||||
|
||||
---Get default insert range
|
||||
---@return lsp.Range|nil
|
||||
---Get default insert range (UTF8 byte index).
|
||||
---@return lsp.Range
|
||||
source.get_default_insert_range = function(self)
|
||||
if not self.context then
|
||||
return nil
|
||||
error('context is not initialized yet.')
|
||||
end
|
||||
|
||||
return self.cache:ensure({ 'get_default_insert_range', self.revision }, function()
|
||||
return self.cache:ensure({ 'get_default_insert_range', tostring(self.revision) }, function()
|
||||
return {
|
||||
start = {
|
||||
line = self.context.cursor.row - 1,
|
||||
character = misc.to_utfindex(self.context.cursor_line, self.offset),
|
||||
character = self.offset - 1,
|
||||
},
|
||||
['end'] = {
|
||||
line = self.context.cursor.row - 1,
|
||||
character = misc.to_utfindex(self.context.cursor_line, self.context.cursor.col),
|
||||
character = self.context.cursor.col - 1,
|
||||
},
|
||||
}
|
||||
end)
|
||||
end
|
||||
|
||||
---Get default replace range
|
||||
---@return lsp.Range|nil
|
||||
---Get default replace range (UTF8 byte index).
|
||||
---@return lsp.Range
|
||||
source.get_default_replace_range = function(self)
|
||||
if not self.context then
|
||||
return nil
|
||||
error('context is not initialized yet.')
|
||||
end
|
||||
|
||||
return self.cache:ensure({ 'get_default_replace_range', self.revision }, function()
|
||||
return self.cache:ensure({ 'get_default_replace_range', tostring(self.revision) }, function()
|
||||
local _, e = pattern.offset('^' .. '\\%(' .. self:get_keyword_pattern() .. '\\)', string.sub(self.context.cursor_line, self.offset))
|
||||
return {
|
||||
start = {
|
||||
line = self.context.cursor.row - 1,
|
||||
character = misc.to_utfindex(self.context.cursor_line, self.offset),
|
||||
character = self.offset,
|
||||
},
|
||||
['end'] = {
|
||||
line = self.context.cursor.row - 1,
|
||||
character = misc.to_utfindex(self.context.cursor_line, e and self.offset + e - 1 or self.context.cursor.col),
|
||||
character = (e and self.offset + e - 2 or self.context.cursor.col - 1),
|
||||
},
|
||||
}
|
||||
end)
|
||||
@ -217,13 +222,16 @@ source.get_keyword_pattern = function(self)
|
||||
return c.keyword_pattern
|
||||
end
|
||||
if self.source.get_keyword_pattern then
|
||||
return self.source:get_keyword_pattern(misc.copy(c))
|
||||
local keyword_pattern = self.source:get_keyword_pattern(misc.copy(c))
|
||||
if keyword_pattern then
|
||||
return keyword_pattern
|
||||
end
|
||||
end
|
||||
return config.get().completion.keyword_pattern
|
||||
end
|
||||
|
||||
---Get keyword_length
|
||||
---@return number
|
||||
---@return integer
|
||||
source.get_keyword_length = function(self)
|
||||
local c = self:get_source_config()
|
||||
if c.keyword_length then
|
||||
@ -232,10 +240,31 @@ source.get_keyword_length = function(self)
|
||||
return config.get().completion.keyword_length or 1
|
||||
end
|
||||
|
||||
---Get filter
|
||||
--@return fun(entry: cmp.Entry, context: cmp.Context): boolean
|
||||
source.get_entry_filter = function(self)
|
||||
local c = self:get_source_config()
|
||||
if c.entry_filter then
|
||||
return c.entry_filter --[[@as fun(entry: cmp.Entry, context: cmp.Context): boolean]]
|
||||
end
|
||||
return function(_, _)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
---Get lsp.PositionEncodingKind
|
||||
---@return lsp.PositionEncodingKind
|
||||
source.get_position_encoding_kind = function(self)
|
||||
if self.source.get_position_encoding_kind then
|
||||
return self.source:get_position_encoding_kind()
|
||||
end
|
||||
return types.lsp.PositionEncodingKind.UTF16
|
||||
end
|
||||
|
||||
---Invoke completion
|
||||
---@param ctx cmp.Context
|
||||
---@param callback function
|
||||
---@return boolean Return true if not trigger completion.
|
||||
---@return boolean? Return true if not trigger completion.
|
||||
source.complete = function(self, ctx, callback)
|
||||
local offset = ctx:get_offset(self:get_keyword_pattern())
|
||||
|
||||
@ -260,7 +289,7 @@ source.complete = function(self, ctx, callback)
|
||||
triggerCharacter = before_char,
|
||||
}
|
||||
elseif ctx:get_reason() ~= types.cmp.ContextReason.TriggerOnly then
|
||||
if self:get_keyword_length() <= (ctx.cursor.col - offset) then
|
||||
if offset < ctx.cursor.col and self:get_keyword_length() <= (ctx.cursor.col - offset) then
|
||||
if self.incomplete and self.context.cursor.col ~= ctx.cursor.col and self.status ~= source.SourceStatus.FETCHING then
|
||||
completion_context = {
|
||||
triggerKind = types.lsp.CompletionTriggerKind.TriggerForIncompleteCompletions,
|
||||
@ -300,6 +329,10 @@ source.complete = function(self, ctx, callback)
|
||||
completion_context = completion_context,
|
||||
}),
|
||||
self.complete_dedup(vim.schedule_wrap(function(response)
|
||||
if self.context ~= ctx then
|
||||
return
|
||||
end
|
||||
---@type lsp.CompletionResponse
|
||||
response = response or {}
|
||||
|
||||
self.incomplete = response.isIncomplete or false
|
||||
@ -312,14 +345,14 @@ source.complete = function(self, ctx, callback)
|
||||
self.status = source.SourceStatus.COMPLETED
|
||||
self.entries = {}
|
||||
for i, item in ipairs(response.items or response) do
|
||||
if (misc.safe(item) or {}).label then
|
||||
local e = entry.new(ctx, self, item)
|
||||
if (item or {}).label then
|
||||
local e = entry.new(ctx, self, item, response.itemDefaults)
|
||||
self.entries[i] = e
|
||||
self.offset = math.min(self.offset, e:get_offset())
|
||||
end
|
||||
end
|
||||
self.revision = self.revision + 1
|
||||
if #self:get_entries(ctx) == 0 then
|
||||
if #self.entries == 0 then
|
||||
self.offset = old_offset
|
||||
self.entries = old_entries
|
||||
self.revision = self.revision + 1
|
||||
|
130
bundle/nvim-cmp/lua/cmp/types/cmp.lua
vendored
130
bundle/nvim-cmp/lua/cmp/types/cmp.lua
vendored
@ -1,37 +1,43 @@
|
||||
local cmp = {}
|
||||
|
||||
---@alias cmp.ConfirmBehavior "'insert'" | "'replace'"
|
||||
cmp.ConfirmBehavior = {}
|
||||
cmp.ConfirmBehavior.Insert = 'insert'
|
||||
cmp.ConfirmBehavior.Replace = 'replace'
|
||||
---@alias cmp.ConfirmBehavior 'insert' | 'replace'
|
||||
cmp.ConfirmBehavior = {
|
||||
Insert = 'insert',
|
||||
Replace = 'replace',
|
||||
}
|
||||
|
||||
---@alias cmp.SelectBehavior "'insert'" | "'select'"
|
||||
cmp.SelectBehavior = {}
|
||||
cmp.SelectBehavior.Insert = 'insert'
|
||||
cmp.SelectBehavior.Select = 'select'
|
||||
---@alias cmp.SelectBehavior 'insert' | 'select'
|
||||
cmp.SelectBehavior = {
|
||||
Insert = 'insert',
|
||||
Select = 'select',
|
||||
}
|
||||
|
||||
---@alias cmp.ContextReason "'auto'" | "'manual'" | "'none'"
|
||||
cmp.ContextReason = {}
|
||||
cmp.ContextReason.Auto = 'auto'
|
||||
cmp.ContextReason.Manual = 'manual'
|
||||
cmp.ContextReason.TriggerOnly = 'triggerOnly'
|
||||
cmp.ContextReason.None = 'none'
|
||||
---@alias cmp.ContextReason 'auto' | 'manual' | 'triggerOnly' | 'none'
|
||||
cmp.ContextReason = {
|
||||
Auto = 'auto',
|
||||
Manual = 'manual',
|
||||
TriggerOnly = 'triggerOnly',
|
||||
None = 'none',
|
||||
}
|
||||
|
||||
---@alias cmp.TriggerEvent "'InsertEnter'" | "'TextChanged'"
|
||||
cmp.TriggerEvent = {}
|
||||
cmp.TriggerEvent.InsertEnter = 'InsertEnter'
|
||||
cmp.TriggerEvent.TextChanged = 'TextChanged'
|
||||
---@alias cmp.TriggerEvent 'InsertEnter' | 'TextChanged'
|
||||
cmp.TriggerEvent = {
|
||||
InsertEnter = 'InsertEnter',
|
||||
TextChanged = 'TextChanged',
|
||||
}
|
||||
|
||||
---@alias cmp.PreselectMode "'item'" | "'None'"
|
||||
cmp.PreselectMode = {}
|
||||
cmp.PreselectMode.Item = 'item'
|
||||
cmp.PreselectMode.None = 'none'
|
||||
---@alias cmp.PreselectMode 'item' | 'None'
|
||||
cmp.PreselectMode = {
|
||||
Item = 'item',
|
||||
None = 'none',
|
||||
}
|
||||
|
||||
---@alias cmp.ItemField "'abbr'" | "'kind'" | "'menu'"
|
||||
cmp.ItemField = {}
|
||||
cmp.ItemField.Abbr = 'abbr'
|
||||
cmp.ItemField.Kind = 'kind'
|
||||
cmp.ItemField.Menu = 'menu'
|
||||
---@alias cmp.ItemField 'abbr' | 'kind' | 'menu'
|
||||
cmp.ItemField = {
|
||||
Abbr = 'abbr',
|
||||
Kind = 'kind',
|
||||
Menu = 'menu',
|
||||
}
|
||||
|
||||
---@class cmp.ContextOption
|
||||
---@field public reason cmp.ContextReason|nil
|
||||
@ -45,22 +51,24 @@ cmp.ItemField.Menu = 'menu'
|
||||
|
||||
---@class cmp.SnippetExpansionParams
|
||||
---@field public body string
|
||||
---@field public insert_text_mode number
|
||||
---@field public insert_text_mode integer
|
||||
|
||||
---@class cmp.CompleteParams
|
||||
---@field public reason? cmp.ContextReason
|
||||
---@field public config? cmp.ConfigSchema
|
||||
|
||||
---@class cmp.Setup
|
||||
---@field public __call fun(c: cmp.ConfigSchema)
|
||||
---@class cmp.SetupProperty
|
||||
---@field public buffer fun(c: cmp.ConfigSchema)
|
||||
---@field public global fun(c: cmp.ConfigSchema)
|
||||
---@field public cmdline fun(type: string, c: cmp.ConfigSchema)
|
||||
---@field public cmdline fun(type: string|string[], c: cmp.ConfigSchema)
|
||||
---@field public filetype fun(type: string|string[], c: cmp.ConfigSchema)
|
||||
|
||||
---@alias cmp.Setup cmp.SetupProperty | fun(c: cmp.ConfigSchema)
|
||||
|
||||
---@class cmp.SourceApiParams: cmp.SourceConfig
|
||||
|
||||
---@class cmp.SourceCompletionApiParams : cmp.SourceConfig
|
||||
---@field public offset number
|
||||
---@field public offset integer
|
||||
---@field public context cmp.Context
|
||||
---@field public completion_context lsp.CompletionContext
|
||||
|
||||
@ -71,11 +79,12 @@ cmp.ItemField.Menu = 'menu'
|
||||
---@field public s nil|function(fallback: function): void
|
||||
|
||||
---@class cmp.ConfigSchema
|
||||
---@field private revision number
|
||||
---@field public enabled fun():boolean|boolean
|
||||
---@field private revision integer
|
||||
---@field public enabled boolean | fun(): boolean
|
||||
---@field public performance cmp.PerformanceConfig
|
||||
---@field public preselect cmp.PreselectMode
|
||||
---@field public completion cmp.CompletionConfig
|
||||
---@field public documentation cmp.DocumentationConfig|"false"
|
||||
---@field public window cmp.WindowConfig|nil
|
||||
---@field public confirmation cmp.ConfirmationConfig
|
||||
---@field public matching cmp.MatchingConfig
|
||||
---@field public sorting cmp.SortingConfig
|
||||
@ -86,19 +95,32 @@ cmp.ItemField.Menu = 'menu'
|
||||
---@field public view cmp.ViewConfig
|
||||
---@field public experimental cmp.ExperimentalConfig
|
||||
|
||||
---@class cmp.PerformanceConfig
|
||||
---@field public debounce integer
|
||||
---@field public throttle integer
|
||||
---@field public fetching_timeout integer
|
||||
---@field public async_budget integer Maximum time (in ms) an async function is allowed to run during one step of the event loop.
|
||||
---@field public max_view_entries integer
|
||||
|
||||
---@class cmp.WindowConfig
|
||||
---@field completion cmp.WindowConfig
|
||||
---@field documentation cmp.WindowConfig|nil
|
||||
|
||||
---@class cmp.CompletionConfig
|
||||
---@field public autocomplete cmp.TriggerEvent[]
|
||||
---@field public completeopt string
|
||||
---@field public keyword_pattern string
|
||||
---@field public keyword_length number
|
||||
---@field public get_trigger_characters fun(trigger_characters: string[]): string[]
|
||||
---@field public keyword_length integer
|
||||
---@field public keyword_pattern string
|
||||
|
||||
---@class cmp.DocumentationConfig
|
||||
---@field public border string[]
|
||||
---@class cmp.WindowConfig
|
||||
---@field public border string|string[]
|
||||
---@field public winhighlight string
|
||||
---@field public maxwidth number|nil
|
||||
---@field public maxheight number|nil
|
||||
---@field public zindex number|nil
|
||||
---@field public zindex integer|nil
|
||||
---@field public max_width integer|nil
|
||||
---@field public max_height integer|nil
|
||||
---@field public scrolloff integer|nil
|
||||
---@field public scrollbar boolean|true
|
||||
|
||||
---@class cmp.ConfirmationConfig
|
||||
---@field public default_behavior cmp.ConfirmBehavior
|
||||
@ -106,23 +128,25 @@ cmp.ItemField.Menu = 'menu'
|
||||
|
||||
---@class cmp.MatchingConfig
|
||||
---@field public disallow_fuzzy_matching boolean
|
||||
---@field public disallow_fullfuzzy_matching boolean
|
||||
---@field public disallow_partial_fuzzy_matching boolean
|
||||
---@field public disallow_partial_matching boolean
|
||||
---@field public disallow_prefix_unmatching boolean
|
||||
|
||||
---@class cmp.SortingConfig
|
||||
---@field public priority_weight number
|
||||
---@field public priority_weight integer
|
||||
---@field public comparators function[]
|
||||
|
||||
---@class cmp.FormattingConfig
|
||||
---@field public fields cmp.ItemField[]
|
||||
---@field public expandable_indicator boolean
|
||||
---@field public format fun(entry: cmp.Entry, vim_item: vim.CompletedItem): vim.CompletedItem
|
||||
|
||||
---@class cmp.SnippetConfig
|
||||
---@field public expand fun(args: cmp.SnippetExpansionParams)
|
||||
|
||||
---@class cmp.ExperimentalConfig
|
||||
---@field public native_menu boolean
|
||||
---@field public ghost_text cmp.GhostTextConfig|"false"
|
||||
---@field public ghost_text cmp.GhostTextConfig|false
|
||||
|
||||
---@class cmp.GhostTextConfig
|
||||
---@field hl_group string
|
||||
@ -130,12 +154,12 @@ cmp.ItemField.Menu = 'menu'
|
||||
---@class cmp.SourceConfig
|
||||
---@field public name string
|
||||
---@field public option table|nil
|
||||
---@field public priority number|nil
|
||||
---@field public priority integer|nil
|
||||
---@field public trigger_characters string[]|nil
|
||||
---@field public keyword_pattern string|nil
|
||||
---@field public keyword_length number|nil
|
||||
---@field public max_item_count number|nil
|
||||
---@field public group_index number|nil
|
||||
---@field public keyword_length integer|nil
|
||||
---@field public group_index integer|nil
|
||||
---@field public entry_filter nil|function(entry: cmp.Entry, ctx: cmp.Context): boolean
|
||||
|
||||
---@class cmp.ViewConfig
|
||||
---@field public entries cmp.EntriesConfig
|
||||
@ -143,14 +167,14 @@ cmp.ItemField.Menu = 'menu'
|
||||
---@alias cmp.EntriesConfig cmp.CustomEntriesConfig|cmp.NativeEntriesConfig|cmp.WildmenuEntriesConfig|string
|
||||
|
||||
---@class cmp.CustomEntriesConfig
|
||||
---@field name "'custom'"
|
||||
---@field selection_order "'top_down'"|"'near_cursor'"
|
||||
---@field name 'custom'
|
||||
---@field selection_order 'top_down'|'near_cursor'
|
||||
|
||||
---@class cmp.NativeEntriesConfig
|
||||
---@field name "'native'"
|
||||
---@field name 'native'
|
||||
|
||||
---@class cmp.WildmenuEntriesConfig
|
||||
---@field name "'wildmenu'"
|
||||
---@field name 'wildmenu'
|
||||
---@field separator string|nil
|
||||
|
||||
return cmp
|
||||
|
372
bundle/nvim-cmp/lua/cmp/types/lsp.lua
vendored
372
bundle/nvim-cmp/lua/cmp/types/lsp.lua
vendored
@ -1,151 +1,234 @@
|
||||
local misc = require('cmp.utils.misc')
|
||||
|
||||
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/
|
||||
---@class lsp
|
||||
local lsp = {}
|
||||
|
||||
lsp.Position = {}
|
||||
---@enum lsp.PositionEncodingKind
|
||||
lsp.PositionEncodingKind = {
|
||||
UTF8 = 'utf-8',
|
||||
UTF16 = 'utf-16',
|
||||
UTF32 = 'utf-32',
|
||||
}
|
||||
|
||||
---Convert lsp.Position to vim.Position
|
||||
---@param buf number|string
|
||||
---@param position lsp.Position
|
||||
---@return vim.Position
|
||||
lsp.Position.to_vim = function(buf, position)
|
||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||
vim.fn.bufload(buf)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, position.line, position.line + 1, false)
|
||||
if #lines > 0 then
|
||||
lsp.Position = {
|
||||
---Convert lsp.Position to vim.Position
|
||||
---@param buf integer
|
||||
---@param position lsp.Position
|
||||
--
|
||||
---@return vim.Position
|
||||
to_vim = function(buf, position)
|
||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||
vim.fn.bufload(buf)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, position.line, position.line + 1, false)
|
||||
if #lines > 0 then
|
||||
return {
|
||||
row = position.line + 1,
|
||||
col = misc.to_vimindex(lines[1], position.character),
|
||||
}
|
||||
end
|
||||
return {
|
||||
row = position.line + 1,
|
||||
col = misc.to_vimindex(lines[1], position.character),
|
||||
col = position.character + 1,
|
||||
}
|
||||
end
|
||||
return {
|
||||
row = position.line + 1,
|
||||
col = position.character + 1,
|
||||
}
|
||||
end
|
||||
|
||||
---Convert vim.Position to lsp.Position
|
||||
---@param buf number|string
|
||||
---@param position vim.Position
|
||||
---@return lsp.Position
|
||||
lsp.Position.to_lsp = function(buf, position)
|
||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||
vim.fn.bufload(buf)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, position.row - 1, position.row, false)
|
||||
if #lines > 0 then
|
||||
end,
|
||||
---Convert vim.Position to lsp.Position
|
||||
---@param buf integer
|
||||
---@param position vim.Position
|
||||
---@return lsp.Position
|
||||
to_lsp = function(buf, position)
|
||||
if not vim.api.nvim_buf_is_loaded(buf) then
|
||||
vim.fn.bufload(buf)
|
||||
end
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, position.row - 1, position.row, false)
|
||||
if #lines > 0 then
|
||||
return {
|
||||
line = position.row - 1,
|
||||
character = misc.to_utfindex(lines[1], position.col),
|
||||
}
|
||||
end
|
||||
return {
|
||||
line = position.row - 1,
|
||||
character = misc.to_utfindex(lines[1], position.col),
|
||||
character = position.col - 1,
|
||||
}
|
||||
end
|
||||
return {
|
||||
line = position.row - 1,
|
||||
character = position.col - 1,
|
||||
}
|
||||
end
|
||||
end,
|
||||
|
||||
lsp.Range = {}
|
||||
---Convert position to utf8 from specified encoding.
|
||||
---@param text string
|
||||
---@param position lsp.Position
|
||||
---@param from_encoding? lsp.PositionEncodingKind
|
||||
---@return lsp.Position
|
||||
to_utf8 = function(text, position, from_encoding)
|
||||
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||
if from_encoding == lsp.PositionEncodingKind.UTF8 then
|
||||
return position
|
||||
end
|
||||
|
||||
---Convert lsp.Range to vim.Range
|
||||
---@param buf number|string
|
||||
---@param range lsp.Range
|
||||
---@return vim.Range
|
||||
lsp.Range.to_vim = function(buf, range)
|
||||
return {
|
||||
start = lsp.Position.to_vim(buf, range.start),
|
||||
['end'] = lsp.Position.to_vim(buf, range['end']),
|
||||
}
|
||||
end
|
||||
local ok, byteindex = pcall(function()
|
||||
return vim.str_byteindex(text, position.character, from_encoding == lsp.PositionEncodingKind.UTF16)
|
||||
end)
|
||||
if not ok then
|
||||
return position
|
||||
end
|
||||
return { line = position.line, character = byteindex }
|
||||
end,
|
||||
|
||||
---Convert vim.Range to lsp.Range
|
||||
---@param buf number|string
|
||||
---@param range vim.Range
|
||||
---@return lsp.Range
|
||||
lsp.Range.to_lsp = function(buf, range)
|
||||
return {
|
||||
start = lsp.Position.to_lsp(buf, range.start),
|
||||
['end'] = lsp.Position.to_lsp(buf, range['end']),
|
||||
}
|
||||
end
|
||||
---Convert position to utf16 from specified encoding.
|
||||
---@param text string
|
||||
---@param position lsp.Position
|
||||
---@param from_encoding? lsp.PositionEncodingKind
|
||||
---@return lsp.Position
|
||||
to_utf16 = function(text, position, from_encoding)
|
||||
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||
if from_encoding == lsp.PositionEncodingKind.UTF16 then
|
||||
return position
|
||||
end
|
||||
|
||||
---@alias lsp.CompletionTriggerKind "1" | "2" | "3"
|
||||
lsp.CompletionTriggerKind = {}
|
||||
lsp.CompletionTriggerKind.Invoked = 1
|
||||
lsp.CompletionTriggerKind.TriggerCharacter = 2
|
||||
lsp.CompletionTriggerKind.TriggerForIncompleteCompletions = 3
|
||||
local utf8 = lsp.Position.to_utf8(text, position, from_encoding)
|
||||
for index = utf8.character, 0, -1 do
|
||||
local ok, utf16index = pcall(function()
|
||||
return select(2, vim.str_utfindex(text, index))
|
||||
end)
|
||||
if ok then
|
||||
return { line = utf8.line, character = utf16index }
|
||||
end
|
||||
end
|
||||
return position
|
||||
end,
|
||||
|
||||
---Convert position to utf32 from specified encoding.
|
||||
---@param text string
|
||||
---@param position lsp.Position
|
||||
---@param from_encoding? lsp.PositionEncodingKind
|
||||
---@return lsp.Position
|
||||
to_utf32 = function(text, position, from_encoding)
|
||||
from_encoding = from_encoding or lsp.PositionEncodingKind.UTF16
|
||||
if from_encoding == lsp.PositionEncodingKind.UTF32 then
|
||||
return position
|
||||
end
|
||||
|
||||
local utf8 = lsp.Position.to_utf8(text, position, from_encoding)
|
||||
for index = utf8.character, 0, -1 do
|
||||
local ok, utf32index = pcall(function()
|
||||
return select(1, vim.str_utfindex(text, index))
|
||||
end)
|
||||
if ok then
|
||||
return { line = utf8.line, character = utf32index }
|
||||
end
|
||||
end
|
||||
return position
|
||||
end,
|
||||
}
|
||||
|
||||
lsp.Range = {
|
||||
---Convert lsp.Range to vim.Range
|
||||
---@param buf integer
|
||||
---@param range lsp.Range
|
||||
---@return vim.Range
|
||||
to_vim = function(buf, range)
|
||||
return {
|
||||
start = lsp.Position.to_vim(buf, range.start),
|
||||
['end'] = lsp.Position.to_vim(buf, range['end']),
|
||||
}
|
||||
end,
|
||||
|
||||
---Convert vim.Range to lsp.Range
|
||||
---@param buf integer
|
||||
---@param range vim.Range
|
||||
---@return lsp.Range
|
||||
to_lsp = function(buf, range)
|
||||
return {
|
||||
start = lsp.Position.to_lsp(buf, range.start),
|
||||
['end'] = lsp.Position.to_lsp(buf, range['end']),
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
---@alias lsp.CompletionTriggerKind 1 | 2 | 3
|
||||
lsp.CompletionTriggerKind = {
|
||||
Invoked = 1,
|
||||
TriggerCharacter = 2,
|
||||
TriggerForIncompleteCompletions = 3,
|
||||
}
|
||||
|
||||
---@alias lsp.InsertTextFormat 1 | 2
|
||||
lsp.InsertTextFormat = {}
|
||||
lsp.InsertTextFormat.PlainText = 1
|
||||
lsp.InsertTextFormat.Snippet = 2
|
||||
|
||||
---@alias lsp.InsertTextMode 1 | 2
|
||||
lsp.InsertTextMode = {
|
||||
AsIs = 1,
|
||||
AdjustIndentation = 2,
|
||||
}
|
||||
|
||||
---@alias lsp.MarkupKind 'plaintext' | 'markdown'
|
||||
lsp.MarkupKind = {
|
||||
PlainText = 'plaintext',
|
||||
Markdown = 'markdown',
|
||||
}
|
||||
|
||||
---@alias lsp.CompletionItemTag 1
|
||||
lsp.CompletionItemTag = {
|
||||
Deprecated = 1,
|
||||
}
|
||||
|
||||
---@alias lsp.CompletionItemKind 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25
|
||||
lsp.CompletionItemKind = {
|
||||
Text = 1,
|
||||
Method = 2,
|
||||
Function = 3,
|
||||
Constructor = 4,
|
||||
Field = 5,
|
||||
Variable = 6,
|
||||
Class = 7,
|
||||
Interface = 8,
|
||||
Module = 9,
|
||||
Property = 10,
|
||||
Unit = 11,
|
||||
Value = 12,
|
||||
Enum = 13,
|
||||
Keyword = 14,
|
||||
Snippet = 15,
|
||||
Color = 16,
|
||||
File = 17,
|
||||
Reference = 18,
|
||||
Folder = 19,
|
||||
EnumMember = 20,
|
||||
Constant = 21,
|
||||
Struct = 22,
|
||||
Event = 23,
|
||||
Operator = 24,
|
||||
TypeParameter = 25,
|
||||
}
|
||||
lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
||||
|
||||
---@class lsp.internal.CompletionItemDefaults
|
||||
---@field public commitCharacters? string[]
|
||||
---@field public editRange? lsp.Range | { insert: lsp.Range, replace: lsp.Range }
|
||||
---@field public insertTextFormat? lsp.InsertTextFormat
|
||||
---@field public insertTextMode? lsp.InsertTextMode
|
||||
---@field public data? any
|
||||
|
||||
---@class lsp.CompletionContext
|
||||
---@field public triggerKind lsp.CompletionTriggerKind
|
||||
---@field public triggerCharacter string|nil
|
||||
|
||||
---@alias lsp.InsertTextFormat "1" | "2"
|
||||
lsp.InsertTextFormat = {}
|
||||
lsp.InsertTextFormat.PlainText = 1
|
||||
lsp.InsertTextFormat.Snippet = 2
|
||||
lsp.InsertTextFormat = vim.tbl_add_reverse_lookup(lsp.InsertTextFormat)
|
||||
|
||||
---@alias lsp.InsertTextMode "1" | "2"
|
||||
lsp.InsertTextMode = {}
|
||||
lsp.InsertTextMode.AsIs = 0
|
||||
lsp.InsertTextMode.AdjustIndentation = 1
|
||||
lsp.InsertTextMode = vim.tbl_add_reverse_lookup(lsp.InsertTextMode)
|
||||
|
||||
---@alias lsp.MarkupKind "'plaintext'" | "'markdown'"
|
||||
lsp.MarkupKind = {}
|
||||
lsp.MarkupKind.PlainText = 'plaintext'
|
||||
lsp.MarkupKind.Markdown = 'markdown'
|
||||
lsp.MarkupKind = vim.tbl_add_reverse_lookup(lsp.MarkupKind)
|
||||
|
||||
---@alias lsp.CompletionItemTag "1"
|
||||
lsp.CompletionItemTag = {}
|
||||
lsp.CompletionItemTag.Deprecated = 1
|
||||
lsp.CompletionItemTag = vim.tbl_add_reverse_lookup(lsp.CompletionItemTag)
|
||||
|
||||
---@alias lsp.CompletionItemKind "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25"
|
||||
lsp.CompletionItemKind = {}
|
||||
lsp.CompletionItemKind.Text = 1
|
||||
lsp.CompletionItemKind.Method = 2
|
||||
lsp.CompletionItemKind.Function = 3
|
||||
lsp.CompletionItemKind.Constructor = 4
|
||||
lsp.CompletionItemKind.Field = 5
|
||||
lsp.CompletionItemKind.Variable = 6
|
||||
lsp.CompletionItemKind.Class = 7
|
||||
lsp.CompletionItemKind.Interface = 8
|
||||
lsp.CompletionItemKind.Module = 9
|
||||
lsp.CompletionItemKind.Property = 10
|
||||
lsp.CompletionItemKind.Unit = 11
|
||||
lsp.CompletionItemKind.Value = 12
|
||||
lsp.CompletionItemKind.Enum = 13
|
||||
lsp.CompletionItemKind.Keyword = 14
|
||||
lsp.CompletionItemKind.Snippet = 15
|
||||
lsp.CompletionItemKind.Color = 16
|
||||
lsp.CompletionItemKind.File = 17
|
||||
lsp.CompletionItemKind.Reference = 18
|
||||
lsp.CompletionItemKind.Folder = 19
|
||||
lsp.CompletionItemKind.EnumMember = 20
|
||||
lsp.CompletionItemKind.Constant = 21
|
||||
lsp.CompletionItemKind.Struct = 22
|
||||
lsp.CompletionItemKind.Event = 23
|
||||
lsp.CompletionItemKind.Operator = 24
|
||||
lsp.CompletionItemKind.TypeParameter = 25
|
||||
lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
||||
|
||||
---@class lsp.CompletionList
|
||||
---@field public isIncomplete boolean
|
||||
---@field public itemDefaults? lsp.internal.CompletionItemDefaults
|
||||
---@field public items lsp.CompletionItem[]
|
||||
|
||||
---@alias lsp.CompletionResponse lsp.CompletionList|lsp.CompletionItem[]|nil
|
||||
---@alias lsp.CompletionResponse lsp.CompletionList|lsp.CompletionItem[]
|
||||
|
||||
---@class lsp.MarkupContent
|
||||
---@field public kind lsp.MarkupKind
|
||||
---@field public value string
|
||||
|
||||
---@class lsp.Position
|
||||
---@field public line number
|
||||
---@field public character number
|
||||
---@field public line integer
|
||||
---@field public character integer
|
||||
|
||||
---@class lsp.Range
|
||||
---@field public start lsp.Position
|
||||
@ -160,34 +243,45 @@ lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind)
|
||||
---@field public range lsp.Range|nil
|
||||
---@field public newText string
|
||||
|
||||
---@class lsp.InsertReplaceTextEdit
|
||||
---@field public insert lsp.Range|nil
|
||||
---@field public replace lsp.Range|nil
|
||||
---@alias lsp.InsertReplaceTextEdit lsp.internal.InsertTextEdit|lsp.internal.ReplaceTextEdit
|
||||
|
||||
---@class lsp.internal.InsertTextEdit
|
||||
---@field public insert lsp.Range
|
||||
---@field public newText string
|
||||
|
||||
---@class lsp.internal.ReplaceTextEdit
|
||||
---@field public replace lsp.Range
|
||||
---@field public newText string
|
||||
|
||||
---@class lsp.CompletionItemLabelDetails
|
||||
---@field public detail string|nil
|
||||
---@field public description string|nil
|
||||
---@field public detail? string
|
||||
---@field public description? string
|
||||
|
||||
---@class lsp.internal.CmpCompletionExtension
|
||||
---@field public kind_text string
|
||||
---@field public kind_hl_group string
|
||||
|
||||
---@class lsp.CompletionItem
|
||||
---@field public label string
|
||||
---@field public labelDetails lsp.CompletionItemLabelDetails|nil
|
||||
---@field public kind lsp.CompletionItemKind|nil
|
||||
---@field public tags lsp.CompletionItemTag[]|nil
|
||||
---@field public detail string|nil
|
||||
---@field public documentation lsp.MarkupContent|string|nil
|
||||
---@field public deprecated boolean|nil
|
||||
---@field public preselect boolean|nil
|
||||
---@field public sortText string|nil
|
||||
---@field public filterText string|nil
|
||||
---@field public insertText string|nil
|
||||
---@field public insertTextFormat lsp.InsertTextFormat
|
||||
---@field public insertTextMode lsp.InsertTextMode
|
||||
---@field public textEdit lsp.TextEdit|lsp.InsertReplaceTextEdit|nil
|
||||
---@field public additionalTextEdits lsp.TextEdit[]
|
||||
---@field public commitCharacters string[]|nil
|
||||
---@field public command lsp.Command|nil
|
||||
---@field public data any|nil
|
||||
---@field public labelDetails? lsp.CompletionItemLabelDetails
|
||||
---@field public kind? lsp.CompletionItemKind
|
||||
---@field public tags? lsp.CompletionItemTag[]
|
||||
---@field public detail? string
|
||||
---@field public documentation? lsp.MarkupContent|string
|
||||
---@field public deprecated? boolean
|
||||
---@field public preselect? boolean
|
||||
---@field public sortText? string
|
||||
---@field public filterText? string
|
||||
---@field public insertText? string
|
||||
---@field public insertTextFormat? lsp.InsertTextFormat
|
||||
---@field public insertTextMode? lsp.InsertTextMode
|
||||
---@field public textEdit? lsp.TextEdit|lsp.InsertReplaceTextEdit
|
||||
---@field public textEditText? string
|
||||
---@field public additionalTextEdits? lsp.TextEdit[]
|
||||
---@field public commitCharacters? string[]
|
||||
---@field public command? lsp.Command
|
||||
---@field public data? any
|
||||
---@field public cmp? lsp.internal.CmpCompletionExtension
|
||||
---
|
||||
---TODO: Should send the issue for upstream?
|
||||
---@field public word string|nil
|
||||
|
12
bundle/nvim-cmp/lua/cmp/types/vim.lua
vendored
12
bundle/nvim-cmp/lua/cmp/types/vim.lua
vendored
@ -3,17 +3,17 @@
|
||||
---@field public abbr string|nil
|
||||
---@field public kind string|nil
|
||||
---@field public menu string|nil
|
||||
---@field public equal "1"|nil
|
||||
---@field public empty "1"|nil
|
||||
---@field public dup "1"|nil
|
||||
---@field public equal 1|nil
|
||||
---@field public empty 1|nil
|
||||
---@field public dup 1|nil
|
||||
---@field public id any
|
||||
---@field public abbr_hl_group string|nil
|
||||
---@field public kind_hl_group string|nil
|
||||
---@field public menu_hl_group string|nil
|
||||
|
||||
---@class vim.Position
|
||||
---@field public row number
|
||||
---@field public col number
|
||||
---@class vim.Position 1-based index
|
||||
---@field public row integer
|
||||
---@field public col integer
|
||||
|
||||
---@class vim.Range
|
||||
---@field public start vim.Position
|
||||
|
5
bundle/nvim-cmp/lua/cmp/utils/api.lua
vendored
5
bundle/nvim-cmp/lua/cmp/utils/api.lua
vendored
@ -44,9 +44,10 @@ api.get_current_line = function()
|
||||
return vim.api.nvim_get_current_line()
|
||||
end
|
||||
|
||||
---@return { [1]: integer, [2]: integer }
|
||||
api.get_cursor = function()
|
||||
if api.is_cmdline_mode() then
|
||||
return { vim.o.lines - (vim.api.nvim_get_option('cmdheight') or 1) + 1, vim.fn.getcmdpos() - 1 }
|
||||
return { math.min(vim.o.lines, vim.o.lines - (vim.api.nvim_get_option('cmdheight') - 1)), vim.fn.getcmdpos() - 1 }
|
||||
end
|
||||
return vim.api.nvim_win_get_cursor(0)
|
||||
end
|
||||
@ -54,7 +55,7 @@ end
|
||||
api.get_screen_cursor = function()
|
||||
if api.is_cmdline_mode() then
|
||||
local cursor = api.get_cursor()
|
||||
return { cursor[1], cursor[2] + 1 }
|
||||
return { cursor[1], vim.fn.strdisplaywidth(string.sub(vim.fn.getcmdline(), 1, cursor[2] + 1)) }
|
||||
end
|
||||
local cursor = api.get_cursor()
|
||||
local pos = vim.fn.screenpos(0, cursor[1], cursor[2] + 1)
|
||||
|
22
bundle/nvim-cmp/lua/cmp/utils/api_spec.lua
vendored
22
bundle/nvim-cmp/lua/cmp/utils/api_spec.lua
vendored
@ -4,8 +4,8 @@ local feedkeys = require('cmp.utils.feedkeys')
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
describe('api', function()
|
||||
before_each(spec.before)
|
||||
describe('get_cursor', function()
|
||||
before_each(spec.before)
|
||||
it('insert-mode', function()
|
||||
local cursor
|
||||
feedkeys.call(keymap.t('i\t1234567890'), 'nx', function()
|
||||
@ -24,8 +24,26 @@ describe('api', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_screen_cursor', function()
|
||||
it('insert-mode', function()
|
||||
local screen_cursor
|
||||
feedkeys.call(keymap.t('iあいうえお'), 'nx', function()
|
||||
screen_cursor = api.get_screen_cursor()
|
||||
end)
|
||||
assert.are.equal(10, screen_cursor[2])
|
||||
end)
|
||||
it('cmdline-mode', function()
|
||||
local screen_cursor
|
||||
keymap.set_map(0, 'c', '<Plug>(cmp-spec-spy)', function()
|
||||
screen_cursor = api.get_screen_cursor()
|
||||
end, { expr = true, noremap = true })
|
||||
feedkeys.call(keymap.t(':あいうえお'), 'n')
|
||||
feedkeys.call(keymap.t('<Plug>(cmp-spec-spy)'), 'x')
|
||||
assert.are.equal(10, screen_cursor[2])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('get_cursor_before_line', function()
|
||||
before_each(spec.before)
|
||||
it('insert-mode', function()
|
||||
local cursor_before_line
|
||||
feedkeys.call(keymap.t('i\t1234567890<Left><Left>'), 'nx', function()
|
||||
|
198
bundle/nvim-cmp/lua/cmp/utils/async.lua
vendored
198
bundle/nvim-cmp/lua/cmp/utils/async.lua
vendored
@ -1,18 +1,37 @@
|
||||
local feedkeys = require('cmp.utils.feedkeys')
|
||||
local config = require('cmp.config')
|
||||
|
||||
local async = {}
|
||||
|
||||
---@class cmp.AsyncThrottle
|
||||
---@field public running boolean
|
||||
---@field public timeout number
|
||||
---@field public sync function(self: cmp.AsyncThrottle, timeout: number|nil)
|
||||
---@field public timeout integer
|
||||
---@field public sync function(self: cmp.AsyncThrottle, timeout: integer|nil)
|
||||
---@field public stop function
|
||||
---@field public __call function
|
||||
|
||||
---@type uv_timer_t[]
|
||||
local timers = {}
|
||||
|
||||
vim.api.nvim_create_autocmd('VimLeavePre', {
|
||||
callback = function()
|
||||
for _, timer in pairs(timers) do
|
||||
if timer and not timer:is_closing() then
|
||||
timer:stop()
|
||||
timer:close()
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
---@param fn function
|
||||
---@param timeout number
|
||||
---@param timeout integer
|
||||
---@return cmp.AsyncThrottle
|
||||
async.throttle = function(fn, timeout)
|
||||
local time = nil
|
||||
local timer = vim.loop.new_timer()
|
||||
local timer = assert(vim.loop.new_timer())
|
||||
local _async = nil ---@type Async?
|
||||
timers[#timers + 1] = timer
|
||||
return setmetatable({
|
||||
running = false,
|
||||
timeout = timeout,
|
||||
@ -21,9 +40,15 @@ async.throttle = function(fn, timeout)
|
||||
return not self.running
|
||||
end)
|
||||
end,
|
||||
stop = function()
|
||||
time = nil
|
||||
stop = function(reset_time)
|
||||
if reset_time ~= false then
|
||||
time = nil
|
||||
end
|
||||
timer:stop()
|
||||
if _async then
|
||||
_async:cancel()
|
||||
_async = nil
|
||||
end
|
||||
end,
|
||||
}, {
|
||||
__call = function(self, ...)
|
||||
@ -34,12 +59,23 @@ async.throttle = function(fn, timeout)
|
||||
end
|
||||
|
||||
self.running = true
|
||||
timer:stop()
|
||||
self.stop(false)
|
||||
timer:start(math.max(1, self.timeout - (vim.loop.now() - time)), 0, function()
|
||||
vim.schedule(function()
|
||||
time = nil
|
||||
fn(unpack(args))
|
||||
self.running = false
|
||||
local ret = fn(unpack(args))
|
||||
if async.is_async(ret) then
|
||||
---@cast ret Async
|
||||
_async = ret
|
||||
_async:await(function(_, error)
|
||||
self.running = false
|
||||
if error and error ~= 'abort' then
|
||||
vim.notify(error, vim.log.levels.ERROR)
|
||||
end
|
||||
end)
|
||||
else
|
||||
self.running = false
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end,
|
||||
@ -60,7 +96,7 @@ end
|
||||
|
||||
---Timeout callback function
|
||||
---@param fn function
|
||||
---@param timeout number
|
||||
---@param timeout integer
|
||||
---@return function
|
||||
async.timeout = function(fn, timeout)
|
||||
local timer
|
||||
@ -109,4 +145,146 @@ async.sync = function(runner, timeout)
|
||||
end, 10, false)
|
||||
end
|
||||
|
||||
---Wait and callback for next safe state.
|
||||
async.debounce_next_tick = function(callback)
|
||||
local running = false
|
||||
return function()
|
||||
if running then
|
||||
return
|
||||
end
|
||||
running = true
|
||||
vim.schedule(function()
|
||||
running = false
|
||||
callback()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
---Wait and callback for consuming next keymap.
|
||||
async.debounce_next_tick_by_keymap = function(callback)
|
||||
return function()
|
||||
feedkeys.call('', '', callback)
|
||||
end
|
||||
end
|
||||
|
||||
local Scheduler = {}
|
||||
Scheduler._queue = {}
|
||||
Scheduler._executor = assert(vim.loop.new_check())
|
||||
|
||||
function Scheduler.step()
|
||||
local budget = config.get().performance.async_budget * 1e6
|
||||
local start = vim.loop.hrtime()
|
||||
while #Scheduler._queue > 0 and vim.loop.hrtime() - start < budget do
|
||||
local a = table.remove(Scheduler._queue, 1)
|
||||
a:_step()
|
||||
if a.running then
|
||||
table.insert(Scheduler._queue, a)
|
||||
end
|
||||
end
|
||||
if #Scheduler._queue == 0 then
|
||||
return Scheduler._executor:stop()
|
||||
end
|
||||
end
|
||||
|
||||
---@param a Async
|
||||
function Scheduler.add(a)
|
||||
table.insert(Scheduler._queue, a)
|
||||
if not Scheduler._executor:is_active() then
|
||||
Scheduler._executor:start(vim.schedule_wrap(Scheduler.step))
|
||||
end
|
||||
end
|
||||
|
||||
--- @alias AsyncCallback fun(result?:any, error?:string)
|
||||
|
||||
--- @class Async
|
||||
--- @field running boolean
|
||||
--- @field result? any
|
||||
--- @field error? string
|
||||
--- @field callbacks AsyncCallback[]
|
||||
--- @field thread thread
|
||||
local Async = {}
|
||||
Async.__index = Async
|
||||
|
||||
function Async.new(fn)
|
||||
local self = setmetatable({}, Async)
|
||||
self.callbacks = {}
|
||||
self.running = true
|
||||
self.thread = coroutine.create(fn)
|
||||
Scheduler.add(self)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param result? any
|
||||
---@param error? string
|
||||
function Async:_done(result, error)
|
||||
self.running = false
|
||||
self.result = result
|
||||
self.error = error
|
||||
for _, callback in ipairs(self.callbacks) do
|
||||
callback(result, error)
|
||||
end
|
||||
end
|
||||
|
||||
function Async:_step()
|
||||
local ok, res = coroutine.resume(self.thread)
|
||||
if not ok then
|
||||
return self:_done(nil, res)
|
||||
elseif res == 'abort' then
|
||||
return self:_done(nil, 'abort')
|
||||
elseif coroutine.status(self.thread) == 'dead' then
|
||||
return self:_done(res)
|
||||
end
|
||||
end
|
||||
|
||||
function Async:cancel()
|
||||
self.running = false
|
||||
end
|
||||
|
||||
---@param cb AsyncCallback
|
||||
function Async:await(cb)
|
||||
if not cb then
|
||||
error('callback is required')
|
||||
end
|
||||
if self.running then
|
||||
table.insert(self.callbacks, cb)
|
||||
else
|
||||
cb(self.result, self.error)
|
||||
end
|
||||
end
|
||||
|
||||
function Async:sync()
|
||||
while self.running do
|
||||
vim.wait(10)
|
||||
end
|
||||
return self.error and error(self.error) or self.result
|
||||
end
|
||||
|
||||
--- @return boolean
|
||||
function async.is_async(obj)
|
||||
return obj and type(obj) == 'table' and getmetatable(obj) == Async
|
||||
end
|
||||
|
||||
--- @return fun(...): Async
|
||||
function async.wrap(fn)
|
||||
return function(...)
|
||||
local args = { ... }
|
||||
return Async.new(function()
|
||||
return fn(unpack(args))
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- This will yield when called from a coroutine
|
||||
function async.yield(...)
|
||||
if not coroutine.isyieldable() then
|
||||
error('Trying to yield from a non-yieldable context')
|
||||
return ...
|
||||
end
|
||||
return coroutine.yield(...)
|
||||
end
|
||||
|
||||
function async.abort()
|
||||
return async.yield('abort')
|
||||
end
|
||||
|
||||
return async
|
||||
|
34
bundle/nvim-cmp/lua/cmp/utils/autocmd.lua
vendored
34
bundle/nvim-cmp/lua/cmp/utils/autocmd.lua
vendored
@ -2,20 +2,38 @@ local debug = require('cmp.utils.debug')
|
||||
|
||||
local autocmd = {}
|
||||
|
||||
autocmd.group = vim.api.nvim_create_augroup('___cmp___', { clear = true })
|
||||
|
||||
autocmd.events = {}
|
||||
|
||||
---Subscribe autocmd
|
||||
---@param event string
|
||||
---@param events string|string[]
|
||||
---@param callback function
|
||||
---@return function
|
||||
autocmd.subscribe = function(event, callback)
|
||||
autocmd.events[event] = autocmd.events[event] or {}
|
||||
table.insert(autocmd.events[event], callback)
|
||||
autocmd.subscribe = function(events, callback)
|
||||
events = type(events) == 'string' and { events } or events
|
||||
|
||||
for _, event in ipairs(events) do
|
||||
if not autocmd.events[event] then
|
||||
autocmd.events[event] = {}
|
||||
vim.api.nvim_create_autocmd(event, {
|
||||
desc = ('nvim-cmp: autocmd: %s'):format(event),
|
||||
group = autocmd.group,
|
||||
callback = function()
|
||||
autocmd.emit(event)
|
||||
end,
|
||||
})
|
||||
end
|
||||
table.insert(autocmd.events[event], callback)
|
||||
end
|
||||
|
||||
return function()
|
||||
for i, callback_ in ipairs(autocmd.events[event]) do
|
||||
if callback_ == callback then
|
||||
table.remove(autocmd.events[event], i)
|
||||
break
|
||||
for _, event in ipairs(events) do
|
||||
for i, callback_ in ipairs(autocmd.events[event]) do
|
||||
if callback_ == callback then
|
||||
table.remove(autocmd.events[event], i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
6
bundle/nvim-cmp/lua/cmp/utils/binary.lua
vendored
6
bundle/nvim-cmp/lua/cmp/utils/binary.lua
vendored
@ -3,7 +3,7 @@ local binary = {}
|
||||
---Insert item to list to ordered index
|
||||
---@param list any[]
|
||||
---@param item any
|
||||
---@param func fun(a: any, b: any): "1"|"-1"|"0"
|
||||
---@param func fun(a: any, b: any): 1|-1|0
|
||||
binary.insort = function(list, item, func)
|
||||
table.insert(list, binary.search(list, item, func), item)
|
||||
end
|
||||
@ -11,8 +11,8 @@ end
|
||||
---Search suitable index from list
|
||||
---@param list any[]
|
||||
---@param item any
|
||||
---@param func fun(a: any, b: any): "1"|"-1"|"0"
|
||||
---@return number
|
||||
---@param func fun(a: any, b: any): 1|-1|0
|
||||
---@return integer
|
||||
binary.search = function(list, item, func)
|
||||
local s = 1
|
||||
local e = #list
|
||||
|
6
bundle/nvim-cmp/lua/cmp/utils/buffer.lua
vendored
6
bundle/nvim-cmp/lua/cmp/utils/buffer.lua
vendored
@ -2,7 +2,7 @@ local buffer = {}
|
||||
|
||||
buffer.cache = {}
|
||||
|
||||
---@return number buf
|
||||
---@return integer buf
|
||||
buffer.get = function(name)
|
||||
local buf = buffer.cache[name]
|
||||
if buf and vim.api.nvim_buf_is_valid(buf) then
|
||||
@ -12,7 +12,7 @@ buffer.get = function(name)
|
||||
end
|
||||
end
|
||||
|
||||
---@return number buf
|
||||
---@return integer buf
|
||||
---@return boolean created_new
|
||||
buffer.ensure = function(name)
|
||||
local created_new = false
|
||||
@ -20,8 +20,6 @@ buffer.ensure = function(name)
|
||||
if not buf then
|
||||
created_new = true
|
||||
buf = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_option(buf, 'buftype', 'nofile')
|
||||
vim.api.nvim_buf_set_option(buf, 'bufhidden', 'hide')
|
||||
buffer.cache[name] = buf
|
||||
end
|
||||
return buf, created_new
|
||||
|
12
bundle/nvim-cmp/lua/cmp/utils/cache.lua
vendored
12
bundle/nvim-cmp/lua/cmp/utils/cache.lua
vendored
@ -9,7 +9,7 @@ cache.new = function()
|
||||
end
|
||||
|
||||
---Get cache value
|
||||
---@param key string
|
||||
---@param key string|string[]
|
||||
---@return any|nil
|
||||
cache.get = function(self, key)
|
||||
key = self:key(key)
|
||||
@ -20,7 +20,7 @@ cache.get = function(self, key)
|
||||
end
|
||||
|
||||
---Set cache value explicitly
|
||||
---@param key string
|
||||
---@param key string|string[]
|
||||
---@vararg any
|
||||
cache.set = function(self, key, value)
|
||||
key = self:key(key)
|
||||
@ -28,8 +28,10 @@ cache.set = function(self, key, value)
|
||||
end
|
||||
|
||||
---Ensure value by callback
|
||||
---@param key string
|
||||
---@param callback fun(): any
|
||||
---@generic T
|
||||
---@param key string|string[]
|
||||
---@param callback fun(): T
|
||||
---@return T
|
||||
cache.ensure = function(self, key, callback)
|
||||
local value = self:get(key)
|
||||
if value == nil then
|
||||
@ -46,7 +48,7 @@ cache.clear = function(self)
|
||||
end
|
||||
|
||||
---Create key
|
||||
---@param key string|table
|
||||
---@param key string|string[]
|
||||
---@return string
|
||||
cache.key = function(_, key)
|
||||
if type(key) == 'table' then
|
||||
|
34
bundle/nvim-cmp/lua/cmp/utils/char.lua
vendored
34
bundle/nvim-cmp/lua/cmp/utils/char.lua
vendored
@ -1,69 +1,71 @@
|
||||
local _
|
||||
|
||||
local alpha = {}
|
||||
string.gsub('abcdefghijklmnopqrstuvwxyz', '.', function(char)
|
||||
_ = string.gsub('abcdefghijklmnopqrstuvwxyz', '.', function(char)
|
||||
alpha[string.byte(char)] = true
|
||||
end)
|
||||
|
||||
local ALPHA = {}
|
||||
string.gsub('ABCDEFGHIJKLMNOPQRSTUVWXYZ', '.', function(char)
|
||||
_ = string.gsub('ABCDEFGHIJKLMNOPQRSTUVWXYZ', '.', function(char)
|
||||
ALPHA[string.byte(char)] = true
|
||||
end)
|
||||
|
||||
local digit = {}
|
||||
string.gsub('1234567890', '.', function(char)
|
||||
_ = string.gsub('1234567890', '.', function(char)
|
||||
digit[string.byte(char)] = true
|
||||
end)
|
||||
|
||||
local white = {}
|
||||
string.gsub(' \t\n', '.', function(char)
|
||||
_ = string.gsub(' \t\n', '.', function(char)
|
||||
white[string.byte(char)] = true
|
||||
end)
|
||||
|
||||
local char = {}
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_upper = function(byte)
|
||||
return ALPHA[byte]
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_alpha = function(byte)
|
||||
return alpha[byte] or ALPHA[byte]
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_digit = function(byte)
|
||||
return digit[byte]
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_white = function(byte)
|
||||
return white[byte]
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_symbol = function(byte)
|
||||
return not (char.is_alnum(byte) or char.is_white(byte))
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_printable = function(byte)
|
||||
return string.match(string.char(byte), '^%c$') == nil
|
||||
end
|
||||
|
||||
---@param byte number
|
||||
---@param byte integer
|
||||
---@return boolean
|
||||
char.is_alnum = function(byte)
|
||||
return char.is_alpha(byte) or char.is_digit(byte)
|
||||
end
|
||||
|
||||
---@param text string
|
||||
---@param index number
|
||||
---@param index integer
|
||||
---@return boolean
|
||||
char.is_semantic_index = function(text, index)
|
||||
if index <= 1 then
|
||||
@ -89,8 +91,8 @@ char.is_semantic_index = function(text, index)
|
||||
end
|
||||
|
||||
---@param text string
|
||||
---@param current_index number
|
||||
---@return boolean
|
||||
---@param current_index integer
|
||||
---@return integer
|
||||
char.get_next_semantic_index = function(text, current_index)
|
||||
for i = current_index + 1, #text do
|
||||
if char.is_semantic_index(text, i) then
|
||||
@ -101,8 +103,8 @@ char.get_next_semantic_index = function(text, current_index)
|
||||
end
|
||||
|
||||
---Ignore case match
|
||||
---@param byte1 number
|
||||
---@param byte2 number
|
||||
---@param byte1 integer
|
||||
---@param byte2 integer
|
||||
---@return boolean
|
||||
char.match = function(byte1, byte2)
|
||||
if not char.is_alpha(byte1) or not char.is_alpha(byte2) then
|
||||
|
69
bundle/nvim-cmp/lua/cmp/utils/feedkeys.lua
vendored
69
bundle/nvim-cmp/lua/cmp/utils/feedkeys.lua
vendored
@ -7,22 +7,18 @@ feedkeys.call = setmetatable({
|
||||
callbacks = {},
|
||||
}, {
|
||||
__call = function(self, keys, mode, callback)
|
||||
if vim.fn.reg_recording() ~= '' then
|
||||
return feedkeys.call_macro(keys, mode, callback)
|
||||
end
|
||||
|
||||
local is_insert = string.match(mode, 'i') ~= nil
|
||||
local is_immediate = string.match(mode, 'x') ~= nil
|
||||
|
||||
local queue = {}
|
||||
if #keys > 0 then
|
||||
table.insert(queue, { keymap.t('<Cmd>set lazyredraw<CR>'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>set textwidth=0<CR>'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>set eventignore=all<CR>'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal lazyredraw<CR>'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal textwidth=0<CR>'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal backspace=2<CR>'), 'n' })
|
||||
table.insert(queue, { keys, string.gsub(mode, '[itx]', ''), true })
|
||||
table.insert(queue, { keymap.t('<Cmd>set %slazyredraw<CR>'):format(vim.o.lazyredraw and '' or 'no'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>set textwidth=%s<CR>'):format(vim.bo.textwidth or 0), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>set eventignore=%s<CR>'):format(vim.o.eventignore or ''), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal %slazyredraw<CR>'):format(vim.o.lazyredraw and '' or 'no'), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal textwidth=%s<CR>'):format(vim.bo.textwidth or 0), 'n' })
|
||||
table.insert(queue, { keymap.t('<Cmd>setlocal backspace=%s<CR>'):format(vim.go.backspace or 2), 'n' })
|
||||
end
|
||||
|
||||
if callback then
|
||||
@ -54,57 +50,4 @@ misc.set(_G, { 'cmp', 'utils', 'feedkeys', 'call', 'run' }, function(id)
|
||||
return ''
|
||||
end)
|
||||
|
||||
feedkeys.call_macro = setmetatable({
|
||||
queue = {},
|
||||
current = nil,
|
||||
timer = vim.loop.new_timer(),
|
||||
running = false,
|
||||
}, {
|
||||
__call = function(self, keys, mode, callback)
|
||||
local is_insert = string.match(mode, 'i') ~= nil
|
||||
table.insert(self.queue, is_insert and 1 or #self.queue + 1, {
|
||||
keys = keys,
|
||||
mode = mode,
|
||||
callback = callback,
|
||||
})
|
||||
|
||||
if not self.running then
|
||||
self.running = true
|
||||
local consume
|
||||
consume = vim.schedule_wrap(function()
|
||||
if vim.fn.getchar(1) == 0 then
|
||||
if self.current then
|
||||
vim.cmd(('set backspace=%s'):format(self.current.backspace or ''))
|
||||
vim.cmd(('set eventignore=%s'):format(self.current.eventignore or ''))
|
||||
if self.current.callback then
|
||||
self.current.callback()
|
||||
end
|
||||
self.current = nil
|
||||
end
|
||||
|
||||
local current = table.remove(self.queue, 1)
|
||||
if current then
|
||||
self.current = {
|
||||
keys = current.keys,
|
||||
callback = current.callback,
|
||||
backspace = vim.o.backspace,
|
||||
eventignore = vim.o.eventignore,
|
||||
}
|
||||
vim.api.nvim_feedkeys(keymap.t('<Cmd>set backspace=start<CR>'), 'n', true)
|
||||
vim.api.nvim_feedkeys(keymap.t('<Cmd>set eventignore=all<CR>'), 'n', true)
|
||||
vim.api.nvim_feedkeys(current.keys, string.gsub(current.mode, '[i]', ''), true) -- 'i' flag is manually resolved.
|
||||
end
|
||||
end
|
||||
|
||||
if #self.queue ~= 0 or self.current then
|
||||
vim.defer_fn(consume, 1)
|
||||
else
|
||||
self.running = false
|
||||
end
|
||||
end)
|
||||
vim.defer_fn(consume, 1)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
return feedkeys
|
||||
|
@ -23,6 +23,15 @@ describe('feedkeys', function()
|
||||
})
|
||||
end)
|
||||
|
||||
it('bacckspace', function()
|
||||
vim.cmd([[setlocal backspace=0]])
|
||||
feedkeys.call(keymap.t('iaiueo'), 'nx')
|
||||
feedkeys.call(keymap.t('a<BS><BS>'), 'nx')
|
||||
assert.are.same(vim.api.nvim_buf_get_lines(0, 0, -1, false), {
|
||||
'aiu',
|
||||
})
|
||||
end)
|
||||
|
||||
it('testability', function()
|
||||
feedkeys.call('i', 'n', function()
|
||||
feedkeys.call('', 'n', function()
|
||||
|
53
bundle/nvim-cmp/lua/cmp/utils/highlight.lua
vendored
53
bundle/nvim-cmp/lua/cmp/utils/highlight.lua
vendored
@ -1,46 +1,31 @@
|
||||
local highlight = {}
|
||||
|
||||
highlight.keys = {
|
||||
'gui',
|
||||
'guifg',
|
||||
'guibg',
|
||||
'cterm',
|
||||
'ctermfg',
|
||||
'ctermbg',
|
||||
'fg',
|
||||
'bg',
|
||||
'bold',
|
||||
'italic',
|
||||
'reverse',
|
||||
'standout',
|
||||
'underline',
|
||||
'undercurl',
|
||||
'strikethrough',
|
||||
}
|
||||
|
||||
highlight.inherit = function(name, source, override)
|
||||
local cmd = ('highlight default %s'):format(name)
|
||||
highlight.inherit = function(name, source, settings)
|
||||
for _, key in ipairs(highlight.keys) do
|
||||
if override[key] then
|
||||
cmd = cmd .. (' %s=%s'):format(key, override[key])
|
||||
else
|
||||
local v = highlight.get(source, key)
|
||||
v = v == '' and 'NONE' or v
|
||||
cmd = cmd .. (' %s=%s'):format(key, v)
|
||||
end
|
||||
end
|
||||
vim.cmd(cmd)
|
||||
end
|
||||
|
||||
highlight.get = function(source, key)
|
||||
if key == 'gui' or key == 'cterm' then
|
||||
local ui = {}
|
||||
for _, k in ipairs({ 'bold', 'italic', 'reverse', 'inverse', 'standout', 'underline', 'undercurl', 'strikethrough' }) do
|
||||
if vim.fn.synIDattr(vim.fn.hlID(source), k, key) == 1 then
|
||||
table.insert(ui, k)
|
||||
if not settings[key] then
|
||||
local v = vim.fn.synIDattr(vim.fn.hlID(source), key)
|
||||
if key == 'fg' or key == 'bg' then
|
||||
local n = tonumber(v, 10)
|
||||
v = type(n) == 'number' and n or v
|
||||
else
|
||||
v = v == 1
|
||||
end
|
||||
settings[key] = v == '' and 'NONE' or v
|
||||
end
|
||||
return table.concat(ui, ',')
|
||||
elseif key == 'guifg' then
|
||||
return vim.fn.synIDattr(vim.fn.hlID(source), 'fg#', 'gui')
|
||||
elseif key == 'guibg' then
|
||||
return vim.fn.synIDattr(vim.fn.hlID(source), 'bg#', 'gui')
|
||||
elseif key == 'ctermfg' then
|
||||
return vim.fn.synIDattr(vim.fn.hlID(source), 'fg', 'term')
|
||||
elseif key == 'ctermbg' then
|
||||
return vim.fn.synIDattr(vim.fn.hlID(source), 'bg', 'term')
|
||||
end
|
||||
vim.api.nvim_set_hl(0, name, settings)
|
||||
end
|
||||
|
||||
return highlight
|
||||
|
106
bundle/nvim-cmp/lua/cmp/utils/keymap.lua
vendored
106
bundle/nvim-cmp/lua/cmp/utils/keymap.lua
vendored
@ -1,4 +1,5 @@
|
||||
local misc = require('cmp.utils.misc')
|
||||
local buffer = require('cmp.utils.buffer')
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
local keymap = {}
|
||||
@ -16,12 +17,16 @@ end
|
||||
---@param keys string
|
||||
---@return string
|
||||
keymap.normalize = function(keys)
|
||||
vim.api.nvim_set_keymap('t', '<Plug>(cmp.utils.keymap.normalize)', keys, {})
|
||||
for _, map in ipairs(vim.api.nvim_get_keymap('t')) do
|
||||
if keymap.equals(map.lhs, '<Plug>(cmp.utils.keymap.normalize)') then
|
||||
return map.rhs
|
||||
local normalize_buf = buffer.ensure('cmp.util.keymap.normalize')
|
||||
vim.api.nvim_buf_set_keymap(normalize_buf, 't', keys, '<Plug>(cmp.utils.keymap.normalize)', {})
|
||||
for _, map in ipairs(vim.api.nvim_buf_get_keymap(normalize_buf, 't')) do
|
||||
if keymap.t(map.rhs) == keymap.t('<Plug>(cmp.utils.keymap.normalize)') then
|
||||
vim.api.nvim_buf_del_keymap(normalize_buf, 't', keys)
|
||||
return map.lhs
|
||||
end
|
||||
end
|
||||
vim.api.nvim_buf_del_keymap(normalize_buf, 't', keys)
|
||||
vim.api.nvim_buf_delete(normalize_buf, {})
|
||||
return keys
|
||||
end
|
||||
|
||||
@ -64,7 +69,7 @@ keymap.undojoin = function()
|
||||
end
|
||||
|
||||
---Create backspace keys.
|
||||
---@param count number
|
||||
---@param count string|integer
|
||||
---@return string
|
||||
keymap.backspace = function(count)
|
||||
if type(count) == 'string' then
|
||||
@ -78,8 +83,23 @@ keymap.backspace = function(count)
|
||||
return table.concat(keys, '')
|
||||
end
|
||||
|
||||
---Create delete keys.
|
||||
---@param count string|integer
|
||||
---@return string
|
||||
keymap.delete = function(count)
|
||||
if type(count) == 'string' then
|
||||
count = vim.fn.strchars(count, true)
|
||||
end
|
||||
if count <= 0 then
|
||||
return ''
|
||||
end
|
||||
local keys = {}
|
||||
table.insert(keys, keymap.t(string.rep('<Del>', count)))
|
||||
return table.concat(keys, '')
|
||||
end
|
||||
|
||||
---Update indentkeys.
|
||||
---@param expr string
|
||||
---@param expr? string
|
||||
---@return string
|
||||
keymap.indentkeys = function(expr)
|
||||
return string.format(keymap.t('<Cmd>set indentkeys=%s<CR>'), expr and vim.fn.escape(expr, '| \t\\') or '')
|
||||
@ -90,7 +110,7 @@ end
|
||||
---@param b string
|
||||
---@return boolean
|
||||
keymap.equals = function(a, b)
|
||||
return keymap.t(a) == keymap.t(b)
|
||||
return keymap.normalize(a) == keymap.normalize(b)
|
||||
end
|
||||
|
||||
---Register keypress handler.
|
||||
@ -98,8 +118,7 @@ keymap.listen = function(mode, lhs, callback)
|
||||
lhs = keymap.normalize(keymap.to_keymap(lhs))
|
||||
|
||||
local existing = keymap.get_map(mode, lhs)
|
||||
local id = string.match(existing.rhs, 'v:lua%.cmp%.utils%.keymap%.set_map%((%d+)%)')
|
||||
if id and keymap.set_map.callbacks[tonumber(id, 10)] then
|
||||
if existing.desc == 'cmp.utils.keymap.set_map' then
|
||||
return
|
||||
end
|
||||
|
||||
@ -124,8 +143,8 @@ end
|
||||
keymap.fallback = function(bufnr, mode, map)
|
||||
return function()
|
||||
if map.expr then
|
||||
local fallback_expr = string.format('<Plug>(cmp.u.k.fallback_expr:%s)', map.lhs)
|
||||
keymap.set_map(bufnr, mode, fallback_expr, function()
|
||||
local fallback_lhs = string.format('<Plug>(cmp.u.k.fallback_expr:%s)', map.lhs)
|
||||
keymap.set_map(bufnr, mode, fallback_lhs, function()
|
||||
return keymap.solve(bufnr, mode, map).keys
|
||||
end, {
|
||||
expr = true,
|
||||
@ -133,13 +152,14 @@ keymap.fallback = function(bufnr, mode, map)
|
||||
script = map.script,
|
||||
nowait = map.nowait,
|
||||
silent = map.silent and mode ~= 'c',
|
||||
replace_keycodes = map.replace_keycodes,
|
||||
})
|
||||
vim.api.nvim_feedkeys(keymap.t(fallback_expr), 'im', true)
|
||||
elseif not map.callback then
|
||||
vim.api.nvim_feedkeys(keymap.t(fallback_lhs), 'im', true)
|
||||
elseif map.callback then
|
||||
map.callback()
|
||||
else
|
||||
local solved = keymap.solve(bufnr, mode, map)
|
||||
vim.api.nvim_feedkeys(solved.keys, solved.mode, true)
|
||||
else
|
||||
map.callback()
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -147,7 +167,14 @@ end
|
||||
---Solve
|
||||
keymap.solve = function(bufnr, mode, map)
|
||||
local lhs = keymap.t(map.lhs)
|
||||
local rhs = map.expr and (map.callback and map.callback() or vim.api.nvim_eval(keymap.t(map.rhs))) or keymap.t(map.rhs)
|
||||
local rhs = keymap.t(map.rhs)
|
||||
if map.expr then
|
||||
if map.callback then
|
||||
rhs = map.callback()
|
||||
else
|
||||
rhs = vim.api.nvim_eval(keymap.t(map.rhs))
|
||||
end
|
||||
end
|
||||
|
||||
if map.noremap then
|
||||
return { keys = rhs, mode = 'in' }
|
||||
@ -157,9 +184,10 @@ keymap.solve = function(bufnr, mode, map)
|
||||
local recursive = string.format('<SNR>0_(cmp.u.k.recursive:%s)', lhs)
|
||||
keymap.set_map(bufnr, mode, recursive, lhs, {
|
||||
noremap = true,
|
||||
script = map.script,
|
||||
script = true,
|
||||
nowait = map.nowait,
|
||||
silent = map.silent and mode ~= 'c',
|
||||
replace_keycodes = map.replace_keycodes,
|
||||
})
|
||||
return { keys = keymap.t(recursive) .. string.gsub(rhs, '^' .. vim.pesc(lhs), ''), mode = 'im' }
|
||||
end
|
||||
@ -180,11 +208,13 @@ keymap.get_map = function(mode, lhs)
|
||||
rhs = map.rhs or '',
|
||||
expr = map.expr == 1,
|
||||
callback = map.callback,
|
||||
desc = map.desc,
|
||||
noremap = map.noremap == 1,
|
||||
script = map.script == 1,
|
||||
silent = map.silent == 1,
|
||||
nowait = map.nowait == 1,
|
||||
buffer = true,
|
||||
replace_keycodes = map.replace_keycodes == 1,
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -196,11 +226,13 @@ keymap.get_map = function(mode, lhs)
|
||||
rhs = map.rhs or '',
|
||||
expr = map.expr == 1,
|
||||
callback = map.callback,
|
||||
desc = map.desc,
|
||||
noremap = map.noremap == 1,
|
||||
script = map.script == 1,
|
||||
silent = map.silent == 1,
|
||||
nowait = map.nowait == 1,
|
||||
buffer = false,
|
||||
replace_keycodes = map.replace_keycodes == 1,
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -215,33 +247,27 @@ keymap.get_map = function(mode, lhs)
|
||||
silent = true,
|
||||
nowait = false,
|
||||
buffer = false,
|
||||
replace_keycodes = true,
|
||||
}
|
||||
end
|
||||
|
||||
---Set keymapping
|
||||
keymap.set_map = setmetatable({
|
||||
callbacks = {},
|
||||
}, {
|
||||
__call = function(self, bufnr, mode, lhs, rhs, opts)
|
||||
if type(rhs) == 'function' then
|
||||
local id = misc.id('cmp.utils.keymap.set_map')
|
||||
self.callbacks[id] = rhs
|
||||
if opts.expr then
|
||||
rhs = ('v:lua.cmp.utils.keymap.set_map(%s)'):format(id)
|
||||
else
|
||||
rhs = ('<Cmd>call v:lua.cmp.utils.keymap.set_map(%s)<CR>'):format(id)
|
||||
end
|
||||
end
|
||||
keymap.set_map = function(bufnr, mode, lhs, rhs, opts)
|
||||
if type(rhs) == 'function' then
|
||||
opts.callback = rhs
|
||||
rhs = ''
|
||||
end
|
||||
opts.desc = 'cmp.utils.keymap.set_map'
|
||||
|
||||
if bufnr == -1 then
|
||||
vim.api.nvim_set_keymap(mode, lhs, rhs, opts)
|
||||
else
|
||||
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)
|
||||
end
|
||||
end,
|
||||
})
|
||||
misc.set(_G, { 'cmp', 'utils', 'keymap', 'set_map' }, function(id)
|
||||
return keymap.set_map.callbacks[id]() or ''
|
||||
end)
|
||||
if vim.fn.has('nvim-0.8') == 0 then
|
||||
opts.replace_keycodes = nil
|
||||
end
|
||||
|
||||
if bufnr == -1 then
|
||||
vim.api.nvim_set_keymap(mode, lhs, rhs, opts)
|
||||
else
|
||||
vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts)
|
||||
end
|
||||
end
|
||||
|
||||
return keymap
|
||||
|
100
bundle/nvim-cmp/lua/cmp/utils/misc.lua
vendored
100
bundle/nvim-cmp/lua/cmp/utils/misc.lua
vendored
@ -29,6 +29,24 @@ misc.concat = function(list1, list2)
|
||||
return new_list
|
||||
end
|
||||
|
||||
---Repeat values
|
||||
---@generic T
|
||||
---@param str_or_tbl T
|
||||
---@param count integer
|
||||
---@return T
|
||||
misc.rep = function(str_or_tbl, count)
|
||||
if type(str_or_tbl) == 'string' then
|
||||
return string.rep(str_or_tbl, count)
|
||||
end
|
||||
local rep = {}
|
||||
for _ = 1, count do
|
||||
for _, v in ipairs(str_or_tbl) do
|
||||
table.insert(rep, v)
|
||||
end
|
||||
end
|
||||
return rep
|
||||
end
|
||||
|
||||
---Return the valu is empty or not.
|
||||
---@param v any
|
||||
---@return boolean
|
||||
@ -56,42 +74,38 @@ misc.none = vim.NIL
|
||||
|
||||
---Merge two tables recursively
|
||||
---@generic T
|
||||
---@param v1 T
|
||||
---@param v2 T
|
||||
---@param tbl1 T
|
||||
---@param tbl2 T
|
||||
---@return T
|
||||
misc.merge = function(v1, v2)
|
||||
local merge1 = type(v1) == 'table' and (not vim.tbl_islist(v1) or vim.tbl_isempty(v1))
|
||||
local merge2 = type(v2) == 'table' and (not vim.tbl_islist(v2) or vim.tbl_isempty(v2))
|
||||
if merge1 and merge2 then
|
||||
misc.merge = function(tbl1, tbl2)
|
||||
local is_dict1 = type(tbl1) == 'table' and (not vim.tbl_islist(tbl1) or vim.tbl_isempty(tbl1))
|
||||
local is_dict2 = type(tbl2) == 'table' and (not vim.tbl_islist(tbl2) or vim.tbl_isempty(tbl2))
|
||||
if is_dict1 and is_dict2 then
|
||||
local new_tbl = {}
|
||||
for k, v in pairs(v2) do
|
||||
new_tbl[k] = misc.merge(v1[k], v)
|
||||
for k, v in pairs(tbl2) do
|
||||
if tbl1[k] ~= misc.none then
|
||||
new_tbl[k] = misc.merge(tbl1[k], v)
|
||||
end
|
||||
end
|
||||
for k, v in pairs(v1) do
|
||||
if v2[k] == nil and v ~= misc.none then
|
||||
new_tbl[k] = v
|
||||
for k, v in pairs(tbl1) do
|
||||
if tbl2[k] == nil then
|
||||
if v ~= misc.none then
|
||||
new_tbl[k] = misc.merge(v, {})
|
||||
else
|
||||
new_tbl[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return new_tbl
|
||||
end
|
||||
if v1 == misc.none then
|
||||
return nil
|
||||
end
|
||||
if v1 == nil then
|
||||
if v2 == misc.none then
|
||||
return nil
|
||||
else
|
||||
return v2
|
||||
end
|
||||
end
|
||||
if v1 == true then
|
||||
if merge2 then
|
||||
return v2
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
return v1
|
||||
if tbl1 == misc.none then
|
||||
return nil
|
||||
elseif tbl1 == nil then
|
||||
return misc.merge(tbl2, {})
|
||||
else
|
||||
return tbl1
|
||||
end
|
||||
end
|
||||
|
||||
---Generate id for group name
|
||||
@ -105,22 +119,12 @@ misc.id = setmetatable({
|
||||
end,
|
||||
})
|
||||
|
||||
---Check the value is nil or not.
|
||||
---@param v boolean
|
||||
---@return boolean
|
||||
misc.safe = function(v)
|
||||
if v == nil or v == vim.NIL then
|
||||
return nil
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
---Treat 1/0 as bool value
|
||||
---@param v boolean|"1"|"0"
|
||||
---@param v boolean|1|0
|
||||
---@param def boolean
|
||||
---@return boolean
|
||||
misc.bool = function(v, def)
|
||||
if misc.safe(v) == nil then
|
||||
if v == nil then
|
||||
return def
|
||||
end
|
||||
return v == true or v == 1
|
||||
@ -134,7 +138,7 @@ misc.set = function(t, keys, v)
|
||||
local c = t
|
||||
for i = 1, #keys - 1 do
|
||||
local key = keys[i]
|
||||
c[key] = misc.safe(c[key]) or {}
|
||||
c[key] = c[key] or {}
|
||||
c = c[key]
|
||||
end
|
||||
c[keys[#keys]] = v
|
||||
@ -166,8 +170,8 @@ end
|
||||
|
||||
---Safe version of vim.str_utfindex
|
||||
---@param text string
|
||||
---@param vimindex number|nil
|
||||
---@return number
|
||||
---@param vimindex integer|nil
|
||||
---@return integer
|
||||
misc.to_utfindex = function(text, vimindex)
|
||||
vimindex = vimindex or #text + 1
|
||||
return vim.str_utfindex(text, math.max(0, math.min(vimindex - 1, #text)))
|
||||
@ -175,8 +179,8 @@ end
|
||||
|
||||
---Safe version of vim.str_byteindex
|
||||
---@param text string
|
||||
---@param utfindex number
|
||||
---@return number
|
||||
---@param utfindex integer
|
||||
---@return integer
|
||||
misc.to_vimindex = function(text, utfindex)
|
||||
utfindex = utfindex or #text
|
||||
for i = utfindex, 1, -1 do
|
||||
@ -206,12 +210,14 @@ end
|
||||
misc.redraw = setmetatable({
|
||||
doing = false,
|
||||
force = false,
|
||||
termcode = vim.api.nvim_replace_termcodes('<C-r><Esc>', true, true, true),
|
||||
-- We use `<Up><Down>` to redraw the screen. (Previously, We use <C-r><ESC>. it will remove the unmatches search history.)
|
||||
incsearch_redraw_keys = ' <BS>',
|
||||
}, {
|
||||
__call = function(self, force)
|
||||
local termcode = vim.api.nvim_replace_termcodes(self.incsearch_redraw_keys, true, true, true)
|
||||
if vim.tbl_contains({ '/', '?' }, vim.fn.getcmdtype()) then
|
||||
if vim.o.incsearch then
|
||||
return vim.api.nvim_feedkeys(self.termcode, 'in', true)
|
||||
return vim.api.nvim_feedkeys(termcode, 'ni', true)
|
||||
end
|
||||
end
|
||||
|
||||
|
12
bundle/nvim-cmp/lua/cmp/utils/misc_spec.lua
vendored
12
bundle/nvim-cmp/lua/cmp/utils/misc_spec.lua
vendored
@ -16,6 +16,18 @@ describe('misc', function()
|
||||
})
|
||||
assert.are.equal(merged.a.b, 1)
|
||||
|
||||
merged = misc.merge({
|
||||
a = {
|
||||
i = 1,
|
||||
},
|
||||
}, {
|
||||
a = {
|
||||
c = 2,
|
||||
},
|
||||
})
|
||||
assert.are.equal(merged.a.i, 1)
|
||||
assert.are.equal(merged.a.c, 2)
|
||||
|
||||
merged = misc.merge({
|
||||
a = false,
|
||||
}, {
|
||||
|
25
bundle/nvim-cmp/lua/cmp/utils/options.lua
vendored
Normal file
25
bundle/nvim-cmp/lua/cmp/utils/options.lua
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
local M = {}
|
||||
|
||||
-- Set window option without triggering the OptionSet event
|
||||
---@param window number
|
||||
---@param name string
|
||||
---@param value any
|
||||
M.win_set_option = function(window, name, value)
|
||||
local eventignore = vim.opt.eventignore:get()
|
||||
vim.opt.eventignore:append('OptionSet')
|
||||
vim.api.nvim_win_set_option(window, name, value)
|
||||
vim.opt.eventignore = eventignore
|
||||
end
|
||||
|
||||
-- Set buffer option without triggering the OptionSet event
|
||||
---@param buffer number
|
||||
---@param name string
|
||||
---@param value any
|
||||
M.buf_set_option = function(buffer, name, value)
|
||||
local eventignore = vim.opt.eventignore:get()
|
||||
vim.opt.eventignore:append('OptionSet')
|
||||
vim.api.nvim_buf_set_option(buffer, name, value)
|
||||
vim.opt.eventignore = eventignore
|
||||
end
|
||||
|
||||
return M
|
22
bundle/nvim-cmp/lua/cmp/utils/str.lua
vendored
22
bundle/nvim-cmp/lua/cmp/utils/str.lua
vendored
@ -1,5 +1,4 @@
|
||||
local char = require('cmp.utils.char')
|
||||
local pattern = require('cmp.utils.pattern')
|
||||
|
||||
local str = {}
|
||||
|
||||
@ -73,23 +72,6 @@ str.remove_suffix = function(text, suffix)
|
||||
return string.sub(text, 1, -#suffix - 1)
|
||||
end
|
||||
|
||||
---strikethrough
|
||||
---@param text string
|
||||
---@return string
|
||||
str.strikethrough = function(text)
|
||||
local r = pattern.regex('.')
|
||||
local buffer = ''
|
||||
while text ~= '' do
|
||||
local s, e = r:match_str(text)
|
||||
if not s then
|
||||
break
|
||||
end
|
||||
buffer = buffer .. string.sub(text, s, e) .. '̶'
|
||||
text = string.sub(text, e + 1)
|
||||
end
|
||||
return buffer
|
||||
end
|
||||
|
||||
---trim
|
||||
---@param text string
|
||||
---@return string
|
||||
@ -117,8 +99,8 @@ end
|
||||
|
||||
---get_word
|
||||
---@param text string
|
||||
---@param stop_char number
|
||||
---@param min_length number
|
||||
---@param stop_char integer
|
||||
---@param min_length integer
|
||||
---@return string
|
||||
str.get_word = function(text, stop_char, min_length)
|
||||
min_length = min_length or 0
|
||||
|
4
bundle/nvim-cmp/lua/cmp/utils/str_spec.lua
vendored
4
bundle/nvim-cmp/lua/cmp/utils/str_spec.lua
vendored
@ -12,10 +12,6 @@ describe('utils.str', function()
|
||||
assert.are.equal(str.get_word('import { GetStaticProps$1 } from "next";', nil, 9), 'import { GetStaticProps')
|
||||
end)
|
||||
|
||||
it('strikethrough', function()
|
||||
assert.are.equal(str.strikethrough('あいうえお'), 'あ̶い̶う̶え̶お̶')
|
||||
end)
|
||||
|
||||
it('remove_suffix', function()
|
||||
assert.are.equal(str.remove_suffix('log()', '$0'), 'log()')
|
||||
assert.are.equal(str.remove_suffix('log()$0', '$0'), 'log()')
|
||||
|
288
bundle/nvim-cmp/lua/cmp/utils/window.lua
vendored
288
bundle/nvim-cmp/lua/cmp/utils/window.lua
vendored
@ -1,25 +1,26 @@
|
||||
local cache = require('cmp.utils.cache')
|
||||
local misc = require('cmp.utils.misc')
|
||||
local opt = require('cmp.utils.options')
|
||||
local buffer = require('cmp.utils.buffer')
|
||||
local api = require('cmp.utils.api')
|
||||
local config = require('cmp.config')
|
||||
|
||||
---@class cmp.WindowStyle
|
||||
---@field public relative string
|
||||
---@field public row number
|
||||
---@field public col number
|
||||
---@field public width number
|
||||
---@field public height number
|
||||
---@field public zindex number|nil
|
||||
---@field public row integer
|
||||
---@field public col integer
|
||||
---@field public width integer|float
|
||||
---@field public height integer|float
|
||||
---@field public border string|string[]|nil
|
||||
---@field public zindex integer|nil
|
||||
|
||||
---@class cmp.Window
|
||||
---@field public name string
|
||||
---@field public win number|nil
|
||||
---@field public swin1 number|nil
|
||||
---@field public swin2 number|nil
|
||||
---@field public win integer|nil
|
||||
---@field public thumb_win integer|nil
|
||||
---@field public sbar_win integer|nil
|
||||
---@field public style cmp.WindowStyle
|
||||
---@field public opt table<string, any>
|
||||
---@field public buffer_opt table<string, any>
|
||||
---@field public cache cmp.Cache
|
||||
local window = {}
|
||||
|
||||
---new
|
||||
@ -28,10 +29,9 @@ window.new = function()
|
||||
local self = setmetatable({}, { __index = window })
|
||||
self.name = misc.id('cmp.utils.window.new')
|
||||
self.win = nil
|
||||
self.swin1 = nil
|
||||
self.swin2 = nil
|
||||
self.sbar_win = nil
|
||||
self.thumb_win = nil
|
||||
self.style = {}
|
||||
self.cache = cache.new()
|
||||
self.opt = {}
|
||||
self.buffer_opt = {}
|
||||
return self
|
||||
@ -52,7 +52,7 @@ window.option = function(self, key, value)
|
||||
|
||||
self.opt[key] = value
|
||||
if self:visible() then
|
||||
vim.api.nvim_win_set_option(self.win, key, value)
|
||||
opt.win_set_option(self.win, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
@ -72,30 +72,35 @@ window.buffer_option = function(self, key, value)
|
||||
self.buffer_opt[key] = value
|
||||
local existing_buf = buffer.get(self.name)
|
||||
if existing_buf then
|
||||
vim.api.nvim_buf_set_option(existing_buf, key, value)
|
||||
opt.buf_set_option(existing_buf, key, value)
|
||||
end
|
||||
end
|
||||
|
||||
---Set style.
|
||||
---@param style cmp.WindowStyle
|
||||
window.set_style = function(self, style)
|
||||
if vim.o.columns and vim.o.columns <= style.col + style.width then
|
||||
style.width = vim.o.columns - style.col - 1
|
||||
end
|
||||
if vim.o.lines and vim.o.lines <= style.row + style.height then
|
||||
style.height = vim.o.lines - style.row - 1
|
||||
end
|
||||
self.style = style
|
||||
local info = self:info()
|
||||
|
||||
if vim.o.lines and vim.o.lines <= info.row + info.height + 1 then
|
||||
self.style.height = vim.o.lines - info.row - info.border_info.vert - 1
|
||||
end
|
||||
|
||||
self.style.zindex = self.style.zindex or 1
|
||||
|
||||
--- GUI clients are allowed to return fractional bounds, but we need integer
|
||||
--- bounds to open the window
|
||||
self.style.width = math.ceil(self.style.width)
|
||||
self.style.height = math.ceil(self.style.height)
|
||||
end
|
||||
|
||||
---Return buffer id.
|
||||
---@return number
|
||||
---@return integer
|
||||
window.get_buffer = function(self)
|
||||
local buf, created_new = buffer.ensure(self.name)
|
||||
if created_new then
|
||||
for k, v in pairs(self.buffer_opt) do
|
||||
vim.api.nvim_buf_set_option(buf, k, v)
|
||||
opt.buf_set_option(buf, k, v)
|
||||
end
|
||||
end
|
||||
return buf
|
||||
@ -119,7 +124,7 @@ window.open = function(self, style)
|
||||
s.noautocmd = true
|
||||
self.win = vim.api.nvim_open_win(self:get_buffer(), false, s)
|
||||
for k, v in pairs(self.opt) do
|
||||
vim.api.nvim_win_set_option(self.win, k, v)
|
||||
opt.win_set_option(self.win, k, v)
|
||||
end
|
||||
end
|
||||
self:update()
|
||||
@ -127,49 +132,57 @@ end
|
||||
|
||||
---Update
|
||||
window.update = function(self)
|
||||
if self:has_scrollbar() then
|
||||
local total = self:get_content_height()
|
||||
local info = self:info()
|
||||
local bar_height = math.ceil(info.height * (info.height / total))
|
||||
local bar_offset = math.min(info.height - bar_height, math.floor(info.height * (vim.fn.getwininfo(self.win)[1].topline / total)))
|
||||
local style1 = {}
|
||||
style1.relative = 'editor'
|
||||
style1.style = 'minimal'
|
||||
style1.width = 1
|
||||
style1.height = info.height
|
||||
style1.row = info.row
|
||||
style1.col = info.col + info.width - (info.has_scrollbar and 1 or 0)
|
||||
style1.zindex = (self.style.zindex and (self.style.zindex + 1) or 1)
|
||||
if self.swin1 and vim.api.nvim_win_is_valid(self.swin1) then
|
||||
vim.api.nvim_win_set_config(self.swin1, style1)
|
||||
else
|
||||
style1.noautocmd = true
|
||||
self.swin1 = vim.api.nvim_open_win(buffer.ensure(self.name .. 'sbuf1'), false, style1)
|
||||
vim.api.nvim_win_set_option(self.swin1, 'winhighlight', 'EndOfBuffer:PmenuSbar,Normal:PmenuSbar,NormalNC:PmenuSbar,NormalFloat:PmenuSbar')
|
||||
local info = self:info()
|
||||
if info.scrollable then
|
||||
-- Draw the background of the scrollbar
|
||||
|
||||
if not info.border_info.visible then
|
||||
local style = {
|
||||
relative = 'editor',
|
||||
style = 'minimal',
|
||||
width = 1,
|
||||
height = self.style.height,
|
||||
row = info.row,
|
||||
col = info.col + info.width - info.scrollbar_offset, -- info.col was already contained the scrollbar offset.
|
||||
zindex = (self.style.zindex and (self.style.zindex + 1) or 1),
|
||||
}
|
||||
if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then
|
||||
vim.api.nvim_win_set_config(self.sbar_win, style)
|
||||
else
|
||||
style.noautocmd = true
|
||||
self.sbar_win = vim.api.nvim_open_win(buffer.ensure(self.name .. 'sbar_buf'), false, style)
|
||||
opt.win_set_option(self.sbar_win, 'winhighlight', 'EndOfBuffer:PmenuSbar,NormalFloat:PmenuSbar')
|
||||
end
|
||||
end
|
||||
local style2 = {}
|
||||
style2.relative = 'editor'
|
||||
style2.style = 'minimal'
|
||||
style2.width = 1
|
||||
style2.height = bar_height
|
||||
style2.row = info.row + bar_offset
|
||||
style2.col = info.col + info.width - (info.has_scrollbar and 1 or 0)
|
||||
style2.zindex = (self.style.zindex and (self.style.zindex + 2) or 2)
|
||||
if self.swin2 and vim.api.nvim_win_is_valid(self.swin2) then
|
||||
vim.api.nvim_win_set_config(self.swin2, style2)
|
||||
|
||||
-- Draw the scrollbar thumb
|
||||
local thumb_height = math.floor(info.inner_height * (info.inner_height / self:get_content_height()) + 0.5)
|
||||
local thumb_offset = math.floor(info.inner_height * (vim.fn.getwininfo(self.win)[1].topline / self:get_content_height()))
|
||||
|
||||
local style = {
|
||||
relative = 'editor',
|
||||
style = 'minimal',
|
||||
width = 1,
|
||||
height = math.max(1, thumb_height),
|
||||
row = info.row + thumb_offset + (info.border_info.visible and info.border_info.top or 0),
|
||||
col = info.col + info.width - 1, -- info.col was already added scrollbar offset.
|
||||
zindex = (self.style.zindex and (self.style.zindex + 2) or 2),
|
||||
}
|
||||
if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then
|
||||
vim.api.nvim_win_set_config(self.thumb_win, style)
|
||||
else
|
||||
style2.noautocmd = true
|
||||
self.swin2 = vim.api.nvim_open_win(buffer.ensure(self.name .. 'sbuf2'), false, style2)
|
||||
vim.api.nvim_win_set_option(self.swin2, 'winhighlight', 'EndOfBuffer:PmenuThumb,Normal:PmenuThumb,NormalNC:PmenuThumb,NormalFloat:PmenuThumb')
|
||||
style.noautocmd = true
|
||||
self.thumb_win = vim.api.nvim_open_win(buffer.ensure(self.name .. 'thumb_buf'), false, style)
|
||||
opt.win_set_option(self.thumb_win, 'winhighlight', 'EndOfBuffer:PmenuThumb,NormalFloat:PmenuThumb')
|
||||
end
|
||||
else
|
||||
if self.swin1 and vim.api.nvim_win_is_valid(self.swin1) then
|
||||
vim.api.nvim_win_hide(self.swin1)
|
||||
self.swin1 = nil
|
||||
if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then
|
||||
vim.api.nvim_win_hide(self.sbar_win)
|
||||
self.sbar_win = nil
|
||||
end
|
||||
if self.swin2 and vim.api.nvim_win_is_valid(self.swin2) then
|
||||
vim.api.nvim_win_hide(self.swin2)
|
||||
self.swin2 = nil
|
||||
if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then
|
||||
vim.api.nvim_win_hide(self.thumb_win)
|
||||
self.thumb_win = nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -188,13 +201,13 @@ window.close = function(self)
|
||||
vim.api.nvim_win_hide(self.win)
|
||||
self.win = nil
|
||||
end
|
||||
if self.swin1 and vim.api.nvim_win_is_valid(self.swin1) then
|
||||
vim.api.nvim_win_hide(self.swin1)
|
||||
self.swin1 = nil
|
||||
if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then
|
||||
vim.api.nvim_win_hide(self.sbar_win)
|
||||
self.sbar_win = nil
|
||||
end
|
||||
if self.swin2 and vim.api.nvim_win_is_valid(self.swin2) then
|
||||
vim.api.nvim_win_hide(self.swin2)
|
||||
self.swin2 = nil
|
||||
if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then
|
||||
vim.api.nvim_win_hide(self.thumb_win)
|
||||
self.thumb_win = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -204,91 +217,102 @@ window.visible = function(self)
|
||||
return self.win and vim.api.nvim_win_is_valid(self.win)
|
||||
end
|
||||
|
||||
---Return the scrollbar will shown or not.
|
||||
window.has_scrollbar = function(self)
|
||||
return (self.style.height or 0) < self:get_content_height()
|
||||
end
|
||||
|
||||
---Return win info.
|
||||
window.info = function(self)
|
||||
local border_width = self:get_border_width()
|
||||
local has_scrollbar = self:has_scrollbar()
|
||||
return {
|
||||
local border_info = self:get_border_info()
|
||||
local scrollbar = config.get().window.completion.scrollbar
|
||||
local info = {
|
||||
row = self.style.row,
|
||||
col = self.style.col,
|
||||
width = self.style.width + border_width + (has_scrollbar and 1 or 0),
|
||||
height = self.style.height,
|
||||
border_width = border_width,
|
||||
has_scrollbar = has_scrollbar,
|
||||
width = self.style.width + border_info.left + border_info.right,
|
||||
height = self.style.height + border_info.top + border_info.bottom,
|
||||
inner_width = self.style.width,
|
||||
inner_height = self.style.height,
|
||||
border_info = border_info,
|
||||
scrollable = false,
|
||||
scrollbar_offset = 0,
|
||||
}
|
||||
|
||||
if self:get_content_height() > info.inner_height and scrollbar then
|
||||
info.scrollable = true
|
||||
if not border_info.visible then
|
||||
info.scrollbar_offset = 1
|
||||
info.width = info.width + 1
|
||||
end
|
||||
end
|
||||
|
||||
return info
|
||||
end
|
||||
|
||||
---Get border width
|
||||
---@return number
|
||||
window.get_border_width = function(self)
|
||||
---Return border information.
|
||||
---@return { top: integer, left: integer, right: integer, bottom: integer, vert: integer, horiz: integer, visible: boolean }
|
||||
window.get_border_info = function(self)
|
||||
local border = self.style.border
|
||||
if type(border) == 'table' then
|
||||
local new_border = {}
|
||||
while #new_border < 8 do
|
||||
for _, b in ipairs(border) do
|
||||
table.insert(new_border, b)
|
||||
end
|
||||
if not border or border == 'none' then
|
||||
return {
|
||||
top = 0,
|
||||
left = 0,
|
||||
right = 0,
|
||||
bottom = 0,
|
||||
vert = 0,
|
||||
horiz = 0,
|
||||
visible = false,
|
||||
}
|
||||
end
|
||||
if type(border) == 'string' then
|
||||
if border == 'shadow' then
|
||||
return {
|
||||
top = 0,
|
||||
left = 0,
|
||||
right = 1,
|
||||
bottom = 1,
|
||||
vert = 1,
|
||||
horiz = 1,
|
||||
visible = false,
|
||||
}
|
||||
end
|
||||
border = new_border
|
||||
return {
|
||||
top = 1,
|
||||
left = 1,
|
||||
right = 1,
|
||||
bottom = 1,
|
||||
vert = 2,
|
||||
horiz = 2,
|
||||
visible = true,
|
||||
}
|
||||
end
|
||||
|
||||
local w = 0
|
||||
if border then
|
||||
if type(border) == 'string' then
|
||||
if border == 'single' then
|
||||
w = 2
|
||||
elseif border == 'solid' then
|
||||
w = 2
|
||||
elseif border == 'double' then
|
||||
w = 2
|
||||
elseif border == 'rounded' then
|
||||
w = 2
|
||||
elseif border == 'shadow' then
|
||||
w = 1
|
||||
end
|
||||
elseif type(border) == 'table' then
|
||||
local b4 = type(border[4]) == 'table' and border[4][1] or border[4]
|
||||
if #b4 > 0 then
|
||||
w = w + 1
|
||||
end
|
||||
local b8 = type(border[8]) == 'table' and border[8][1] or border[8]
|
||||
if #b8 > 0 then
|
||||
w = w + 1
|
||||
end
|
||||
local new_border = {}
|
||||
while #new_border <= 8 do
|
||||
for _, b in ipairs(border) do
|
||||
table.insert(new_border, type(b) == 'string' and b or b[1])
|
||||
end
|
||||
end
|
||||
return w
|
||||
local info = {}
|
||||
info.top = new_border[2] == '' and 0 or 1
|
||||
info.right = new_border[4] == '' and 0 or 1
|
||||
info.bottom = new_border[6] == '' and 0 or 1
|
||||
info.left = new_border[8] == '' and 0 or 1
|
||||
info.vert = info.top + info.bottom
|
||||
info.horiz = info.left + info.right
|
||||
info.visible = not (vim.tbl_contains({ '', ' ' }, new_border[2]) and vim.tbl_contains({ '', ' ' }, new_border[4]) and vim.tbl_contains({ '', ' ' }, new_border[6]) and vim.tbl_contains({ '', ' ' }, new_border[8]))
|
||||
return info
|
||||
end
|
||||
|
||||
---Get scroll height.
|
||||
---@return number
|
||||
---NOTE: The result of vim.fn.strdisplaywidth depends on the buffer it was called in (see comment in cmp.Entry.get_view).
|
||||
---@return integer
|
||||
window.get_content_height = function(self)
|
||||
if not self:option('wrap') then
|
||||
return vim.api.nvim_buf_line_count(self:get_buffer())
|
||||
end
|
||||
|
||||
return self.cache:ensure({
|
||||
'get_content_height',
|
||||
self.style.width,
|
||||
self:get_buffer(),
|
||||
vim.api.nvim_buf_get_changedtick(self:get_buffer()),
|
||||
}, function()
|
||||
local height = 0
|
||||
local buf = self:get_buffer()
|
||||
-- The result of vim.fn.strdisplaywidth depends on the buffer it was called
|
||||
-- in (see comment in cmp.Entry.get_view).
|
||||
vim.api.nvim_buf_call(buf, function()
|
||||
for _, text in ipairs(vim.api.nvim_buf_get_lines(buf, 0, -1, false)) do
|
||||
height = height + math.ceil(math.max(1, vim.fn.strdisplaywidth(text)) / self.style.width)
|
||||
end
|
||||
end)
|
||||
return height
|
||||
local height = 0
|
||||
vim.api.nvim_buf_call(self:get_buffer(), function()
|
||||
for _, text in ipairs(vim.api.nvim_buf_get_lines(self:get_buffer(), 0, -1, false)) do
|
||||
height = height + math.max(1, math.ceil(vim.fn.strdisplaywidth(text) / self.style.width))
|
||||
end
|
||||
end)
|
||||
return height
|
||||
end
|
||||
|
||||
return window
|
||||
|
15
bundle/nvim-cmp/lua/cmp/view.lua
vendored
15
bundle/nvim-cmp/lua/cmp/view.lua
vendored
@ -47,6 +47,7 @@ end
|
||||
---Open menu
|
||||
---@param ctx cmp.Context
|
||||
---@param sources cmp.Source[]
|
||||
---@return boolean did_open
|
||||
view.open = function(self, ctx, sources)
|
||||
local source_group_map = {}
|
||||
for _, s in ipairs(sources) do
|
||||
@ -104,10 +105,15 @@ view.open = function(self, ctx, sources)
|
||||
end
|
||||
end
|
||||
end)
|
||||
local max_item_count = config.get().performance.max_view_entries or 200
|
||||
entries = vim.list_slice(entries, 1, max_item_count)
|
||||
|
||||
-- open
|
||||
if #entries > 0 then
|
||||
self:_get_entries_view():open(offset, entries)
|
||||
self.event:emit('menu_opened', {
|
||||
window = self:_get_entries_view(),
|
||||
})
|
||||
break
|
||||
end
|
||||
end
|
||||
@ -116,6 +122,7 @@ view.open = function(self, ctx, sources)
|
||||
if #entries == 0 then
|
||||
self:close()
|
||||
end
|
||||
return #entries > 0
|
||||
end
|
||||
|
||||
---Close menu
|
||||
@ -128,6 +135,9 @@ view.close = function(self)
|
||||
self:_get_entries_view():close()
|
||||
self.docs_view:close()
|
||||
self.ghost_text_view:hide()
|
||||
self.event:emit('menu_closed', {
|
||||
window = self:_get_entries_view(),
|
||||
})
|
||||
end
|
||||
|
||||
---Abort menu
|
||||
@ -135,6 +145,9 @@ view.abort = function(self)
|
||||
self:_get_entries_view():abort()
|
||||
self.docs_view:close()
|
||||
self.ghost_text_view:hide()
|
||||
self.event:emit('menu_closed', {
|
||||
window = self:_get_entries_view(),
|
||||
})
|
||||
end
|
||||
|
||||
---Return the view is visible or not.
|
||||
@ -144,7 +157,7 @@ view.visible = function(self)
|
||||
end
|
||||
|
||||
---Scroll documentation window if possible.
|
||||
---@param delta number
|
||||
---@param delta integer
|
||||
view.scroll_docs = function(self, delta)
|
||||
self.docs_view:scroll(delta)
|
||||
end
|
||||
|
163
bundle/nvim-cmp/lua/cmp/view/custom_entries_view.lua
vendored
163
bundle/nvim-cmp/lua/cmp/view/custom_entries_view.lua
vendored
@ -8,13 +8,11 @@ local keymap = require('cmp.utils.keymap')
|
||||
local misc = require('cmp.utils.misc')
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
local SIDE_PADDING = 1
|
||||
|
||||
local DEFAULT_HEIGHT = 10 -- @see https://github.com/vim/vim/blob/master/src/popupmenu.c#L45
|
||||
|
||||
---@class cmp.CustomEntriesView
|
||||
---@field private entries_win cmp.Window
|
||||
---@field private offset number
|
||||
---@field private offset integer
|
||||
---@field private active boolean
|
||||
---@field private entries cmp.Entry[]
|
||||
---@field private column_width any
|
||||
@ -25,20 +23,21 @@ custom_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.custom_entries_
|
||||
|
||||
custom_entries_view.new = function()
|
||||
local self = setmetatable({}, { __index = custom_entries_view })
|
||||
|
||||
self.entries_win = window.new()
|
||||
self.entries_win:option('conceallevel', 2)
|
||||
self.entries_win:option('concealcursor', 'n')
|
||||
self.entries_win:option('cursorlineopt', 'line')
|
||||
self.entries_win:option('foldenable', false)
|
||||
self.entries_win:option('wrap', false)
|
||||
self.entries_win:option('scrolloff', 0)
|
||||
self.entries_win:option('winhighlight', 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None')
|
||||
-- This is done so that strdisplaywidth calculations for lines in the
|
||||
-- custom_entries_view window exactly match with what is really displayed,
|
||||
-- see comment in cmp.Entry.get_view. Setting tabstop to 1 makes all tabs be
|
||||
-- always rendered one column wide, which removes the unpredictability coming
|
||||
-- from variable width of the tab character.
|
||||
self.entries_win:buffer_option('tabstop', 1)
|
||||
self.entries_win:buffer_option('filetype', 'cmp_menu')
|
||||
self.entries_win:buffer_option('buftype', 'nofile')
|
||||
self.event = event.new()
|
||||
self.offset = -1
|
||||
self.active = false
|
||||
@ -65,7 +64,7 @@ custom_entries_view.new = function()
|
||||
local e = self.entries[i + 1]
|
||||
if e then
|
||||
local v = e:get_view(self.offset, buf)
|
||||
local o = SIDE_PADDING
|
||||
local o = config.get().window.completion.side_padding
|
||||
local a = 0
|
||||
for _, field in ipairs(fields) do
|
||||
if field == types.cmp.ItemField.Abbr then
|
||||
@ -118,17 +117,15 @@ custom_entries_view.is_direction_top_down = function(self)
|
||||
end
|
||||
|
||||
custom_entries_view.open = function(self, offset, entries)
|
||||
local completion = config.get().window.completion
|
||||
self.offset = offset
|
||||
self.entries = {}
|
||||
self.column_width = { abbr = 0, kind = 0, menu = 0 }
|
||||
|
||||
-- Apply window options (that might be changed) on the custom completion menu.
|
||||
self.entries_win:option('winblend', vim.o.pumblend)
|
||||
|
||||
local entries_buf = self.entries_win:get_buffer()
|
||||
local lines = {}
|
||||
local dedup = {}
|
||||
local preselect = 0
|
||||
local preselect_index = 0
|
||||
for _, e in ipairs(entries) do
|
||||
local view = e:get_view(offset, entries_buf)
|
||||
if view.dup == 1 or not dedup[e.completion_item.label] then
|
||||
@ -138,8 +135,8 @@ custom_entries_view.open = function(self, offset, entries)
|
||||
self.column_width.menu = math.max(self.column_width.menu, view.menu.width)
|
||||
table.insert(self.entries, e)
|
||||
table.insert(lines, ' ')
|
||||
if preselect == 0 and e.completion_item.preselect then
|
||||
preselect = #self.entries
|
||||
if preselect_index == 0 and e.completion_item.preselect then
|
||||
preselect_index = #self.entries
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -157,18 +154,26 @@ custom_entries_view.open = function(self, offset, entries)
|
||||
height = math.min(height, #self.entries)
|
||||
|
||||
local pos = api.get_screen_cursor()
|
||||
local cursor = api.get_cursor()
|
||||
local delta = cursor[2] + 1 - self.offset
|
||||
local has_bottom_space = (vim.o.lines - pos[1]) >= DEFAULT_HEIGHT
|
||||
local cursor_before_line = api.get_cursor_before_line()
|
||||
local delta = vim.fn.strdisplaywidth(cursor_before_line:sub(self.offset))
|
||||
local row, col = pos[1], pos[2] - delta - 1
|
||||
|
||||
if not has_bottom_space and math.floor(vim.o.lines * 0.5) <= row and vim.o.lines - row <= height then
|
||||
local border_info = window.get_border_info({ style = completion })
|
||||
local border_offset_row = border_info.top + border_info.bottom
|
||||
local border_offset_col = border_info.left + border_info.right
|
||||
if math.floor(vim.o.lines * 0.5) <= row + border_offset_row and vim.o.lines - row - border_offset_row <= math.min(DEFAULT_HEIGHT, height) then
|
||||
height = math.min(height, row - 1)
|
||||
row = row - height - 1
|
||||
row = row - height - border_offset_row - 1
|
||||
if row < 0 then
|
||||
height = height + row
|
||||
end
|
||||
end
|
||||
if math.floor(vim.o.columns * 0.5) <= col and vim.o.columns - col <= width then
|
||||
if math.floor(vim.o.columns * 0.5) <= col + border_offset_col and vim.o.columns - col - border_offset_col <= width then
|
||||
width = math.min(width, vim.o.columns - 1)
|
||||
col = vim.o.columns - width - 1
|
||||
col = vim.o.columns - width - border_offset_col - 1
|
||||
if col < 0 then
|
||||
width = width + col
|
||||
end
|
||||
end
|
||||
|
||||
if pos[1] > row then
|
||||
@ -182,35 +187,40 @@ custom_entries_view.open = function(self, offset, entries)
|
||||
for i = 1, math.floor(n / 2) do
|
||||
self.entries[i], self.entries[n - i + 1] = self.entries[n - i + 1], self.entries[i]
|
||||
end
|
||||
if preselect ~= 0 then
|
||||
preselect = #self.entries - preselect + 1
|
||||
if preselect_index ~= 0 then
|
||||
preselect_index = #self.entries - preselect_index + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply window options (that might be changed) on the custom completion menu.
|
||||
self.entries_win:option('winblend', vim.o.pumblend)
|
||||
self.entries_win:option('winhighlight', completion.winhighlight)
|
||||
self.entries_win:option('scrolloff', completion.scrolloff)
|
||||
self.entries_win:open({
|
||||
relative = 'editor',
|
||||
style = 'minimal',
|
||||
row = math.max(0, row),
|
||||
col = math.max(0, col),
|
||||
col = math.max(0, col + completion.col_offset),
|
||||
width = width,
|
||||
height = height,
|
||||
zindex = 1001,
|
||||
border = completion.border,
|
||||
zindex = completion.zindex or 1001,
|
||||
})
|
||||
-- always set cursor when starting. It will be adjusted on the call to _select
|
||||
vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 0 })
|
||||
if preselect > 0 and config.get().preselect == types.cmp.PreselectMode.Item then
|
||||
self:_select(preselect, { behavior = types.cmp.SelectBehavior.Select })
|
||||
if preselect_index > 0 and config.get().preselect == types.cmp.PreselectMode.Item then
|
||||
self:_select(preselect_index, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
||||
elseif not string.match(config.get().completion.completeopt, 'noselect') then
|
||||
if self:is_direction_top_down() then
|
||||
self:_select(1, { behavior = types.cmp.SelectBehavior.Select })
|
||||
self:_select(1, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
||||
else
|
||||
self:_select(#self.entries - 1, { behavior = types.cmp.SelectBehavior.Select })
|
||||
self:_select(#self.entries, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
||||
end
|
||||
else
|
||||
if self:is_direction_top_down() then
|
||||
self:_select(0, { behavior = types.cmp.SelectBehavior.Select })
|
||||
self:_select(0, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
||||
else
|
||||
self:_select(#self.entries + 1, { behavior = types.cmp.SelectBehavior.Select })
|
||||
self:_select(#self.entries + 1, { behavior = types.cmp.SelectBehavior.Select, active = false })
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -245,12 +255,12 @@ custom_entries_view.draw = function(self)
|
||||
if e then
|
||||
local view = e:get_view(self.offset, entries_buf)
|
||||
local text = {}
|
||||
table.insert(text, string.rep(' ', SIDE_PADDING))
|
||||
table.insert(text, string.rep(' ', config.get().window.completion.side_padding))
|
||||
for _, field in ipairs(fields) do
|
||||
table.insert(text, view[field].text)
|
||||
table.insert(text, string.rep(' ', 1 + self.column_width[field] - view[field].width))
|
||||
end
|
||||
table.insert(text, string.rep(' ', SIDE_PADDING))
|
||||
table.insert(text, string.rep(' ', config.get().window.completion.side_padding))
|
||||
table.insert(texts, table.concat(text, ''))
|
||||
end
|
||||
end
|
||||
@ -275,34 +285,74 @@ end
|
||||
custom_entries_view.select_next_item = function(self, option)
|
||||
if self:visible() then
|
||||
local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1]
|
||||
if self:is_direction_top_down() then
|
||||
cursor = cursor + 1
|
||||
else
|
||||
cursor = cursor - 1
|
||||
end
|
||||
local is_top_down = self:is_direction_top_down()
|
||||
local last = #self.entries
|
||||
|
||||
if not self.entries_win:option('cursorline') then
|
||||
cursor = (self:is_direction_top_down() and 1) or #self.entries
|
||||
elseif #self.entries < cursor then
|
||||
cursor = (not self:is_direction_top_down() and #self.entries + 1) or 0
|
||||
cursor = (is_top_down and 1) or last
|
||||
else
|
||||
if is_top_down then
|
||||
if cursor == last then
|
||||
cursor = 0
|
||||
else
|
||||
cursor = cursor + option.count
|
||||
if last < cursor then
|
||||
cursor = last
|
||||
end
|
||||
end
|
||||
else
|
||||
if cursor == 0 then
|
||||
cursor = last
|
||||
else
|
||||
cursor = cursor - option.count
|
||||
if cursor < 0 then
|
||||
cursor = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:_select(cursor, option)
|
||||
|
||||
self:_select(cursor, {
|
||||
behavior = option.behavior or types.cmp.SelectBehavior.Insert,
|
||||
active = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
custom_entries_view.select_prev_item = function(self, option)
|
||||
if self:visible() then
|
||||
local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1]
|
||||
if self:is_direction_top_down() then
|
||||
cursor = cursor - 1
|
||||
else
|
||||
cursor = cursor + 1
|
||||
end
|
||||
local is_top_down = self:is_direction_top_down()
|
||||
local last = #self.entries
|
||||
|
||||
if not self.entries_win:option('cursorline') then
|
||||
cursor = (self:is_direction_top_down() and #self.entries) or 1
|
||||
elseif #self.entries < cursor then
|
||||
cursor = (not self:is_direction_top_down() and 0) or #self.entries + 1
|
||||
cursor = (is_top_down and last) or 1
|
||||
else
|
||||
if is_top_down then
|
||||
if cursor == 1 then
|
||||
cursor = 0
|
||||
else
|
||||
cursor = cursor - option.count
|
||||
if cursor < 0 then
|
||||
cursor = 1
|
||||
end
|
||||
end
|
||||
else
|
||||
if cursor == last then
|
||||
cursor = 0
|
||||
else
|
||||
cursor = cursor + option.count
|
||||
if last < cursor then
|
||||
cursor = last
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:_select(cursor, option)
|
||||
|
||||
self:_select(cursor, {
|
||||
behavior = option.behavior or types.cmp.SelectBehavior.Insert,
|
||||
active = true,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@ -343,10 +393,9 @@ custom_entries_view._select = function(self, cursor, option)
|
||||
if is_insert and not self.active then
|
||||
self.prefix = string.sub(api.get_current_line(), self.offset, api.get_cursor()[2]) or ''
|
||||
end
|
||||
self.active = (0 < cursor and cursor <= #self.entries and option.active == true)
|
||||
|
||||
self.active = cursor > 0 and cursor <= #self.entries and is_insert
|
||||
self.entries_win:option('cursorline', cursor > 0 and cursor <= #self.entries)
|
||||
|
||||
vim.api.nvim_win_set_cursor(self.entries_win.win, {
|
||||
math.max(math.min(cursor, #self.entries), 1),
|
||||
0,
|
||||
@ -368,7 +417,17 @@ custom_entries_view._insert = setmetatable({
|
||||
word = word or ''
|
||||
if api.is_cmdline_mode() then
|
||||
local cursor = api.get_cursor()
|
||||
vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true)
|
||||
-- setcmdline() added in v0.8.0
|
||||
if vim.fn.has('nvim-0.8') == 1 then
|
||||
local current_line = api.get_current_line()
|
||||
local before_line = current_line:sub(1, self.offset - 1)
|
||||
local after_line = current_line:sub(cursor[2] + 1)
|
||||
local pos = #before_line + #word + 1
|
||||
vim.fn.setcmdline(before_line .. word .. after_line, pos)
|
||||
vim.api.nvim_feedkeys(keymap.t('<Cmd>redraw<CR>'), 'ni', false)
|
||||
else
|
||||
vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true)
|
||||
end
|
||||
else
|
||||
if this.pending then
|
||||
return
|
||||
|
46
bundle/nvim-cmp/lua/cmp/view/docs_view.lua
vendored
46
bundle/nvim-cmp/lua/cmp/view/docs_view.lua
vendored
@ -15,7 +15,10 @@ docs_view.new = function()
|
||||
self.window:option('foldenable', false)
|
||||
self.window:option('linebreak', true)
|
||||
self.window:option('scrolloff', 0)
|
||||
self.window:option('showbreak', 'NONE')
|
||||
self.window:option('wrap', true)
|
||||
self.window:buffer_option('filetype', 'cmp_docs')
|
||||
self.window:buffer_option('buftype', 'nofile')
|
||||
return self
|
||||
end
|
||||
|
||||
@ -23,7 +26,7 @@ end
|
||||
---@param e cmp.Entry
|
||||
---@param view cmp.WindowStyle
|
||||
docs_view.open = function(self, e, view)
|
||||
local documentation = config.get().documentation
|
||||
local documentation = config.get().window.documentation
|
||||
if not documentation then
|
||||
return
|
||||
end
|
||||
@ -32,11 +35,12 @@ docs_view.open = function(self, e, view)
|
||||
return self:close()
|
||||
end
|
||||
|
||||
local right_space = vim.o.columns - (view.col + view.width) - 2
|
||||
local left_space = view.col - 2
|
||||
local maxwidth = math.min(documentation.maxwidth, math.max(left_space, right_space) - 1)
|
||||
local border_info = window.get_border_info({ style = documentation })
|
||||
local right_space = vim.o.columns - (view.col + view.width) - 1
|
||||
local left_space = view.col - 1
|
||||
local max_width = math.min(documentation.max_width, math.max(left_space, right_space))
|
||||
|
||||
-- update buffer content if needed.
|
||||
-- Update buffer content if needed.
|
||||
if not self.entry or e.id ~= self.entry.id then
|
||||
local documents = e:get_documentation()
|
||||
if #documents == 0 then
|
||||
@ -46,24 +50,29 @@ docs_view.open = function(self, e, view)
|
||||
self.entry = e
|
||||
vim.api.nvim_buf_call(self.window:get_buffer(), function()
|
||||
vim.cmd([[syntax clear]])
|
||||
vim.api.nvim_buf_set_lines(self.window:get_buffer(), 0, -1, false, {})
|
||||
end)
|
||||
vim.lsp.util.stylize_markdown(self.window:get_buffer(), documents, {
|
||||
max_width = maxwidth,
|
||||
max_height = documentation.maxheight,
|
||||
max_width = max_width - border_info.horiz,
|
||||
max_height = documentation.max_height,
|
||||
})
|
||||
end
|
||||
|
||||
-- Set buffer as not modified, so it can be removed without errors
|
||||
vim.api.nvim_buf_set_option(self.window:get_buffer(), 'modified', false)
|
||||
|
||||
-- Calculate window size.
|
||||
local width, height = vim.lsp.util._make_floating_popup_size(vim.api.nvim_buf_get_lines(self.window:get_buffer(), 0, -1, false), {
|
||||
max_width = maxwidth,
|
||||
max_height = documentation.maxheight,
|
||||
max_width = max_width - border_info.horiz,
|
||||
max_height = documentation.max_height - border_info.vert,
|
||||
})
|
||||
if width <= 0 or height <= 0 then
|
||||
return self:close()
|
||||
end
|
||||
|
||||
-- Calculate window position.
|
||||
local right_col = view.col + view.width
|
||||
local left_col = view.col - width - 2
|
||||
|
||||
local left_col = view.col - width - border_info.horiz
|
||||
local col, left
|
||||
if right_space >= width and left_space >= width then
|
||||
if right_space < left_space then
|
||||
@ -81,8 +90,10 @@ docs_view.open = function(self, e, view)
|
||||
return self:close()
|
||||
end
|
||||
|
||||
-- Render window.
|
||||
self.window:option('winblend', vim.o.pumblend)
|
||||
self.window:option('winhighlight', documentation.winhighlight)
|
||||
self.window:set_style({
|
||||
local style = {
|
||||
relative = 'editor',
|
||||
style = 'minimal',
|
||||
width = width,
|
||||
@ -91,11 +102,14 @@ docs_view.open = function(self, e, view)
|
||||
col = col,
|
||||
border = documentation.border,
|
||||
zindex = documentation.zindex or 50,
|
||||
})
|
||||
if left and self.window:has_scrollbar() then
|
||||
self.window.style.col = self.window.style.col - 1
|
||||
}
|
||||
self.window:open(style)
|
||||
|
||||
-- Correct left-col for scrollbar existence.
|
||||
if left then
|
||||
style.col = style.col - self.window:info().scrollbar_offset
|
||||
self.window:open(style)
|
||||
end
|
||||
self.window:open()
|
||||
end
|
||||
|
||||
---Close floating window
|
||||
|
32
bundle/nvim-cmp/lua/cmp/view/ghost_text_view.lua
vendored
32
bundle/nvim-cmp/lua/cmp/view/ghost_text_view.lua
vendored
@ -9,6 +9,18 @@ local ghost_text_view = {}
|
||||
|
||||
ghost_text_view.ns = vim.api.nvim_create_namespace('cmp:GHOST_TEXT')
|
||||
|
||||
local has_inline = (function()
|
||||
return (pcall(function()
|
||||
local id = vim.api.nvim_buf_set_extmark(0, ghost_text_view.ns, 0, 0, {
|
||||
virt_text = { { ' ', 'Comment' } },
|
||||
virt_text_pos = 'inline',
|
||||
hl_mode = 'combine',
|
||||
ephemeral = true,
|
||||
})
|
||||
vim.api.nvim_buf_del_extmark(0, ghost_text_view.ns, id)
|
||||
end))
|
||||
end)()
|
||||
|
||||
ghost_text_view.new = function()
|
||||
local self = setmetatable({}, { __index = ghost_text_view })
|
||||
self.win = nil
|
||||
@ -17,7 +29,7 @@ ghost_text_view.new = function()
|
||||
on_win = function(_, win)
|
||||
return win == self.win
|
||||
end,
|
||||
on_line = function(_)
|
||||
on_line = function(_, _, _, on_row)
|
||||
local c = config.get().experimental.ghost_text
|
||||
if not c then
|
||||
return
|
||||
@ -28,17 +40,23 @@ ghost_text_view.new = function()
|
||||
end
|
||||
|
||||
local row, col = unpack(vim.api.nvim_win_get_cursor(0))
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
if string.sub(line, col + 1) ~= '' then
|
||||
if on_row ~= row - 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
if not has_inline then
|
||||
if string.sub(line, col + 1) ~= '' then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local text = self.text_gen(self, line, col)
|
||||
if #text > 0 then
|
||||
vim.api.nvim_buf_set_extmark(0, ghost_text_view.ns, row - 1, col, {
|
||||
right_gravity = false,
|
||||
virt_text = { { text, c.hl_group or 'Comment' } },
|
||||
virt_text_pos = 'overlay',
|
||||
virt_text = { { text, type(c) == 'table' and c.hl_group or 'Comment' } },
|
||||
virt_text_pos = has_inline and 'inline' or 'overlay',
|
||||
hl_mode = 'combine',
|
||||
ephemeral = true,
|
||||
})
|
||||
@ -78,6 +96,10 @@ ghost_text_view.show = function(self, e)
|
||||
if not api.is_insert_mode() then
|
||||
return
|
||||
end
|
||||
local c = config.get().experimental.ghost_text
|
||||
if not c then
|
||||
return
|
||||
end
|
||||
local changed = e ~= self.entry
|
||||
self.win = vim.api.nvim_get_current_win()
|
||||
self.entry = e
|
||||
|
@ -7,10 +7,10 @@ local config = require('cmp.config')
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
---@class cmp.NativeEntriesView
|
||||
---@field private offset number
|
||||
---@field private offset integer
|
||||
---@field private items vim.CompletedItem
|
||||
---@field private entries cmp.Entry[]
|
||||
---@field private preselect_index number
|
||||
---@field private preselect_index integer
|
||||
---@field public event cmp.Event
|
||||
local native_entries_view = {}
|
||||
|
||||
@ -77,8 +77,7 @@ native_entries_view.open = function(self, offset, entries)
|
||||
end
|
||||
|
||||
native_entries_view.close = function(self)
|
||||
if api.is_suitable_mode() and self:visible() then
|
||||
vim.fn.complete(1, {})
|
||||
if api.is_insert_mode() and self:visible() then
|
||||
vim.api.nvim_select_popupmenu_item(-1, false, true, {})
|
||||
end
|
||||
self.offset = -1
|
||||
@ -101,10 +100,10 @@ native_entries_view.info = function(self)
|
||||
if self:visible() then
|
||||
local info = vim.fn.pum_getpos()
|
||||
return {
|
||||
width = info.width + (info.scrollbar and 1 or 0),
|
||||
width = info.width + (info.scrollbar and 1 or 0) + (info.col == 0 and 0 or 1),
|
||||
height = info.height,
|
||||
row = info.row,
|
||||
col = info.col,
|
||||
col = info.col == 0 and 0 or info.col - 1,
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -123,9 +122,9 @@ native_entries_view.select_next_item = function(self, option)
|
||||
end
|
||||
if self:visible() then
|
||||
if (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t('<C-n>'), 'n', callback)
|
||||
feedkeys.call(keymap.t(string.rep('<C-n>', option.count)), 'n', callback)
|
||||
else
|
||||
feedkeys.call(keymap.t('<Down>'), 'n', callback)
|
||||
feedkeys.call(keymap.t(string.rep('<Down>', option.count)), 'n', callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -136,9 +135,9 @@ native_entries_view.select_prev_item = function(self, option)
|
||||
end
|
||||
if self:visible() then
|
||||
if (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert then
|
||||
feedkeys.call(keymap.t('<C-p>'), 'n', callback)
|
||||
feedkeys.call(keymap.t(string.rep('<C-p>', option.count)), 'n', callback)
|
||||
else
|
||||
feedkeys.call(keymap.t('<Up>'), 'n', callback)
|
||||
feedkeys.call(keymap.t(string.rep('<Up>', option.count)), 'n', callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -9,7 +9,7 @@ local misc = require('cmp.utils.misc')
|
||||
local api = require('cmp.utils.api')
|
||||
|
||||
---@class cmp.CustomEntriesView
|
||||
---@field private offset number
|
||||
---@field private offset integer
|
||||
---@field private entries_win cmp.Window
|
||||
---@field private active boolean
|
||||
---@field private entries cmp.Entry[]
|
||||
@ -181,11 +181,14 @@ end
|
||||
|
||||
wildmenu_entries_view.select_next_item = function(self, option)
|
||||
if self:visible() then
|
||||
local cursor
|
||||
if self.selected_index == 0 or self.selected_index == #self.entries then
|
||||
self:_select(1, option)
|
||||
cursor = option.count
|
||||
else
|
||||
self:_select(self.selected_index + 1, option)
|
||||
cursor = self.selected_index + option.count
|
||||
end
|
||||
cursor = math.max(math.min(cursor, #self.entries), 0)
|
||||
self:_select(cursor, option)
|
||||
end
|
||||
end
|
||||
|
||||
@ -194,7 +197,7 @@ wildmenu_entries_view.select_prev_item = function(self, option)
|
||||
if self.selected_index == 0 or self.selected_index <= 1 then
|
||||
self:_select(#self.entries, option)
|
||||
else
|
||||
self:_select(self.selected_index - 1, option)
|
||||
self:_select(math.max(self.selected_index - option.count, 0), option)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
6
bundle/nvim-cmp/lua/cmp/vim_source.lua
vendored
6
bundle/nvim-cmp/lua/cmp/vim_source.lua
vendored
@ -2,7 +2,7 @@ local misc = require('cmp.utils.misc')
|
||||
|
||||
local vim_source = {}
|
||||
|
||||
---@param id number
|
||||
---@param id integer
|
||||
---@param args any[]
|
||||
vim_source.on_callback = function(id, args)
|
||||
if vim_source.to_callback.callbacks[id] then
|
||||
@ -11,7 +11,7 @@ vim_source.on_callback = function(id, args)
|
||||
end
|
||||
|
||||
---@param callback function
|
||||
---@return number
|
||||
---@return integer
|
||||
vim_source.to_callback = setmetatable({
|
||||
callbacks = {},
|
||||
}, {
|
||||
@ -36,7 +36,7 @@ vim_source.to_args = function(args)
|
||||
return args
|
||||
end
|
||||
|
||||
---@param bridge_id number
|
||||
---@param bridge_id integer
|
||||
---@param methods string[]
|
||||
vim_source.new = function(bridge_id, methods)
|
||||
local self = {}
|
||||
|
31
bundle/nvim-cmp/nvim-cmp-scm-1.rockspec
vendored
Normal file
31
bundle/nvim-cmp/nvim-cmp-scm-1.rockspec
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
local MODREV, SPECREV = 'scm', '-1'
|
||||
rockspec_format = '3.0'
|
||||
package = 'nvim-cmp'
|
||||
version = MODREV .. SPECREV
|
||||
|
||||
description = {
|
||||
summary = 'A completion plugin for neovim',
|
||||
labels = { 'neovim' },
|
||||
detailed = [[
|
||||
A completion engine plugin for neovim written in Lua. Completion sources are installed from external repositories and "sourced".
|
||||
]],
|
||||
homepage = 'https://github.com/hrsh7th/nvim-cmp',
|
||||
license = 'MIT',
|
||||
}
|
||||
|
||||
dependencies = {
|
||||
'lua >= 5.1, < 5.4',
|
||||
}
|
||||
|
||||
source = {
|
||||
url = 'git://github.com/hrsh7th/nvim-cmp',
|
||||
}
|
||||
|
||||
build = {
|
||||
type = 'builtin',
|
||||
copy_directories = {
|
||||
'autoload',
|
||||
'plugin',
|
||||
'doc'
|
||||
}
|
||||
}
|
147
bundle/nvim-cmp/plugin/cmp.lua
vendored
147
bundle/nvim-cmp/plugin/cmp.lua
vendored
@ -3,140 +3,57 @@ if vim.g.loaded_cmp then
|
||||
end
|
||||
vim.g.loaded_cmp = true
|
||||
|
||||
local api = require "cmp.utils.api"
|
||||
local misc = require('cmp.utils.misc')
|
||||
if not vim.api.nvim_create_autocmd then
|
||||
return print('[nvim-cmp] Your nvim does not has `nvim_create_autocmd` function. Please update to latest nvim.')
|
||||
end
|
||||
|
||||
local api = require('cmp.utils.api')
|
||||
local types = require('cmp.types')
|
||||
local config = require('cmp.config')
|
||||
local highlight = require('cmp.utils.highlight')
|
||||
local autocmd = require('cmp.utils.autocmd')
|
||||
|
||||
-- TODO: https://github.com/neovim/neovim/pull/14661
|
||||
vim.cmd [[
|
||||
augroup ___cmp___
|
||||
autocmd!
|
||||
autocmd InsertEnter * lua require'cmp.utils.autocmd'.emit('InsertEnter')
|
||||
autocmd InsertLeave * lua require'cmp.utils.autocmd'.emit('InsertLeave')
|
||||
autocmd TextChangedI,TextChangedP * lua require'cmp.utils.autocmd'.emit('TextChanged')
|
||||
autocmd CursorMovedI * lua require'cmp.utils.autocmd'.emit('CursorMoved')
|
||||
autocmd CompleteChanged * lua require'cmp.utils.autocmd'.emit('CompleteChanged')
|
||||
autocmd CompleteDone * lua require'cmp.utils.autocmd'.emit('CompleteDone')
|
||||
autocmd ColorScheme * call v:lua.cmp.plugin.colorscheme()
|
||||
autocmd CmdlineEnter * call v:lua.cmp.plugin.cmdline.enter()
|
||||
autocmd CmdwinEnter * call v:lua.cmp.plugin.cmdline.leave() " for entering cmdwin with `<C-f>`
|
||||
augroup END
|
||||
]]
|
||||
|
||||
misc.set(_G, { 'cmp', 'plugin', 'cmdline', 'enter' }, function()
|
||||
if config.is_native_menu() then
|
||||
return
|
||||
vim.api.nvim_set_hl(0, 'CmpItemAbbr', { link = 'CmpItemAbbrDefault', default = true })
|
||||
vim.api.nvim_set_hl(0, 'CmpItemAbbrDeprecated', { link = 'CmpItemAbbrDeprecatedDefault', default = true })
|
||||
vim.api.nvim_set_hl(0, 'CmpItemAbbrMatch', { link = 'CmpItemAbbrMatchDefault', default = true })
|
||||
vim.api.nvim_set_hl(0, 'CmpItemAbbrMatchFuzzy', { link = 'CmpItemAbbrMatchFuzzyDefault', default = true })
|
||||
vim.api.nvim_set_hl(0, 'CmpItemKind', { link = 'CmpItemKindDefault', default = true })
|
||||
vim.api.nvim_set_hl(0, 'CmpItemMenu', { link = 'CmpItemMenuDefault', default = true })
|
||||
for kind in pairs(types.lsp.CompletionItemKind) do
|
||||
if type(kind) == 'string' then
|
||||
local name = ('CmpItemKind%s'):format(kind)
|
||||
vim.api.nvim_set_hl(0, name, { link = ('%sDefault'):format(name), default = true })
|
||||
end
|
||||
if vim.fn.expand('<afile>')~= '=' then
|
||||
vim.schedule(function()
|
||||
if api.is_cmdline_mode() then
|
||||
vim.cmd [[
|
||||
augroup cmp-cmdline
|
||||
autocmd!
|
||||
autocmd CmdlineChanged * lua require'cmp.utils.autocmd'.emit('TextChanged')
|
||||
autocmd CmdlineLeave * call v:lua.cmp.plugin.cmdline.leave()
|
||||
augroup END
|
||||
]]
|
||||
require('cmp.utils.autocmd').emit('CmdlineEnter')
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
misc.set(_G, { 'cmp', 'plugin', 'cmdline', 'leave' }, function()
|
||||
if vim.fn.expand('<afile>') ~= '=' then
|
||||
vim.cmd [[
|
||||
augroup cmp-cmdline
|
||||
autocmd!
|
||||
augroup END
|
||||
]]
|
||||
require('cmp.utils.autocmd').emit('CmdlineLeave')
|
||||
end
|
||||
end)
|
||||
|
||||
misc.set(_G, { 'cmp', 'plugin', 'colorscheme' }, function()
|
||||
highlight.inherit('CmpItemAbbrDefault', 'Pmenu', {
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
highlight.inherit('CmpItemAbbrDeprecatedDefault', 'Comment', {
|
||||
gui = 'NONE',
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
highlight.inherit('CmpItemAbbrMatchDefault', 'Pmenu', {
|
||||
gui = 'NONE',
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
highlight.inherit('CmpItemAbbrMatchFuzzyDefault', 'Pmenu', {
|
||||
gui = 'NONE',
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
highlight.inherit('CmpItemKindDefault', 'Special', {
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
autocmd.subscribe('ColorScheme', function()
|
||||
highlight.inherit('CmpItemAbbrDefault', 'Pmenu', { bg = 'NONE', default = false })
|
||||
highlight.inherit('CmpItemAbbrDeprecatedDefault', 'Comment', { bg = 'NONE', default = false })
|
||||
highlight.inherit('CmpItemAbbrMatchDefault', 'Pmenu', { bg = 'NONE', default = false })
|
||||
highlight.inherit('CmpItemAbbrMatchFuzzyDefault', 'Pmenu', { bg = 'NONE', default = false })
|
||||
highlight.inherit('CmpItemKindDefault', 'Special', { bg = 'NONE', default = false })
|
||||
highlight.inherit('CmpItemMenuDefault', 'Pmenu', { bg = 'NONE', default = false })
|
||||
for name in pairs(types.lsp.CompletionItemKind) do
|
||||
if type(name) == 'string' then
|
||||
vim.cmd(([[highlight default link CmpItemKind%sDefault CmpItemKind]]):format(name))
|
||||
vim.api.nvim_set_hl(0, ('CmpItemKind%sDefault'):format(name), { link = 'CmpItemKind', default = false })
|
||||
end
|
||||
end
|
||||
highlight.inherit('CmpItemMenuDefault', 'Pmenu', {
|
||||
guibg = 'NONE',
|
||||
ctermbg = 'NONE',
|
||||
})
|
||||
end)
|
||||
_G.cmp.plugin.colorscheme()
|
||||
|
||||
if vim.fn.hlexists('CmpItemAbbr') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemAbbr CmpItemAbbrDefault]]
|
||||
end
|
||||
|
||||
if vim.fn.hlexists('CmpItemAbbrDeprecated') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemAbbrDeprecated CmpItemAbbrDeprecatedDefault]]
|
||||
end
|
||||
|
||||
if vim.fn.hlexists('CmpItemAbbrMatch') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemAbbrMatch CmpItemAbbrMatchDefault]]
|
||||
end
|
||||
|
||||
if vim.fn.hlexists('CmpItemAbbrMatchFuzzy') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemAbbrMatchFuzzy CmpItemAbbrMatchFuzzyDefault]]
|
||||
end
|
||||
|
||||
if vim.fn.hlexists('CmpItemKind') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemKind CmpItemKindDefault]]
|
||||
end
|
||||
for name in pairs(types.lsp.CompletionItemKind) do
|
||||
if type(name) == 'string' then
|
||||
local hi = ('CmpItemKind%s'):format(name)
|
||||
if vim.fn.hlexists(hi) ~= 1 then
|
||||
vim.cmd(([[highlight default link %s %sDefault]]):format(hi, hi))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vim.fn.hlexists('CmpItemMenu') ~= 1 then
|
||||
vim.cmd [[highlight default link CmpItemMenu CmpItemMenuDefault]]
|
||||
end
|
||||
|
||||
vim.cmd [[command! CmpStatus lua require('cmp').status()]]
|
||||
|
||||
vim.cmd [[doautocmd <nomodeline> User CmpReady]]
|
||||
autocmd.emit('ColorScheme')
|
||||
|
||||
if vim.on_key then
|
||||
vim.on_key(function(keys)
|
||||
if keys == vim.api.nvim_replace_termcodes('<C-c>', true, true, true) then
|
||||
vim.schedule(function()
|
||||
if not api.is_suitable_mode() then
|
||||
require('cmp.utils.autocmd').emit('InsertLeave')
|
||||
autocmd.emit('InsertLeave')
|
||||
end
|
||||
end)
|
||||
end
|
||||
end, vim.api.nvim_create_namespace('cmp.plugin'))
|
||||
end
|
||||
|
||||
vim.api.nvim_create_user_command('CmpStatus', function()
|
||||
require('cmp').status()
|
||||
end, { desc = 'Check status of cmp sources' })
|
||||
|
||||
vim.cmd([[doautocmd <nomodeline> User CmpReady]])
|
||||
|
63
bundle/nvim-cmp/utils/install_stylua.sh
vendored
63
bundle/nvim-cmp/utils/install_stylua.sh
vendored
@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu pipefall
|
||||
|
||||
declare -r INSTALL_DIR="$PWD/utils"
|
||||
declare -r RELEASE="0.10.0"
|
||||
declare -r OS="linux"
|
||||
# declare -r OS="$(uname -s)"
|
||||
declare -r FILENAME="stylua-$RELEASE-$OS"
|
||||
|
||||
declare -a __deps=("curl" "unzip")
|
||||
|
||||
function check_deps() {
|
||||
for dep in "${__deps[@]}"; do
|
||||
if ! command -v "$dep" >/dev/null; then
|
||||
echo "Missing depdendecy!"
|
||||
echo "The \"$dep\" command was not found!. Please install and try again."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function download_stylua() {
|
||||
local DOWNLOAD_DIR
|
||||
local URL="https://github.com/JohnnyMorganz/StyLua/releases/download/v$RELEASE/$FILENAME.zip"
|
||||
|
||||
DOWNLOAD_DIR="$(mktemp -d)"
|
||||
echo "Initiating download for Stylua v$RELEASE"
|
||||
if ! curl --progress-bar --fail -L "$URL" -o "$DOWNLOAD_DIR/$FILENAME.zip"; then
|
||||
echo "Download failed. Check that the release/filename are correct."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Installation in progress.."
|
||||
unzip -q "$DOWNLOAD_DIR/$FILENAME.zip" -d "$DOWNLOAD_DIR"
|
||||
|
||||
if [ -f "$DOWNLOAD_DIR/stylua" ]; then
|
||||
mv "$DOWNLOAD_DIR/stylua" "$INSTALL_DIR/stylua"
|
||||
else
|
||||
mv "$DOWNLOAD_DIR/$FILENAME/stylua" "$INSTALL_DIR/."
|
||||
fi
|
||||
|
||||
chmod u+x "$INSTALL_DIR/stylua"
|
||||
}
|
||||
|
||||
function verify_install() {
|
||||
echo "Verifying installation.."
|
||||
local DOWNLOADED_VER
|
||||
DOWNLOADED_VER="$("$INSTALL_DIR/stylua" -V | awk '{ print $2 }')"
|
||||
if [ "$DOWNLOADED_VER" != "$RELEASE" ]; then
|
||||
echo "Mismatched version!"
|
||||
echo "Expected: v$RELEASE but got v$DOWNLOADED_VER"
|
||||
exit 1
|
||||
fi
|
||||
echo "Verification complete!"
|
||||
}
|
||||
|
||||
function main() {
|
||||
check_deps
|
||||
download_stylua
|
||||
verify_install
|
||||
}
|
||||
|
||||
main "$@"
|
6
bundle/nvim-cmp/utils/vimrc.vim
vendored
6
bundle/nvim-cmp/utils/vimrc.vim
vendored
@ -36,15 +36,15 @@ cmp.setup {
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true })
|
||||
},
|
||||
|
||||
sources = {
|
||||
sources = cmp.config.sources({
|
||||
{ name = "nvim_lsp" },
|
||||
{ name = "buffer" },
|
||||
},
|
||||
}),
|
||||
}
|
||||
EOF
|
||||
|
||||
lua << EOF
|
||||
local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())
|
||||
local capabilities = require('cmp_nvim_lsp').default_capabilities()
|
||||
|
||||
require'lspconfig'.cssls.setup {
|
||||
capabilities = capabilities,
|
||||
|
Loading…
Reference in New Issue
Block a user