Skip to content

Commit

Permalink
dev (#956)
Browse files Browse the repository at this point in the history
* Adjust empty line count

* Implement vim.api.nvim_create_autocmd (#844)

* Implement vim.api.nvim_create_autocmd

* Only use vim.api.nvim_create_autocmd on nighly

* Cleanup

* cleanup

* Rename autos.lua to autocmds.lua

* Fix forgot to rename autos to autocmds

* Remove legacy autocmd

* Add descriptions on autocmds

* Update descriptions on autocmds

* Update CmpStatus command to lua API (#922)

Signed-off-by: Micah Halter <[email protected]>

* Move highlights to nvim_set_hl lua API (#925)

Signed-off-by: Micah Halter <[email protected]>

* Add default to highlight

* Refactor autocmds

* fmt

* Improve performance

* Fix bug

* Improve matching logic
Fixes #954

* Fix format

* Improve performance
Fix #825

* Fix cmdline redraw bug

* Fix event

Co-authored-by: hrsh7th <>
Co-authored-by: zer09 <[email protected]>
Co-authored-by: Micah Halter <[email protected]>
  • Loading branch information
3 people authored May 3, 2022
1 parent bba6fb6 commit 5054c14
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 242 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ Concept
- No flicker



Setup
====================

Expand Down Expand Up @@ -134,15 +133,14 @@ EOF
```



### Where can I find more completion sources?

- See the [Wiki](https://github.com/hrsh7th/nvim-cmp/wiki/List-of-sources)
- See the [GitHub topic](https://github.com/topics/nvim-cmp).



### Where can I find advanced configuration examples?

See the [Wiki](https://github.com/hrsh7th/nvim-cmp/wiki)


2 changes: 1 addition & 1 deletion lua/cmp/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local event = require('cmp.utils.event')

local SOURCE_TIMEOUT = 500
local DEBOUNCE_TIME = 80
local THROTTLE_TIME = 60
local THROTTLE_TIME = 40

---@class cmp.Core
---@field public suspending boolean
Expand Down
62 changes: 30 additions & 32 deletions lua/cmp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}

Expand Down Expand Up @@ -283,51 +284,48 @@ cmp.setup = setmetatable({
end,
})

autocmd.subscribe('InsertEnter', function()
feedkeys.call('', 'i', function()
-- In InsertEnter autocmd, vim will detects mode=normal unexpectedly.
autocmd.subscribe(
{ 'InsertEnter', 'CmdlineEnter' },
async.debounce_safe_state(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('InsertLeave', function()
cmp.core:reset()
cmp.core.view:close()
end)

autocmd.subscribe('CmdlineEnter', function()
if config.enabled() then
cmp.core:prepare()
cmp.core:on_change('InsertEnter')
end
end)

autocmd.subscribe('CmdlineLeave', function()
cmp.core:reset()
cmp.core.view:close()
end)
)

autocmd.subscribe('TextChanged', function()
if config.enabled() then
cmp.core:on_change('TextChanged')
end
end)
-- async.throttle is needed for performance. The mapping `:<C-u>...<CR>` will fire `CmdlineChanged` for each character.
autocmd.subscribe(
{ 'TextChangedI', 'TextChangedP', 'CmdlineChanged' },
async.debounce_safe_state(function()
if config.enabled() then
cmp.core:on_change('TextChanged')
end
end)
)

autocmd.subscribe('CursorMoved', function()
-- If make this asynchronous, the completion menu will not close when the command output is displayed.
autocmd.subscribe({ 'InsertLeave', 'CmdlineLeave' }, function()
if config.enabled() then
cmp.core:on_moved()
else
cmp.core:reset()
cmp.core.view:close()
end
end)

autocmd.subscribe('InsertEnter', function()
cmp.config.compare.scopes:update()
cmp.config.compare.locality:update()
end)
autocmd.subscribe(
'CursorMovedI',
async.debounce_safe_state(function()
if config.enabled() then
cmp.core:on_moved()
else
cmp.core:reset()
cmp.core.view:close()
end
end)
)

cmp.event:on('complete_done', function(evt)
if evt.entry then
Expand Down
18 changes: 17 additions & 1 deletion lua/cmp/matcher.lua
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@ 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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -146,6 +154,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
Expand Down Expand Up @@ -260,6 +272,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)
Expand All @@ -272,6 +285,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
Expand All @@ -281,6 +295,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
Expand All @@ -298,6 +313,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
Expand Down
3 changes: 3 additions & 0 deletions lua/cmp/matcher_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ 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' }))
end)
Expand Down
17 changes: 17 additions & 0 deletions lua/cmp/utils/async.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
local feedkeys = require('cmp.utils.feedkeys')

local async = {}

---@class cmp.AsyncThrottle
Expand Down Expand Up @@ -109,4 +111,19 @@ async.sync = function(runner, timeout)
end, 10, false)
end

---Wait and callback for next safe state.
async.debounce_safe_state = function(callback)
local running = false
return function()
if running then
return
end
running = true
feedkeys.call('', 'n', function()
running = false
callback()
end)
end
end

return async
34 changes: 26 additions & 8 deletions lua/cmp/utils/autocmd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 6 additions & 63 deletions lua/cmp/utils/feedkeys.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
9 changes: 9 additions & 0 deletions lua/cmp/utils/feedkeys_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 5054c14

Please sign in to comment.