diff --git a/lua/blink/cmp/keymap/apply.lua b/lua/blink/cmp/keymap/apply.lua deleted file mode 100644 index c56052dc..00000000 --- a/lua/blink/cmp/keymap/apply.lua +++ /dev/null @@ -1,81 +0,0 @@ -local apply = {} - -local snippet_commands = { 'snippet_forward', 'snippet_backward' } - ---- Applies the keymaps to the current buffer ---- @param keys_to_commands table -function apply.keymap_to_current_buffer(keys_to_commands) - -- skip if we've already applied the keymaps - for _, mapping in ipairs(vim.api.nvim_buf_get_keymap(0, 'i')) do - if mapping.desc == 'blink.cmp' then return end - end - - -- insert mode: uses both snippet and insert commands - for key, commands in pairs(keys_to_commands) do - if #commands == 0 then goto continue end - - apply.set('i', key, function() - for _, command in ipairs(commands) do - -- special case for fallback - if command == 'fallback' then - return require('blink.cmp.keymap.fallback').run_non_blink_keymap('i', key) - - -- run user defined functions - elseif type(command) == 'function' then - if command(require('blink.cmp')) then return end - - -- otherwise, run the built-in command - elseif require('blink.cmp')[command]() then - return - end - end - end) - - ::continue:: - end - - -- snippet mode - for key, commands in pairs(keys_to_commands) do - local has_snippet_command = false - for _, command in ipairs(commands) do - if vim.tbl_contains(snippet_commands, command) then has_snippet_command = true end - end - if not has_snippet_command or #commands == 0 then goto continue end - - apply.set('s', key, function() - for _, command in ipairs(keys_to_commands[key] or {}) do - -- special case for fallback - if command == 'fallback' then - return require('blink.cmp.keymap.fallback').run_non_blink_keymap('s', key) - - -- run user defined functions - elseif type(command) == 'function' then - if command(require('blink.cmp')) then return end - - -- only run snippet commands - elseif vim.tbl_contains(snippet_commands, command) then - local did_run = require('blink.cmp')[command]() - if did_run then return end - end - end - end) - - ::continue:: - end -end - ---- @param mode string ---- @param key string ---- @param callback fun(): string | nil -function apply.set(mode, key, callback) - vim.api.nvim_buf_set_keymap(0, mode, key, '', { - callback = callback, - expr = true, - silent = true, - noremap = true, - replace_keycodes = false, - desc = 'blink.cmp', - }) -end - -return apply diff --git a/lua/blink/cmp/keymap/fallback.lua b/lua/blink/cmp/keymap/fallback.lua deleted file mode 100644 index bfaee7d9..00000000 --- a/lua/blink/cmp/keymap/fallback.lua +++ /dev/null @@ -1,51 +0,0 @@ -local fallback = {} - ---- Gets the first non blink.cmp keymap for the given mode and key ---- @param mode string ---- @param key string ---- @return vim.api.keyset.keymap | nil -function fallback.get_non_blink_mapping_for_key(mode, key) - local normalized_key = vim.api.nvim_replace_termcodes(key, true, true, true) - - -- get buffer local and global mappings - local mappings = vim.api.nvim_buf_get_keymap(0, mode) - vim.list_extend(mappings, vim.api.nvim_get_keymap(mode)) - - for _, mapping in ipairs(mappings) do - local mapping_key = vim.api.nvim_replace_termcodes(mapping.lhs, true, true, true) - if mapping_key == normalized_key and mapping.desc ~= 'blink.cmp' then return mapping end - end -end - ---- Runs the first non blink.cmp keymap for the given mode and key ---- @param mode string ---- @param key string ---- @return string | nil -function fallback.run_non_blink_keymap(mode, key) - local mapping = fallback.get_non_blink_mapping_for_key(mode, key) or {} - - -- TODO: there's likely many edge cases here. the nvim-cmp version is lacking documentation - -- and is quite complex. we should look to see if we can simplify their logic - -- https://github.com/hrsh7th/nvim-cmp/blob/ae644feb7b67bf1ce4260c231d1d4300b19c6f30/lua/cmp/utils/keymap.lua - if type(mapping.callback) == 'function' then - -- with expr = true, which we use, we can't modify the buffer without scheduling - -- so if the keymap does not use expr, we must schedule it - if mapping.expr ~= 1 then - vim.schedule(mapping.callback) - return - end - - local expr = mapping.callback() - if mapping.replace_keycodes == 1 then expr = vim.api.nvim_replace_termcodes(expr, true, true, true) end - return expr - elseif mapping.rhs then - local rhs = vim.api.nvim_replace_termcodes(mapping.rhs, true, true, true) - if mapping.expr == 1 then rhs = vim.api.nvim_eval(rhs) end - return rhs - end - - -- pass the key along as usual - return vim.api.nvim_replace_termcodes(key, true, true, true) -end - -return fallback diff --git a/lua/blink/cmp/keymap/init.lua b/lua/blink/cmp/keymap/init.lua index 0b0d5973..cdeb8b8f 100644 --- a/lua/blink/cmp/keymap/init.lua +++ b/lua/blink/cmp/keymap/init.lua @@ -15,21 +15,43 @@ function keymap.setup() mappings = vim.tbl_extend('force', preset_keymap, mappings) end - -- We set on the buffer directly to avoid buffer-local keymaps (such as from autopairs) - -- from overriding our mappings. We also use InsertEnter to avoid conflicts with keymaps - -- applied on other autocmds, such as LspAttach used by nvim-lspconfig and most configs - vim.api.nvim_create_autocmd('InsertEnter', { - callback = function() - if not require('blink.cmp.config').enabled() then return end - require('blink.cmp.keymap.apply').keymap_to_current_buffer(mappings) - end, - }) - - -- This is not called when the plugin loads since it first checks if the binary is - -- installed. As a result, when lazy-loaded on InsertEnter, the event may be missed - if vim.api.nvim_get_mode().mode == 'i' and require('blink.cmp.config').enabled() then - require('blink.cmp.keymap.apply').keymap_to_current_buffer(mappings) - end + local snippet_commands = { 'snippet_forward', 'snippet_backward' } + + -- We listen to every key and return an empty string when blink handles the key, + -- to tell neovim not to run the default keymaps + -- TODO: handle multiple keys like + vim.on_key(function(original_key, key) + if not require('blink.cmp.config').enabled() then return original_key end + + local mode = vim.api.nvim_get_mode().mode + if mode ~= 'i' and mode ~= 's' then return original_key end + + for command_key, commands in pairs(mappings) do + if vim.api.nvim_replace_termcodes(command_key, true, true, true) == key then + for _, command in ipairs(commands) do + -- ignore snippet commands for insert mode + if vim.tbl_contains(snippet_commands, command) and mode == 'i' then goto continue end + + -- special case for fallback, return the key so that neovim continues like normal + if command == 'fallback' then + return original_key + + -- run user defined functions + elseif type(command) == 'function' then + if command(require('blink.cmp')) then return '' end + + -- otherwise, run the built-in command + elseif require('blink.cmp')[command]() then + return '' + end + + ::continue:: + end + end + end + + return original_key + end) end return keymap