Skip to content

fang2hou/blink-copilot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

60 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Completion Sample

blink-copilot

⚙️ Configurable GitHub Copilot blink.cmp source

Table of Contents

📋 Requirements

  • Neovim >= 0.11.0
  • GitHub Copilot LSP Provider (choose one of the following)
    • Copilot Language Server - Official GitHub Copilot LSP client
    • copilot.vim - Official GitHub Copilot Vim/Neovim Plugin
    • copilot.lua - Third-party GitHub Copilot written in Lua
    • copilot-lsp - Native GitHub Copilot LSP client support
      • It also provides a better experience for Copilot's NES feature.

🌟 Features

  1. Compliant with the blink.cmp async specification.
  2. Automatically detects the LSP client during buffer switches.
  3. Supports multiple completion candidates.
  4. Refreshes Copilot suggestion items dynamically as the cursor moves.
  5. Implemented entirely in Lua using the latest GitHub Copilot LSP APIs.
  6. Offers an improved preview with auto-indentation for completion items.
  7. Compatible with both copilot.lua and the official copilot.vim LSP providers.
  8. Easily configurable icon and kind settings.

🥘 Recipes

Here are some example configuration for using blink-copilot with lazy.nvim.

blink-copilot + Copilot Language Server

Sign in to Copilot, or use the :LspCopilotSignIn command from https://github.com/neovim/nvim-lspconfig.


Option 1: Mason-lspconfig

Using mason-lspconfig.nvim (simpler)
{
  "williamboman/mason-lspconfig.nvim", --No manual LSP configuration needed
  opts = {
    ensure_installed = { "copilot" },
  },
  dependencies = { "williamboman/mason.nvim" },
},
{
  "saghen/blink.cmp",
  dependencies = { "fang2hou/blink-copilot" },
  opts = {
    sources = {
      default = { "lsp", "path", "snippets", "buffer", "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          async = true,
        },
      },
    },
  },
},

Option 2: Mason + Custom lspconfig

Using mason.nvim + nvim-lspconfig (more control)
{
  "neovim/nvim-lspconfig",
  opts = {
    servers = {
      copilot = {}, -- manual LSP configuration
    },
  },
},
{
  "mason-org/mason.nvim",
  opts = { ensure_installed = { "copilot" } },
},
{
  "saghen/blink.cmp",
  dependencies = { "fang2hou/blink-copilot" },
  opts = {
    sources = {
      default = { "lsp", "path", "snippets", "buffer", "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          async = true,
        },
      },
    },
  },
},

blink-copilot + zbirenbaum/copilot.lua
{
  "zbirenbaum/copilot.lua",
  cmd = "Copilot",
  event = "InsertEnter",
  opts = {
    suggestion = { enabled = false },
    panel = { enabled = false },
    filetypes = {
      markdown = true,
      help = true,
    },
  },
},
{
  "saghen/blink.cmp",
  optional = true,
  dependencies = { "fang2hou/blink-copilot" },
  opts = {
    sources = {
      default = { "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          score_offset = 100,
          async = true,
        },
      },
    },
  },
}
blink-copilot + github/copilot.vim
{
  "github/copilot.vim",
  cmd = "Copilot",
  event = "BufWinEnter",
  init = function()
    vim.g.copilot_no_maps = true
  end,
  config = function()
    -- Block the normal Copilot suggestions
    vim.api.nvim_create_augroup("github_copilot", { clear = true })
    vim.api.nvim_create_autocmd({ "FileType", "BufUnload" }, {
      group = "github_copilot",
      callback = function(args)
        vim.fn["copilot#On" .. args.event]()
      end,
    })
    vim.fn["copilot#OnFileType"]()
  end,
},
{
  "saghen/blink.cmp",
  dependencies = { "fang2hou/blink-copilot" },
  opts = {
    sources = {
      default = { "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          score_offset = 100,
          async = true,
        },
      },
    },
  },
}
blink-copilot + copilotlsp-nvim/copilot-lsp

You can check the official documentation.

{
  "copilotlsp-nvim/copilot-lsp",
  init = function()
    vim.g.copilot_nes_debounce = 500
    vim.lsp.enable("copilot_ls")
    vim.keymap.set("n", "<tab>", function()
      local bufnr = vim.api.nvim_get_current_buf()
      local state = vim.b[bufnr].nes_state
      if state then
        local _ = require("copilot-lsp.nes").walk_cursor_start_edit()
          or (
            require("copilot-lsp.nes").apply_pending_nes()
            and require("copilot-lsp.nes").walk_cursor_end_edit()
          )
        return nil
      else
        return "<C-i>"
      end
    end, { desc = "Accept Copilot NES suggestion", expr = true })
  end,
}
{
  "saghen/blink.cmp",
  dependencies = { "fang2hou/blink-copilot" },
  opts = {
    sources = {
      default = { "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          score_offset = 100,
          async = true,
        },
      },
    },
    keymap = {
      preset = "super-tab",
      ["<Tab>"] = {
        function(cmp)
          if vim.b[vim.api.nvim_get_current_buf()].nes_state then
            cmp.hide()
            return (
              require("copilot-lsp.nes").apply_pending_nes()
              and require("copilot-lsp.nes").walk_cursor_end_edit()
            )
          end
          if cmp.snippet_active() then
            return cmp.accept()
          else
            return cmp.select_and_accept()
          end
        end,
        "snippet_forward",
        "fallback",
      },
    },
  },
}

