nvim-cmp icon indicating copy to clipboard operation
nvim-cmp copied to clipboard

Feature Request: complete on close

Open Ddystopia opened this issue 1 year ago • 3 comments
trafficstars

Hello, thank you for great plugin!

It would be great if you could've call cmp.confirm() when users just continues to type. In conjunction to preselect = types.cmp.PreselectMode.None user would be able to configure workflow like this:

  1. Just typing, cmp window would appear as usual, without any pre selected entry
  2. Hit tab n times, to find a completion user wan'ts
  3. Instead of hitting <CR> that will do something like that:
      ['<CR>'] = function(fallback)
        if cmp.visible() and cmp.get_selected_entry() ~= nil then
          cmp.confirm()
        else
          fallback()
        end
      end,

just continue typing, and equivalent to <CR> would occur (but writing itself would not be interrupted).

Right now, if you have cmp.select_next_item({ behavior = cmp.SelectBehavior.Insert }) then that workflow would live you with text that was suggested and it is enough for most use cases, but it would do things like auto imports or other useful code actions. Hitting <CR> is not a big price to pay, but maybe plugin can support that feature? Or maybe it already does?

Thank you in advance.

Ddystopia avatar Jul 28 '24 10:07 Ddystopia

I've hacked some user-space proof of concept, but if you be so kind to add a proper solution to the plugin, it would be great

(for some reason, that solution is horribly sloving down the editor. If less bindings are made, then perf is better. Maybe some O(n^2) algorithm going on?)

  local mappings = { ... };

  local try_confirm_with_fallback = function(char)
    return function(fallback)
      if cmp.visible() and cmp.get_selected_entry() ~= nil then
        cmp.confirm()

        vim.defer_fn(function()
          local row, col = unpack(vim.api.nvim_win_get_cursor(0))
          local line = vim.api.nvim_get_current_line()
          local new_line = line:sub(1, col) .. char .. line:sub(col + 1)
          vim.api.nvim_set_current_line(new_line)
          vim.api.nvim_win_set_cursor(0, { row, col + 1 })
        end, 0)
      end

      fallback()
    end
  end

  -- All printable ascii chars
  for i = 32, 126 do
    mapping[string.char(i)] = try_confirm_with_fallback(string.char(i))
  end

  cmp.setup { ..., mappings = mappings, ... }

Ddystopia avatar Jul 28 '24 11:07 Ddystopia

My guess is that keymap.normalize is an expensive function and plugin was not intended to use with hundreds of binds. An easy solution I can think of is to change that code to allow users to pass "default" closure, that would be called if no keys matched. That way users can pass something like try_confirm_with_fallback inside.

  for key, mapping in pairs(config.get().mapping) do
    if keymap.equals(key, keys) and mapping[mode] then
      return mapping[mode](fallback)
    end
  end

Or implement the feature as a whole inside the plugin, closing this issue directly

Ddystopia avatar Jul 28 '24 12:07 Ddystopia

You can try vim.on_key

xzbdmw avatar Aug 01 '24 09:08 xzbdmw