hrsh7th / cmp-cmdline

nvim-cmp source for vim's cmdline
MIT License
493 stars 42 forks source link

Next/previous works for command and search completion, but not in substitute command #92

Open mmirus opened 1 year ago

mmirus commented 1 year ago

Hey there!

If I do the following in the command line: :Lsp, cmp offers to complete the commands and <C-n> and <C-p> successfully let me navigate up and down.

Likewise, if I do /thing, cmp offers to complete the search term and the mappings work.

However, if I do :s/thing or :%s/thing, cmp offers to complete the search term, but the mappings do not work.

Here's a demonstration:

https://user-images.githubusercontent.com/524994/234080224-9ceb14c3-da73-49e5-9789-f82fbe7321f0.mp4

You can't see that I'm pressing <C-n> and <C-p> at then end when the substitute completion pops up (because it doesn't work), but I was. :joy:

Here is my config (using lazy.nvim). Please let me know if you would like me to try to make one that's a more minimal reproduction.

return {
  "hrsh7th/nvim-cmp",
  event = "InsertEnter",
  dependencies = {
    -- Autocompletion
    { "hrsh7th/nvim-cmp" },
    { "hrsh7th/cmp-nvim-lsp" },
    { "hrsh7th/cmp-buffer" },
    { "hrsh7th/cmp-path" },
    { "hrsh7th/cmp-cmdline" },
    { "saadparwaiz1/cmp_luasnip" },
    { "hrsh7th/cmp-nvim-lua" },

    -- Snippets
    { "L3MON4D3/LuaSnip" },

    -- Other
    "onsails/lspkind-nvim",
    {
      "zbirenbaum/copilot-cmp",
      dependencies = { "zbirenbaum/copilot.lua" },
      opts = {},
    },
  },
  config = function()
    local cmp = require("cmp")
    local luasnip = require("luasnip")

    cmp.setup({
      snippet = {
        expand = function(args)
          require("luasnip").lsp_expand(args.body)
        end,
      },
      window = {
        documentation = { border = "solid" },
      },
      mapping = {
        ["<C-b>"] = cmp.mapping.scroll_docs(-4),
        ["<C-f>"] = cmp.mapping.scroll_docs(4),
        ["<C-n>"] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }),
        ["<C-p>"] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }),
        ["<C-Space>"] = cmp.mapping.complete({}),
        ["<C-e>"] = cmp.mapping.abort(),
        ["<CR>"] = cmp.mapping.confirm({ select = true, behavior = cmp.ConfirmBehavior.Insert }),
        ["<S-CR>"] = cmp.mapping.confirm({ select = true, behavior = cmp.ConfirmBehavior.Replace }),

        -- LuaSnip
        ["<C-j>"] = cmp.mapping(function(fallback)
          if luasnip.expand_or_jumpable() then
            luasnip.expand_or_jump()
          elseif cmp.visible() then
            cmp.select_next_item()
          else
            fallback()
          end
        end, { "i", "s" }),
        ["<Tab>"] = cmp.mapping(function(fallback)
          if luasnip.jumpable(1) then
            luasnip.jump(1)
          else
            fallback()
          end
        end, { "i", "s" }),
        ["<S-Tab>"] = cmp.mapping(function(fallback)
          if luasnip.jumpable(-1) then
            luasnip.jump(-1)
          else
            fallback()
          end
        end, { "i", "s" }),
      },
      sources = cmp.config.sources({
        { name = "copilot" },
        { name = "nvim_lsp" },
        { name = "luasnip" },
        { name = "buffer" },
      }),
      formatting = {
        format = require("lspkind").cmp_format({
          symbol_map = { Copilot = "" },
        }),
      },
      experimental = {
        ghost_text = true,
      },
      -- Bump copilot suggestions down below better suggestions from other sources
      sorting = {
        priority_weight = 2,
        comparators = {
          require("copilot_cmp.comparators").prioritize,

          -- Below is the default comparator list and order for nvim-cmp
          cmp.config.compare.offset,
          -- cmp.config.compare.scopes, --this is commented in nvim-cmp too
          cmp.config.compare.exact,
          cmp.config.compare.score,
          cmp.config.compare.recently_used,
          cmp.config.compare.locality,
          cmp.config.compare.kind,
          cmp.config.compare.sort_text,
          cmp.config.compare.length,
          cmp.config.compare.order,
        },
      },
    })

    -- For `/` and `?`
    cmp.setup.cmdline({ "/", "?" }, {
      mapping = cmp.mapping.preset.cmdline(),
      sources = cmp.config.sources({
        { name = "buffer" },
      }),
    })

    -- For ':'
    cmp.setup.cmdline(":", {
      mapping = cmp.mapping.preset.cmdline(),
      sources = cmp.config.sources({
        { name = "path" },
      }, {
        {
          name = "cmdline",
          option = {
            ignore_cmds = { "Man", "!" },
          },
        },
      }, {
        { name = "buffer" },
      }),
    })
  end,
}
EdmundsEcho commented 1 year ago

I'm having the same issue. I can get the <C-n> and <C-p> to work in the main window (in insert mode), as well as in the command window using /, but not :. What I do get with the latter (perhaps to help inform the issue):

<C-p> takes me to the previous command in my command history <C-n> E464: Ambiguous use of user-defined command

The bindings reported by neovim:

:verbose cmap <C-n>

... points to ~/.config/nvim/bundle/nvim-cmp/lua/cmp/utils/keymap.lua:127. This does not seem like a conflict because there is only one entry.

In neovim's default cmap bindings for <C-n> and <C-p> it's clear that in the event it does "see" an auto-completion option, it will default to the behavior I'm getting with <C-p> (moving to the previous item in my command history, instead of completion options).

|c_CTRL-N|  CTRL-N      after using 'wildchar' with multiple matches:
                go to next match, otherwise: recall older
                command-line from history.
        CTRL-O      not used
|c_CTRL-P|  CTRL-P      after using 'wildchar' with multiple matches:
                go to previous match, otherwise: recall older
                command-line from history.

I vaguely recall in vimscript options for setting a value with the first item in the popup list... it may be a need to review this behavior in the command window mode.

The conflict with <C-n> remains unexplained (I also looked at bindings "for all" modes).

Command-line editing mode 4. Command-line editing *ex-edit-index* Get to the command-line with the ':', '!', '/' or '?' commands. Normal characters are inserted at the current cursor position. "Completion" below refers to context-sensitive completion. It will complete file names, tags, commands etc. as appropriate. ```md tag command action in Command-line editing mode ------------------------------------------------------------------------------ CTRL-@ not used |c_CTRL-A| CTRL-A do completion on the pattern in front of the cursor and insert all matches |c_CTRL-B| CTRL-B cursor to begin of command-line |c_CTRL-C| CTRL-C same as |c_CTRL-D| CTRL-D list completions that match the pattern in front of the cursor |c_CTRL-E| CTRL-E cursor to end of command-line |'cedit'| CTRL-F default value for 'cedit': opens the command-line window; otherwise not used |c_CTRL-G| CTRL-G next match when 'incsearch' is active |c_| delete the character in front of the cursor |c_digraph| {char1} {char2} enter digraph when 'digraph' is on |c_CTRL-H| CTRL-H same as |c_| if 'wildchar' is : Do completion on the pattern in front of the cursor |c_| same as CTRL-P |c_wildchar| 'wildchar' Do completion on the pattern in front of the cursor (default: ) |c_CTRL-I| CTRL-I same as |c_| same as |c_CTRL-J| CTRL-J same as |c_CTRL-K| CTRL-K {char1} {char2} enter digraph |c_CTRL-L| CTRL-L do completion on the pattern in front of the cursor and insert the longest common part |c_| execute entered command |c_CTRL-M| CTRL-M same as |c_CTRL-N| CTRL-N after using 'wildchar' with multiple matches: go to next match, otherwise: recall older command-line from history. CTRL-O not used |c_CTRL-P| CTRL-P after using 'wildchar' with multiple matches: go to previous match, otherwise: recall older command-line from history. |c_CTRL-Q| CTRL-Q same as CTRL-V, unless it's used for terminal control flow |c_CTRL-R| CTRL-R {regname} insert the contents of a register or object under the cursor as if typed |c_CTRL-R_CTRL-R| CTRL-R CTRL-R {regname} |c_CTRL-R_CTRL-O| CTRL-R CTRL-O {regname} insert the contents of a register or object under the cursor literally CTRL-S not used, or used for terminal control flow |c_CTRL-T| CTRL-T previous match when 'incsearch' is active |c_CTRL-U| CTRL-U remove all characters |c_CTRL-V| CTRL-V insert next non-digit literally, insert three digit decimal number as a single byte. |c_CTRL-W| CTRL-W delete the word in front of the cursor CTRL-X not used (reserved for completion) CTRL-Y copy (yank) modeless selection CTRL-Z not used (reserved for suspend) |c_| abandon command-line without executing it |c_CTRL-[| CTRL-[ same as |c_CTRL-\_CTRL-N| CTRL-\ CTRL-N go to Normal mode, abandon command-line |c_CTRL-\_CTRL-G| CTRL-\ CTRL-G go to Normal mode, abandon command-line CTRL-\ a - d reserved for extensions |c_CTRL-\_e| CTRL-\ e {expr} replace the command line with the result of {expr} CTRL-\ f - z reserved for extensions CTRL-\ others not used |c_CTRL-]| CTRL-] trigger abbreviation |c_CTRL-^| CTRL-^ toggle use of |:lmap| mappings |c_CTRL-_| CTRL-_ when 'allowrevins' set: change language (Hebrew) |c_| delete the character under the cursor |c_| cursor left |c_| cursor one word left |c_| cursor one word left |c_| cursor right |c_| cursor one word right |c_| cursor one word right |c_| recall previous command-line from history that matches pattern in front of the cursor |c_| recall previous command-line from history |c_| recall next command-line from history that matches pattern in front of the cursor |c_| recall next command-line from history |c_| cursor to start of command-line |c_| cursor to end of command-line |c_| same as |c_| same as |c_| toggle insert/overstrike mode |c_| cursor at mouse click ```

update

I resolved the conflicting use of <C-n>. There was a plugin that set the binding for all modes.

otavioschwanck commented 11 months ago

Same problem here

yangmillstheory commented 5 months ago

I filed https://github.com/hrsh7th/cmp-cmdline/issues/108 yesterday; could be related to this.

maxencetholomier commented 1 month ago

Same issues here

Following a minimal config to reproduce the defect :

--------------------------------------------------------------------------------
-- Plug-in Installation
--------------------------------------------------------------------------------

local vim = vim
local Plug = vim.fn["plug#"]

vim.call("plug#begin")

-- {{{

-- Completion
Plug("hrsh7th/nvim-cmp")
Plug("f3fora/cmp-spell")
Plug("hrsh7th/cmp-buffer")
Plug("hrsh7th/cmp-cmdline")
Plug("hrsh7th/cmp-nvim-lsp")
Plug("hrsh7th/cmp-path")

-- }}}

vim.call("plug#end")

--------------------------------------------------------------------------------
-- Cmp-Nvim
--------------------------------------------------------------------------------

--{{

local cmp = require("cmp")

cmp.setup({
  snippet = {
    expand = function(args)
      require("luasnip").lsp_expand(args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
    ["<CR>"] = cmp.mapping.confirm({ select = true }),
  }),
  sources = cmp.config.sources({
    { name = "nvim_lsp" },
    { name = "spell" },
    { name = "luasnip" },
    { name = "path" },
    { name = "buffer" },
  }),

  enabled = function()
    local context = require("cmp.config.context")
    if vim.api.nvim_get_mode().mode == "c" then
      return true
    else
      return not context.in_treesitter_capture("comment") and not context.in_syntax_group("Comment")
    end
  end,
})

cmp.setup.cmdline({ "/", "?" }, {
    mapping = cmp.mapping.preset.cmdline(),
  sources = {
    { name = "buffer" },
  },
})

cmp.setup.cmdline(":", {
  mapping = cmp.mapping.preset.cmdline(),
  sources = cmp.config.sources({
    { name = "path" },
    { name = "buffer" }, 
    { name = "cmdline" },
  }),
})

--}}}

The workaround provided by EdmundsEcho does not work for my config.

This is not related 108. This one work well with the minimal config provided.