From 286b9f78d1013d4f4d3a70efcc803d00912dfe35 Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Wed, 17 Nov 2021 22:38:56 +0900 Subject: [PATCH] Refactor get_active_entry and core.filter (#535) * Refactor get_active_entry and core.filter * Refactor source.lua --- lua/cmp/core.lua | 24 ++++--------- lua/cmp/source.lua | 20 +++-------- lua/cmp/view/custom_entries_view.lua | 53 +++++++++------------------- 3 files changed, 29 insertions(+), 68 deletions(-) diff --git a/lua/cmp/core.lua b/lua/cmp/core.lua index f2d286a..f21b3f0 100644 --- a/lua/cmp/core.lua +++ b/lua/cmp/core.lua @@ -14,8 +14,8 @@ local api = require('cmp.utils.api') local event = require('cmp.utils.event') local SOURCE_TIMEOUT = 500 -local THROTTLE_TIME = 120 -local DEBOUNCE_TIME = 20 +local THROTTLE_TIME = 100 +local DEBOUNCE_TIME = 50 ---@class cmp.Core ---@field public suspending boolean @@ -250,32 +250,22 @@ end ---Update completion menu core.filter = async.throttle( vim.schedule_wrap(function(self) - if not api.is_suitable_mode() then + local ignore = false + ignore = ignore or not api.is_suitable_mode() + ignore = ignore or self.view:get_active_entry() + if ignore then return end - if self.view:get_active_entry() ~= nil then - return - end - local ctx = self:get_context() - -- To wait for processing source for that's timeout. local sources = {} for _, s in ipairs(self:get_sources({ source.SourceStatus.FETCHING, source.SourceStatus.COMPLETED })) do local time = SOURCE_TIMEOUT - s:get_fetching_time() if not s.incomplete and time > 0 then - if #sources == 0 then - self.filter.stop() - self.filter.timeout = time + 1 - self:filter() - return - end break end table.insert(sources, s) end - self.filter.timeout = THROTTLE_TIME - - self.view:open(ctx, sources) + self.view:open(self:get_context(), sources) end), THROTTLE_TIME ) diff --git a/lua/cmp/source.lua b/lua/cmp/source.lua index 077bb48..307a7e1 100644 --- a/lua/cmp/source.lua +++ b/lua/cmp/source.lua @@ -229,20 +229,15 @@ end ---@return boolean Return true if not trigger completion. source.complete = function(self, ctx, callback) local offset = ctx:get_offset(self:get_keyword_pattern()) - if ctx.cursor.col <= offset then - self:reset() - end + -- NOTE: This implementation is nvim-cmp specific. + -- We trigger new completion after core.confirm but we check only the symbol trigger_character in this case. local before_char = string.sub(ctx.cursor_before_line, -1) - local before_char_iw = string.match(ctx.cursor_before_line, '(.)%s*$') or before_char - if ctx:get_reason() == types.cmp.ContextReason.TriggerOnly then - if string.match(before_char, '^%a+$') then + before_char = string.match(ctx.cursor_before_line, '(.)%s*$') + if not char.is_symbol(string.byte(before_char)) then before_char = '' end - if string.match(before_char_iw, '^%a+$') then - before_char_iw = '' - end end local completion_context @@ -256,11 +251,6 @@ source.complete = function(self, ctx, callback) triggerKind = types.lsp.CompletionTriggerKind.TriggerCharacter, triggerCharacter = before_char, } - elseif vim.tbl_contains(self:get_trigger_characters(), before_char_iw) then - completion_context = { - triggerKind = types.lsp.CompletionTriggerKind.TriggerCharacter, - triggerCharacter = before_char_iw, - } elseif ctx:get_reason() ~= types.cmp.ContextReason.TriggerOnly then if self:get_keyword_length() <= (ctx.cursor.col - offset) then if self.incomplete and self.context.cursor.col ~= ctx.cursor.col then @@ -279,7 +269,7 @@ source.complete = function(self, ctx, callback) end if not completion_context then - if ctx:get_reason() == types.cmp.ContextReason.TriggerOnly then + if not vim.tbl_contains({ self.request_offset, self.offset }, offset) then self:reset() end debug.log(self:get_debug_name(), 'skip completion') diff --git a/lua/cmp/view/custom_entries_view.lua b/lua/cmp/view/custom_entries_view.lua index b6cf72b..57eb7b9 100644 --- a/lua/cmp/view/custom_entries_view.lua +++ b/lua/cmp/view/custom_entries_view.lua @@ -14,6 +14,7 @@ local DEFAULT_HEIGHT = 10 -- @see https://github.com/vim/vim/blob/master/src/pop ---@class cmp.CustomEntriesView ---@field private entries_win cmp.Window ---@field private offset number +---@field private active boolean ---@field private entries cmp.Entry[] ---@field private column_width any ---@field public event cmp.Event @@ -33,6 +34,7 @@ custom_entries_view.new = function() self.entries_win:option('winhighlight', 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None') self.event = event.new() self.offset = -1 + self.active = false self.entries = {} autocmd.subscribe( @@ -93,10 +95,7 @@ custom_entries_view.ready = function() end custom_entries_view.on_change = function(self) - if self:visible() and self:get_active_entry() then - self.entries_win:option('cursorline', false) - vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 1 }) - end + self.active = false end custom_entries_view.open = function(self, offset, entries) @@ -161,22 +160,19 @@ custom_entries_view.open = function(self, offset, entries) height = height, zindex = 1001, }) - vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 1 }) - self.entries_win:option('cursorline', false) - if preselect > 0 and config.get().preselect == types.cmp.PreselectMode.Item then - self:preselect(preselect) + self:_select(preselect, { behavior = types.cmp.SelectBehavior.Select }) elseif not string.match(config.get().completion.completeopt, 'noselect') then - self:preselect(1) + self:_select(1, { behavior = types.cmp.SelectBehavior.Select }) else - self:draw() + self:_select(0, { behavior = types.cmp.SelectBehavior.Select }) end - self.event:emit('change') end custom_entries_view.close = function(self) self.prefix = nil self.offset = -1 + self.active = false self.entries = {} self.entries_win:close() end @@ -227,19 +223,8 @@ custom_entries_view.info = function(self) return self.entries_win:info() end -custom_entries_view.preselect = function(self, index) - if self:visible() then - if index <= #self.entries then - self.entries_win:option('cursorline', true) - vim.api.nvim_win_set_cursor(self.entries_win.win, { index, 1 }) - self.entries_win:update() - self:draw() - end - end -end - custom_entries_view.select_next_item = function(self, option) - if self.entries_win:visible() then + if self:visible() then local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1] + 1 if not self.entries_win:option('cursorline') then cursor = 1 @@ -251,7 +236,7 @@ custom_entries_view.select_next_item = function(self, option) end custom_entries_view.select_prev_item = function(self, option) - if self.entries_win:visible() then + if self:visible() then local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1] - 1 if not self.entries_win:option('cursorline') then cursor = #self.entries @@ -261,36 +246,32 @@ custom_entries_view.select_prev_item = function(self, option) end custom_entries_view.get_first_entry = function(self) - if self.entries_win:visible() then + if self:visible() then return self.entries[1] end end custom_entries_view.get_selected_entry = function(self) - if self.entries_win:visible() and self.entries_win:option('cursorline') then + if self:visible() and self.entries_win:option('cursorline') then return self.entries[vim.api.nvim_win_get_cursor(self.entries_win.win)[1]] end end custom_entries_view.get_active_entry = function(self) - if self.entries_win:visible() and self.entries_win:option('cursorline') then - local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win) - if cursor[2] == 0 then - return self:get_selected_entry() - end + if self:visible() and self.active then + return self:get_selected_entry() end end custom_entries_view._select = function(self, cursor, option) local is_insert = (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert - if is_insert then - if vim.api.nvim_win_get_cursor(self.entries_win.win)[2] == 1 then - self.prefix = string.sub(api.get_current_line(), self.offset, api.get_cursor()[2]) or '' - end + 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 = cursor > 0 and is_insert self.entries_win:option('cursorline', cursor > 0) - vim.api.nvim_win_set_cursor(self.entries_win.win, { math.max(cursor, 1), is_insert and 0 or 1 }) + vim.api.nvim_win_set_cursor(self.entries_win.win, { math.max(cursor, 1), 0 }) if is_insert then self:_insert(self.entries[cursor] and self.entries[cursor]:get_vim_item(self.offset).word or self.prefix)