Skip to content

feat!: replace sources with in-process LSP - #2636

Draft
saghen wants to merge 6 commits into
mainfrom
in-process-lsp
Draft

saghen wants to merge 6 commits into
mainfrom
in-process-lsp

Conversation

@saghen

@saghen saghen commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

This PR implements the biggest breaking change from V1 -> V2, replacing our custom sources system with blink.lib.lsp for in-process LSPs which work with any completion engine (including native!). Additionally, this makes use of the built-in vim.lsp and runtime lsp/* detection. This PR also switches from a custom task implementation to vim.async.

  • blink.compat for v1 sources -> v2 LSP
  • documentation/migration guide
  • terminal-mode completion (can be follow up PR)
  • built-in snippets

I'm going on a vacation for a week, so I'll be late to respond, but feedback is appreciated! @soifou feel free to commit on this branch directly if you'd like to make any changes.

Configuration

Rather than the user defining sources = { default = { ... }, providers = {} }, everything gets defined through vim.lsp.* and cmp.lsp.* (similar API to vim.lsp + per-buffer).

-- LSP author config
local some_lsp = require('blink.lib.lsp').server({
  name = 'some-lsp',
  capabilities = { completionProvider = { resolveProvider = true } },
  settings = require('blink.lib.config').schema({
    use_show_condition = { true, 'boolean' },
    show_autosnippets = { true, 'boolean' },
    use_label_description = { false, 'boolean' },
  }),
  handlers = {
    -- async.run() contexts
    ['textDocument/completion'] = function(params, ctx)
      local settings = ctx.srv.settings --[[@as SomeLspSettings]]
      return { isIncomplete = false, items = get_items(settings) }
    end
    ['completionItem/resolve'] = function(item) .. end
  }
})
vim.lsp.config('some-lsp', { cmd = some_lsp })

-- LSP user config
vim.lsp.config('some-lsp', { settings = { .. } })
vim.lsp.enable('some-lsp')

-- blink.cmp config
local cmp = require('blink.cmp')

-- decides whether blink queries it at all
cmp.lsp.enable('some-lsp', false)
-- can be in ftplugin/*.lua for filetype specific enable/disable
cmp.lsp.enable('some-lsp', true, { bufnr = 0 })
-- provides blink.cmp specific client-side options, also optionally per-buffer
-- replaces `sources.providers.some_lsp.*` from v1 config
cmp.lsp.config('some-lsp', { convert = function(item) return item end })

Since pure declarative configuration is so common, we also provide a more limited lsp = {} option in setup() for users who don't want to use the programmatic interface.

Cmdline

Rather than scattering special cases for cmdline/terminal modes across the codebase, the LSPs attach to a buffer with filetype blink-cmdline which mirrors the actual cmdline's content and performs two-way sync between them. This was surprisingly simple to implement and avoids any special configuration on vim.lsp (simply register your LSP for the blink-cmdline filetype). This approach also supports out-of-process LSPs such as vimls, although I haven't explicitly tested this.

Snippets

The user's snippet engine is now automatically detected from loaded modules. The built-in snippets engine was temporarily dropped, but I'm planning to either add it back to this repo or create a separate blink.snippets project, but I'm unsure which to do atm.

@soifou

soifou commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Hey, great job! Been super busy lately, fixing some IRL stuff and might take a few more weeks... I'll be glad to polish this up on my next spare time but feel free to merge if you think this can land sooner. Don't want to hold you back!

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

Successfully merging this pull request may close these issues.

2 participants