With 💤 LazyVim copilot extra

-- Import copilot extra (you can also use `:LazyExtras` to install it)
{ import = "lazyvim.plugins.extras.ai.copilot" },
(Optional)copilot.lua ➡️ Copilot Language Server
{
  "zbirenbaum/copilot.lua",
  enabled = false,
},
{
  "neovim/nvim-lspconfig",
  opts = {
    servers = {
      -- LazyVim Extra disabled it for copilot.lua
      copilot = { enabled = true },
    },
  },
},
{
  "mason-org/mason.nvim",
  opts = { ensure_installed = { "copilot" } },
},
(Optional)copilot.lua ➡️ copilot.vim
{
  "zbirenbaum/copilot.lua",
  enabled = false,
},
{
  "github/copilot.vim",
  cmd = "Copilot",
  event = "BufWinEnter",
  init = function()
    vim.g.copilot_no_maps = true
  end,
  config = function()
    -- Block the normal Copilot suggestions
    vim.api.nvim_create_autocmd({ "FileType", "BufUnload" }, {
      group = "github_copilot",
      callback = function(args)
        vim.fn["copilot#On" .. args.event]()
      end,
    })
    vim.fn["copilot#OnFileType"]()
  end,
}

⚙️ Configuration

blink-copilot seamlessly integrates with both blink.cmp source options and Neovim plugin configurations. For most users, simply configuring the options within blink options sources.provider.copilot.opts is sufficient.

Explore the configuration in detail
{
  "saghen/blink.cmp",
  optional = true,
  dependencies = {
    "fang2hou/blink-copilot",
    opts = {
      max_completions = 1,  -- Global default for max completions
      max_attempts = 2,     -- Global default for max attempts
    }
  },
  opts = {
    sources = {
      default = { "copilot" },
      providers = {
        copilot = {
          name = "copilot",
          module = "blink-copilot",
          score_offset = 100,
          async = true,
          opts = {
            -- Local options override global ones
            max_completions = 3,  -- Override global max_completions

            -- Final settings:
            -- * max_completions = 3
            -- * max_attempts = 2
            -- * all other options are default
          }
        },
      },
    },
  },
}

Here is the default configuration for blink-copilot:

{
  max_completions = 3,
  max_attempts = 4,
  kind_name = "Copilot", ---@type string | false
  kind_icon = "", ---@type string | false
  kind_hl = false, ---@type string | false
  debounce = 200, ---@type integer | false
  auto_refresh = {
    backward = true,
    forward = true,
  },
}

max_completions

Maximum number of completions to show.

Note

Sometimes Copilot do not provide any completions, even you set max_completions to a large number. This is a limitation of Copilot itself, not the plugin.

Default: 3

max_attempts

Maximum number of attempts to fetch completions.

Note

Each attempt will fetch 0 ~ 10 completions. Considering the possibility of failure, it is generally recommended to set it to max_completions+1.

Default: 4

kind_name

Specifies the type of completion item to display. Some distros may automatically set icon from the kind_name.

Set to false to disable the kind_name in completion items.

Default: "Copilot"

kind_icon

Specifies the icon of completion item to display.

Set to false to disable the kind_icon in completion items.

Default: " " (default-icon)

kind_hl

Specifies the highlight group of completion item to display.

Set to false to disable the kind_hl in completion items.

Default: false

debounce

Note

Debounce is a feature that limits the number of requests sent to Copilot.
You can customize the debounce time in milliseconds or set it to false to disable it.

Important

If you disable debounce and enable auto_refresh, the copilot suggestion items will be refreshed every time the cursor moves.
Excessive refreshing may temporarily block your Copilot.

Default: 200

auto_refresh

Automatically refreshes the completion list when the cursor moves.

Note

If you enable backward, the completion list will be refreshed when the cursor moves backward. If you enable forward, the completion list will be refreshed when the cursor moves forward.

Default: { backward = true, forward = true }

📚 Frequently Asked Questions

The number of completions does not match my settings.

This is because the number of completions provided by Copilot is not fixed. The max_completions setting is only an upper limit, and the actual number of completions may be less than this value.

What's the difference between blink-copilot and blink-cmp-copilot?

  • Completion Preview is now correctly deindented.
  • Support both copilot.lua and copilot.vim as a backend.
  • Support multiple completions, and it is configurable.
  • LSP interaction no longer relies on copilot.lua, ensuring improved performance and compliance with the latest official LSP API specifications.
  • Auto refresh copilot suggestion items when cursor moves.

The completion isn't working after restarting Copilot. What should I do?

The Copilot plugin doesn't automatically attach the new LSP client to buffers. To resolve this, manually reopen your current buffer to attach the LSP client. blink-copilot will automatically detect the new client and resume completions.

Why aren't blink completions showing up?

Blink intentionally pauses completions during macro recording. If you see recording @x in your statusline, press q to stop recording.

🔄 Alternatives and Related Projects

🪪 License

MIT

About

⚙️ Configurable GitHub Copilot blink.cmp source for Neovim

Topics

Resources

License

Stars

Watchers

Forks

Contributors 6

Languages