diff --git a/lua/cmp/core.lua b/lua/cmp/core.lua index b9031af..d1900a6 100644 --- a/lua/cmp/core.lua +++ b/lua/cmp/core.lua @@ -200,91 +200,83 @@ core.confirm = vim.schedule_wrap(function(e, option, callback) debug.log('entry.confirm', e) local ctx = context.new() - keymap.feedkeys( - 'U' .. string.rep('', ctx.cursor.col - e.context.cursor.col), - 'n', - vim.schedule_wrap(function() - --@see https://github.com/microsoft/vscode/blob/main/src/vs/editor/contrib/suggest/suggestController.ts#L334 - if #(misc.safe(e:get_completion_item().additionalTextEdits) or {}) == 0 then - local pre = context.new() - e:resolve(function() - local new = context.new() - local text_edits = misc.safe(e:get_completion_item().additionalTextEdits) or {} - if #text_edits == 0 then - return - end + keymap.feedkeys('U' .. string.rep('', ctx.cursor.col - e.context.cursor.col), 'n', function() + --@see https://github.com/microsoft/vscode/blob/main/src/vs/editor/contrib/suggest/suggestController.ts#L334 + if #(misc.safe(e:get_completion_item().additionalTextEdits) or {}) == 0 then + local pre = context.new() + e:resolve(function() + local new = context.new() + local text_edits = misc.safe(e:get_completion_item().additionalTextEdits) or {} + if #text_edits == 0 then + return + end - local has_cursor_line_text_edit = (function() - local minrow = math.min(pre.cursor.row, new.cursor.row) - local maxrow = math.max(pre.cursor.row, new.cursor.row) - for _, te in ipairs(text_edits) do - local srow = te.range.start.line + 1 - local erow = te.range['end'].line + 1 - if srow <= minrow and maxrow <= erow then - return true - end + local has_cursor_line_text_edit = (function() + local minrow = math.min(pre.cursor.row, new.cursor.row) + local maxrow = math.max(pre.cursor.row, new.cursor.row) + for _, te in ipairs(text_edits) do + local srow = te.range.start.line + 1 + local erow = te.range['end'].line + 1 + if srow <= minrow and maxrow <= erow then + return true end - return false - end)() - if has_cursor_line_text_edit then - return end - vim.fn['cmp#apply_text_edits'](new.bufnr, text_edits) - end) - else - vim.fn['cmp#apply_text_edits'](ctx.bufnr, e:get_completion_item().additionalTextEdits) - end + return false + end)() + if has_cursor_line_text_edit then + return + end + vim.fn['cmp#apply_text_edits'](new.bufnr, text_edits) + end) + else + vim.fn['cmp#apply_text_edits'](ctx.bufnr, e:get_completion_item().additionalTextEdits) + end - -- Prepare completion item for confirmation - local completion_item = misc.copy(e:get_completion_item()) - if not misc.safe(completion_item.textEdit) then - completion_item.textEdit = {} - completion_item.textEdit.newText = misc.safe(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 - completion_item.textEdit.range = e:get_replace_range() - else - completion_item.textEdit.range = e:get_insert_range() - end + -- Prepare completion item for confirmation + local completion_item = misc.copy(e:get_completion_item()) + if not misc.safe(completion_item.textEdit) then + completion_item.textEdit = {} + completion_item.textEdit.newText = misc.safe(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 + completion_item.textEdit.range = e:get_replace_range() + else + completion_item.textEdit.range = e:get_insert_range() + end - local is_snippet = true - is_snippet = is_snippet and completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet - is_snippet = is_snippet and vim.lsp.util.parse_snippet(completion_item.textEdit.newText) ~= completion_item.textEdit.newText + local is_snippet = true + is_snippet = is_snippet and completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet + is_snippet = is_snippet and vim.lsp.util.parse_snippet(completion_item.textEdit.newText) ~= completion_item.textEdit.newText - local keys = '' - if completion_item.textEdit.range['end'].character > e.context.cursor.character then - keys = keys .. string.rep('U', completion_item.textEdit.range['end'].character - e.context.cursor.character) - end - if e.context.cursor.character > completion_item.textEdit.range.start.character then - keys = keys .. string.rep('', e.context.cursor.character - completion_item.textEdit.range.start.character) - end + local keys = '' + if completion_item.textEdit.range['end'].character > e.context.cursor.character then + keys = keys .. string.rep('U', completion_item.textEdit.range['end'].character - e.context.cursor.character) + end + if e.context.cursor.character > completion_item.textEdit.range.start.character then + keys = keys .. string.rep('', e.context.cursor.character - completion_item.textEdit.range.start.character) + end + if is_snippet then + keys = keys .. 'u' .. e:get_word() .. 'u' + keys = keys .. string.rep('', vim.fn.strchars(e:get_word())) + else + keys = keys .. 'u' .. completion_item.textEdit.newText .. 'u' + end + keymap.feedkeys(keys, 'n', function() if is_snippet then - keys = keys .. 'u' .. e:get_word() .. 'u' - keys = keys .. string.rep('', vim.fn.strchars(e:get_word())) - else - keys = keys .. 'u' .. completion_item.textEdit.newText .. 'u' + config.get().snippet.expand({ + body = completion_item.textEdit.newText, + insert_text_mode = completion_item.insertTextMode, + }) end - keymap.feedkeys( - keys, - 'n', - vim.schedule_wrap(function() - if is_snippet then - config.get().snippet.expand({ - body = completion_item.textEdit.newText, - insert_text_mode = completion_item.insertTextMode, - }) - end - e:execute(function() - if callback then - callback() - end - end) - end) - ) + e:execute(function() + if callback then + callback() + end + end) end) - ) + end) end) ---Reset current completion state diff --git a/lua/cmp/utils/keymap.lua b/lua/cmp/utils/keymap.lua index f3c110e..05d1cc7 100644 --- a/lua/cmp/utils/keymap.lua +++ b/lua/cmp/utils/keymap.lua @@ -57,15 +57,23 @@ __call = function(self, keys, mode, callback) if callback then local current_mode = string.sub(vim.api.nvim_get_mode().mode, 1, 1) + local ctrl_r = current_mode == 'i' local id = misc.id('cmp.utils.keymap.feedkeys') local cb = ('(cmp-utils-keymap-feedkeys:%s)'):format(id) self.callbacks[id] = function() - callback() + self.callbacks[id] = nil vim.api.nvim_buf_del_keymap(0, current_mode, cb) + callback() + if ctrl_r then + return '' + end return keymap.t('') end - vim.api.nvim_buf_set_keymap(0, current_mode, cb, ('v:lua.cmp.utils.keymap.feedkeys.expr(%s)'):format(id), { - expr = true, + + local rhs = ctrl_r and '=v:lua.cmp.utils.keymap.feedkeys.run(%s)' or ':v:lua.cmp.utils.keymap.feedkeys.run(%s)' + vim.api.nvim_buf_set_keymap(0, current_mode, cb, string.format(rhs, id), { + expr = not ctrl_r, + noremap = true, nowait = true, silent = true, }) @@ -73,11 +81,11 @@ __call = function(self, keys, mode, callback) end end }) -misc.set(_G, { 'cmp', 'utils', 'keymap', 'feedkeys', 'expr' }, function(id) +misc.set(_G, { 'cmp', 'utils', 'keymap', 'feedkeys', 'run' }, function(id) if keymap.feedkeys.callbacks[id] then - keymap.feedkeys.callbacks[id]() + return keymap.feedkeys.callbacks[id]() end - return keymap.t('') + return '' end) ---Register keypress handler. @@ -126,6 +134,7 @@ keymap.listen = setmetatable({ expr = true, nowait = true, noremap = true, + silent = true, }) end, }) @@ -138,6 +147,7 @@ misc.set(_G, { 'cmp', 'utils', 'keymap', 'expr' }, function(keys) vim.api.nvim_buf_set_keymap(0, 'i', '(cmp-utils-keymap:_)', existing.rhs, { expr = existing.expr == 1, noremap = existing.noremap == 1, + silent = true, }) vim.fn.feedkeys(keymap.t('(cmp-utils-keymap:_)'), 'i') end)