blink.cmp icon indicating copy to clipboard operation
blink.cmp copied to clipboard

Show suggestions after newline/whitespace

Open jclem opened this issue 11 months ago • 18 comments

Feature Description

I've been unable to get suggestions to show up as I type, including after whitespace (newline, space). This would be really useful to me, as Copilot works well in these situations.

return {
	"saghen/blink.cmp",
	version = "*",
	opts_extend = {
		"sources.completion.enabled_providers",
		"sources.compat",
		"sources.default",
		"sources.providers",
	},
	event = "InsertEnter",
	opts = {
		completion = {
			accept = {
				auto_brackets = {
					enabled = true,
				},
			},
			documentation = {
				auto_show = true,
				auto_show_delay_ms = 200,
				window = { border = "rounded", },
			},
			ghost_text = {
				enabled = true,
			},
			keyword = {
				range = 'full',
				regex = '[-_]\\|\\k',
			},
			menu = {

				auto_show = true,

				draw = {
					treesitter = { "lsp", },
				},
			},
			trigger = {
				prefetch_on_insert = true,
				show_on_blocked_trigger_characters = {},
			},
		},

		keymap = {
			preset = "super-tab",
		},

		signature = {
			enabled = true,
		},

		sources = {
			default = {
				"lsp",
				"path",
				"snippets",
				"buffer",
			},
		},
	},
}

I thought that show_on_blocked_trigger_characters = {} would solve this, but I may be misunderstanding the documentation.

jclem avatar Jan 01 '25 00:01 jclem

You could override the get_trigger_characters function for your LSP source:

-- by default, blink.cmp will block newline, tab and space trigger characters, disable that behavior
completion.trigger.blocked_trigger_characters = {}

-- add newline, tab and space to LSP source
sources.providers.lsp.override.get_trigger_characters = function(self)
  local trigger_characters = self:get_trigger_characters()
  vim.list_extend(trigger_characters, { '\n', '\t', ' ' })
  return trigger_characters
end

I've added this to the recipes as well. You may want to add this to your buffer source as well, since if the LSP doesnt return any items, we won't show the menu if it was trigger by any of these three characters

saghen avatar Jan 06 '25 17:01 saghen

@jclem , did you get this to work?

The suggestion above (even after changing completion to signature which I think it should be) does not do anything different for me.

bulletmark avatar Jan 19 '25 00:01 bulletmark

There's more info in the recipe: https://cmp.saghen.dev/recipes.html#show-on-newline-tab-and-space

The example is only for the LSP source, so if you don't have that enabled, you'll want to add it to one of your other enabled sources. And it's meant to be completion, not signature

saghen avatar Jan 19 '25 00:01 saghen

I already saw that recipe but it just restates what you said above.

bulletmark avatar Jan 19 '25 01:01 bulletmark

I stuffed around getting this to work with copilot and looking at the code here. There are two things that need to change in that snippet/recipe:

  1. completion.trigger.blocked_trigger_characters should be completion.trigger.show_on_blocked_trigger_characters

and for copilot:

  1. lsp should be copilot.

bulletmark avatar Jan 19 '25 02:01 bulletmark

@Saghen probably should fix that recipe for item 1 or would you prefer I raise a bug?

bulletmark avatar Jan 19 '25 03:01 bulletmark

Realized the same and fixed item 1 on main already, forgot to mention it here: https://main.cmp.saghen.dev/recipes.html#show-on-newline-tab-and-space

I'm thinking of adding a completion.trigger.additional_trigger_characters option so opening this back up, since this behaves poorly when the LSP doesn't support the space, newline or tab as trigger characters, and returns 0 items in that case.

saghen avatar Jan 19 '25 03:01 saghen

Realized the same and fixed item 1 on main already, forgot to mention it here: https://main.cmp.saghen.dev/recipes.html#show-on-newline-tab-and-space

I'm thinking of adding a completion.trigger.additional_trigger_characters option so opening this back up, since this behaves poorly when the LSP doesn't support the space, newline or tab as trigger characters, and returns 0 items in that case.

Yeah, sometimes when hitting enter, for a split second it shows then dissappears. I use blink-copilot, and @bulletmark , in option 2 , it should be lsp, as if I use copilot, then it will show errors, as get_trigger_characters will be nil.

MuntasirSZN avatar Jan 31 '25 09:01 MuntasirSZN

@Saghen Is this working? I have not been able to get it to work with any of the above settings. If I use copilot instead of lsp, in the recipe, I get the same error as @MuntasirSZN . If I use lsp, then the popup menu simply does not show when typing space or enter.

Like others, I was trying to make this work so that Copilot suggestions, from the copilot.nvim lsp, would show when typing whitspace. I checked LspInfo, and it is attached.

magnusriga avatar Mar 03 '25 23:03 magnusriga

Is there any work done in this part?

MuntasirSZN avatar Mar 26 '25 12:03 MuntasirSZN

@Saghen Although showing completion on custom trigger characters works nicely, thanks for the example, i find that jsdoc snippets from /** will not ovverride /** and will just add the snippet after /**.

Something like this will happen

/**/**
 rest of snippet here.

Is there a way to make auto_insert work for this?

BeniLeuz avatar May 07 '25 10:05 BeniLeuz

Have anybody found a solution to this? The recipe mentioned here didn't seem to work for me, as copilot suggestions don't come up on trigger characters, and it's only after I press ctrl-space to show the blink completion popup I see the copilot suggestions.

This becomes a pain as I have to constantly hit ctrl-space to show copilot suggestions.

{
  "saghen/blink.cmp",
  event = { "InsertEnter" },
  dependencies = {
    "fang2hou/blink-copilot",
opts = {
      completions.trigger.show_on_blocked_trigger_characters = {},
      sources.providers = {
        copilot = {
          async = true,
          score_offset = 100,
          module = "blink-copilot",
-- uncommenting below results in error
          -- override = {
          --   get_trigger_characters = function(self)
          --     local trigger_characters = self:get_trigger_characters()
          --     vim.list_extend(trigger_characters, { "\n", "\t", " " })
          --     return trigger_characters
          --   end,
          -- },
        },
        lsp = {
          async = true,
          score_offset = 99,
          override = {
            get_trigger_characters = function(self)
              local trigger_characters = self:get_trigger_characters()
              vim.list_extend(trigger_characters, { "\n", "\t", " " })
              return trigger_characters
            end,
          },
        },
  }
}

If I uncomment this override.get_trigger_characters for copilot source I get

 Error  12:48:29 msg_show.lua_error Error detected while processing InsertEnter Autocommands for "*":
Error executing lua callback: /Users/rbhanot/.config/nvim/lua/plugins/blink-cmp.lua:118: attempt to call method 'get_trigger_characters' (a nil value)
stack traceback:
	/Users/rbhanot/.config/nvim/lua/plugins/blink-cmp.lua:118: in function 'get_trigger_characters'
	...e/nvim/lazy/blink.cmp/lua/blink/cmp/sources/lib/init.lua:140: in function 'get_trigger_characters'
	...lazy/blink.cmp/lua/blink/cmp/completion/trigger/init.lua:170: in function 'is_trigger_character'
	...lazy/blink.cmp/lua/blink/cmp/completion/trigger/init.lua:100: in function 'on_cursor_moved'
	.../nvim/lazy/blink.cmp/lua/blink/cmp/lib/buffer_events.lua:81: in function <.../nvim/lazy/blink.cmp/lua/blink/cmp/lib/buffer_events.lua:60>

rbhanot4739 avatar May 19 '25 07:05 rbhanot4739

@rbhanot4739 You have the same issue as me, see old comments. Yes, currently no way.

MuntasirSZN avatar May 19 '25 08:05 MuntasirSZN

Probably doesn't help you guys much but it works fine in LazyVim which uses blink by default. Just have to enable ai.copilot from extras and set vim.g.ai_cmp = false in your options.lua. So perhaps look at how LazyVim configures this to work?

bulletmark avatar May 19 '25 08:05 bulletmark

So as @bulletmark mentioned in LazyVim(which is what I use) vim.g.ai_cmp actually controls the opts.suggestion.enable in for copilot.lua.

@MuntasirSZN If you are using LazyVim then setting vim.g.ai_cmp = false so allow the suggestions to come through. If you are not using LazyVim then setting opts.suggestion.enabled = true should make it work.

Additionally you need to set accept key for suggestions which most people prefer as <Tab>, however that makes it really difficult to insert literal tab character, so I set it to <S-cr> which personally works better for me.

  {
    "zbirenbaum/copilot.lua",
    opts = {
      suggestion = {
      enabled = true,
        keymap = {
          accept = "<S-cr>",
        },
      },
}

-- blink
{
  "saghen/blink.cmp",
  opts = {
    keymap = {
      preset = "enter",
      ["<Tab>"] = { "select_next",  "snippet_forward", "fallback"},
      ["<S-Tab>"] = { "select_prev", "snippet_backward", "fallback" },
     }
   }
}

rbhanot4739 avatar May 19 '25 13:05 rbhanot4739

I migrated to suggestions a long time ago @rbhanot4739 . Added two autocmds as in docs so it doesn't show while completions menu is open. I use tab preset though. Doesn't cause problem because of the autocmds.

  • Reference -> https://github.com/zbirenbaum/copilot.lua#suggestion
  • Code:
vim.api.nvim_create_autocmd("User", {
  pattern = "BlinkCmpMenuOpen",
  callback = function()
    vim.b.copilot_suggestion_hidden = true
  end,
})

vim.api.nvim_create_autocmd("User", {
  pattern = "BlinkCmpMenuClose",
  callback = function()
    vim.b.copilot_suggestion_hidden = false
  end,
})

MuntasirSZN avatar May 19 '25 15:05 MuntasirSZN

I am having the same issue, but using codeium. Here is my config:

  "saghen/blink.cmp",
  opts = {
    keymap = {
      ["˚"] = { "select_prev", "fallback" },
      ["∆"] = { "select_next", "fallback" },
      ["<A-Tab>"] = { "accept", "fallback" },
      ["<CR>"] = {},
    },
    completion = {
      menu = {
        draw = {
          components = {
            kind_icon = {
              text = function(ctx)
                if ctx.source_name == "codeium" then
                  return " "
                end
                local icon, _, _ = require("mini.icons").get("lsp", ctx.kind)
                return icon or "? "
              end,
              highlight = function(ctx)
                if ctx.source_name == "codeium" then
                  return "CmpItemKindSnippet" -- or another safe fallback
                end
                local _, hl, _ = require("mini.icons").get("lsp", ctx.kind)
                return hl or "CmpItemKind"
              end,
            },
            kind = {
              highlight = function(ctx)
                if ctx.source_name == "codeium" then
                  return "CmpItemKindSnippet"
                end
                local _, hl, _ = require("mini.icons").get("lsp", ctx.kind)
                return hl or "CmpItemKind"
              end,
            },
          },
        },
      },
    },
  },
  sources = {
    default = { "codeium", "lsp", "path", "snippets", "buffer" },
    providers = {
      codeium = {
        name = "Codeium",
        module = "codeium.blink",
        async = true,
      },
    },
  },
}

georg-ch avatar Jun 22 '25 08:06 georg-ch

I would like an option that allows us to set trigger characters independently of language servers. There are cases where a language server is unavailable, but other completion providers are available and a trigger character should open the list.

It could be implemented as a list of characters that are used as fallback, in case the language server does not define trigger characters.

devgioele avatar Jul 25 '25 11:07 devgioele