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

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

Open
mmirus opened this issue Apr 24, 2023 · 4 comments

Comments

@mmirus
Copy link

mmirus commented Apr 24, 2023

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:

cmp-cmdline.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. 😂

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
Copy link

EdmundsEcho commented Jul 5, 2023

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.

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 <Esc>
|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_<BS>|	<BS>		delete the character in front of the cursor
|c_digraph|	{char1} <BS> {char2}
				enter digraph when 'digraph' is on
|c_CTRL-H|	CTRL-H		same as <BS>
|c_<Tab>|	<Tab>		if 'wildchar' is <Tab>: Do completion on
				the pattern in front of the cursor
|c_<S-Tab>|	<S-Tab>		same as CTRL-P
|c_wildchar|	'wildchar'	Do completion on the pattern in front of the
				cursor (default: <Tab>)
|c_CTRL-I|	CTRL-I		same as <Tab>
|c_<NL>|	<NL>		same as <CR>
|c_CTRL-J|	CTRL-J		same as <CR>
|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_<CR>|	<CR>		execute entered command
|c_CTRL-M|	CTRL-M		same as <CR>
|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_<Esc>|	<Esc>		abandon command-line without executing it
|c_CTRL-[|	CTRL-[		same as <Esc>
|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_<Del>|	<Del>		delete the character under the cursor

|c_<Left>|	<Left>		cursor left
|c_<S-Left>|	<S-Left>	cursor one word left
|c_<C-Left>|	<C-Left>	cursor one word left
|c_<Right>|	<Right>		cursor right
|c_<S-Right>|	<S-Right>	cursor one word right
|c_<C-Right>|	<C-Right>	cursor one word right
|c_<Up>|	<Up>		recall previous command-line from history that
				matches pattern in front of the cursor
|c_<S-Up>|	<S-Up>		recall previous command-line from history
|c_<Down>|	<Down>		recall next command-line from history that
				matches pattern in front of the cursor
|c_<S-Down>|	<S-Down>	recall next command-line from history
|c_<Home>|	<Home>		cursor to start of command-line
|c_<End>|	<End>		cursor to end of command-line
|c_<PageDown>|	<PageDown>	same as <S-Down>
|c_<PageUp>|	<PageUp>	same as <S-Up>
|c_<Insert>|	<Insert>	toggle insert/overstrike mode
|c_<LeftMouse>|	<LeftMouse>	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
Copy link

Same problem here

@yangmillstheory
Copy link

I filed #108 yesterday; could be related to this.

@maxencetholomier
Copy link

maxencetholomier commented May 28, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants