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

buffer-local fallback mappings not triggered #482

Closed
folke opened this issue Dec 9, 2024 · 10 comments · Fixed by #483
Closed

buffer-local fallback mappings not triggered #482

folke opened this issue Dec 9, 2024 · 10 comments · Fixed by #483
Labels
bug Something isn't working

Comments

@folke
Copy link
Contributor

folke commented Dec 9, 2024

require('blink.cmp.keymap.apply').keymap_to_current_buffer(mappings)

I'm working on a new plugin (better vim.ui.input) that opens a floating window and sets keymaps for both <tab> and <cr>.

Blink overrides these buffer-local keymaps.

Is that the intended behavior?

I can't really control users to make sure they exclude the filetype to the blink enabled.
Apart from that, in some cases completion is for sure useful.

Is there any way to trigger the existing keymap when overriding it in the buffer?

Or restoring the old keymaps when the menu closes?

@folke
Copy link
Contributor Author

folke commented Dec 9, 2024

Just checked the code and I see there's actually support for this.

fyi, this is my blink keymap config:

      keymap = {
        preset = "enter",
        ["<Tab>"] = {
          LazyVim.cmp.map({ "snippet_forward", "ai_accept" }),
          "fallback",
        },
      },

The fallback does not trigger for both <cr> and <tab> insert mode mappings.

@folke folke changed the title Blink keymaps are always applied to the buffer even when the menu is not visible. buffer-local fallback mappings not triggered Dec 9, 2024
@folke
Copy link
Contributor Author

folke commented Dec 9, 2024

I don't think this line can work, since the buffer-local keymap has been replaced by the blink one.
fallbacks probably only trigger for global keymaps.

https://github.com/Saghen/blink.cmp/blob/main/lua/blink/cmp/keymap/apply.lua#L21

@Saghen
Copy link
Owner

Saghen commented Dec 9, 2024

Yeah, sounds like a bug, I didn't realize there can't be multiple buffer local mappings on a single key. For now, would it make sense to mark your UI with buftype == 'prompt' so it gets disabled by default?

@folke
Copy link
Contributor Author

folke commented Dec 9, 2024

fyi: to get a mapping (local/global), it's much much faster to use vim.fn.maparg instead of looping over all mappings.

@Saghen Saghen added the bug Something isn't working label Dec 9, 2024
@folke
Copy link
Contributor Author

folke commented Dec 9, 2024

I'll create a PR

@folke
Copy link
Contributor Author

folke commented Dec 9, 2024

See my PR :)

I've also changed the impl to use vim.fn.maparg. It's much much faster than iterating over all mappings.

@hrsh7th
Copy link

hrsh7th commented Dec 10, 2024

In my opinion, nvim-cmp's key mapping fallback mechanism is too complicated, so I don't recommend implementing it from scratch.

Instead, you can consider returning an empty string from vim.on_key callback.

This seems like a cleaner way to achieve "key mapping for a specific context", similar to native completion key bindings.

@folke
Copy link
Contributor Author

folke commented Dec 10, 2024

That's actually a great idea!
I didn't know about the behavior of returning the empty string.

@folke
Copy link
Contributor Author

folke commented Dec 10, 2024

However, would be great to have my PR merged already, since I would like to launch a bunch of new plugins today and the input one is broken for users using blink.

@Saghen
Copy link
Owner

Saghen commented Dec 10, 2024

Looks like that empty string behavior is new neovim/neovim@b34e137. The whole keymap code gets reduced to just the following (very rough code :)), but we'll have to wait for the 0.11 release

local keymap = {}

function keymap.setup()
  local mappings = vim.deepcopy(require('blink.cmp.config').keymap)

  -- Handle preset
  if mappings.preset then
    local preset_keymap = require('blink.cmp.keymap.presets').get(mappings.preset)

    -- Remove 'preset' key from opts to prevent it from being treated as a keymap
    mappings.preset = nil

    -- Merge the preset keymap with the user-defined keymaps
    -- User-defined keymaps overwrite the preset keymaps
    mappings = vim.tbl_extend('force', preset_keymap, mappings)
  end

  local snippet_commands = { 'snippet_forward', 'snippet_backward' }

  -- TODO: handle multiple keys like <C-g><C-o>
  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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants