Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(fallback): make fallback work with buffer-local mappings #483

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lua/blink/cmp/keymap/apply.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ function apply.keymap_to_current_buffer(keys_to_commands)
for key, commands in pairs(keys_to_commands) do
if #commands == 0 then goto continue end

local fallback = require('blink.cmp.keymap.fallback').wrap('i', key)

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)
return fallback()

-- run user defined functions
elseif type(command) == 'function' then
Expand All @@ -42,11 +44,13 @@ function apply.keymap_to_current_buffer(keys_to_commands)
end
if not has_snippet_command or #commands == 0 then goto continue end

local fallback = require('blink.cmp.keymap.fallback').wrap('s', key)

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)
return fallback()

-- run user defined functions
elseif type(command) == 'function' then
Expand Down
50 changes: 40 additions & 10 deletions lua/blink/cmp/keymap/fallback.lua
Original file line number Diff line number Diff line change
@@ -1,29 +1,57 @@
local fallback = {}

--- Gets the first non blink.cmp keymap for the given mode and key
--- Add missing types. Remove when fixed upstream
---@class vim.api.keyset.keymap
---@field lhs string
---@field mode string
---@field rhs? string
---@field lhsraw? string
---@field buffer? number

--- Gets the non blink.cmp global 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)
function fallback.get_non_blink_global_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))
-- get global mappings
local 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
--- Gets the non blink.cmp buffer 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 {}
--- @return vim.api.keyset.keymap?
function fallback.get_non_blink_buffer_mapping_for_key(mode, key)
local ret = vim.fn.maparg(key, mode, false, true) --[[@as vim.api.keyset.keymap]]
if ret and ret.buffer == 0 then return end
if ret and ret.desc and ret.desc == 'blink.cmp' then return end
return ret.lhs ~= nil and ret or nil
end

--- Returns a function that will run the first non blink.cmp keymap for the given mode and key
--- @param mode string
--- @param key string
--- @return fun(): string?
function fallback.wrap(mode, key)
local buffer_mapping = fallback.get_non_blink_buffer_mapping_for_key(mode, key)
return function()
local mapping = buffer_mapping or fallback.get_non_blink_global_mapping_for_key(mode, key)
if mapping then return fallback.run_non_blink_keymap(mapping, key) end
end
end

--- Runs the first non blink.cmp keymap for the given mode and key
--- @param mapping vim.api.keyset.keymap
--- @param key string
--- @return string | nil
function fallback.run_non_blink_keymap(mapping, key)
-- 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
Expand All @@ -36,7 +64,9 @@ function fallback.run_non_blink_keymap(mode, key)
end

local expr = mapping.callback()
if mapping.replace_keycodes == 1 then expr = vim.api.nvim_replace_termcodes(expr, true, true, true) end
if type(expr) == 'string' and 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)
Expand Down