Convert VS Code extensions into coc.nvim plugins at install time and run them natively. Supports Neovim 0.8+ and Vim 9.0+.
β οΈ IMPORTANT: Keep coc-vscode-loader Updatedcoc-vscode-loader is under active development. Each release includes critical bug fixes, converter improvements, and registry updates. Always use the latest version β running an outdated version will silently produce broken plugin conversions (e.g., formatters that don't format, wrong notification colors, or language servers that fail to start).
When updating, the loader automatically detects which installed plugins changed β affected plugins are marked
[changed]in the TUI. Only those need reinstalling, not everything.:CocUpdate coc-vscode-loader " Update to latest :CocCommand loader.open " Check for [changed] markers, press R on those " Or reinstall a specific plugin: :CocCommand loader.reinstall <name>Failure to keep the loader + all plugins in sync is the #1 source of reported issues.
Every registry entry points to an upstream VS Code extension that evolves independently. The Registry Update Check workflow runs daily to ensure nothing silently breaks:
flowchart LR
A[00:00 / 12:00 Beijing] --> B[Check 134 repos]
B --> C{Upstream changed?}
C -->|No| D[Skip]
C -->|Yes| E[Run converter]
E --> F{Output changed?}
F -->|No| G[Skip]
F -->|Yes| H[Create PR]
F -->|Error| I[Create Issue]
| What happens | Action |
|---|---|
| Upstream has new commits β output matches baseline | β Skipped (no news is good news) |
| Upstream has new commits β output changed | π¬ PR created β review & merge |
| Upstream repo is deleted / archived | π¬ Issue created β investigate |
| Converter fails on new upstream code | π¬ Issue created β debug needed |
Each outdated entry gets one isolated PR with detailed diff output and upstream commit history. No noise β only actionable results. See docs/registry-update-checker.md for full design.
Trigger manually: gh workflow run registry-check.yml or via the Actions tab.
Install the loader plugin:
:CocInstall coc-vscode-loaderThen open the TUI to browse and install available extensions:
:CocCommand loader.openWhat happens when you install a plugin (AOT β Ahead-of-Time):
git clonethe upstream VS Code extension source- Run the converter (ts-morph AST transforms + text replacements) to produce a complete coc.nvim plugin package
npm install+esbuildto bundle the output- Copy the result to
~/.config/coc/extensions/node_modules/coc-<name>and register it
No runtime interception or JIT overhead β coc.nvim loads a normal plugin at startup.
Or auto-install extensions via vim variable (no TUI needed):
" .vimrc
let g:coc_loader_global_extensions = ['vscode-pyright', 'vscode-eslint']-- init.lua
vim.g.coc_loader_global_extensions = { 'vscode-pyright', 'vscode-eslint' }Browse all available extensions online: coc-plugin.github.io/coc-vscode-registry
Use the one-step conversion script:
bash scripts/convert-plugin.sh <name> <github-repo> [subdir]
# Examples:
bash scripts/convert-plugin.sh eslint microsoft/vscode-eslint
bash scripts/convert-plugin.sh volar vuejs/language-tools extensions/vscodeFor manual conversion:
cd converter
echo '[{"type":"source","transforms":["import-mapping"],"entry":"src/extension.ts"}]' > convert.json
npx tsx src/cli.ts convert ../path/to/vscode-ext -o ./output --convert-file convert.json
cd ./output && npm install && node esbuild.mjsπ See
docs/for full API mapping docs and converter design.
coc.nvim's API is heavily influenced by the VS Code extension API β both use the same LSP protocol, similar provider systems, and comparable namespace structures. This makes it possible to mechanically convert VS Code extensions to run as coc.nvim plugins.
This repo contains two parts:
- Converter CLI (
converter/) β automatically converts VS Code extensions to coc plugins - Loader plugin (
plugin/) β coc.nvim plugin with a TUI to install/update/uninstall converted plugins
Input (VS Code extension source)
β 1. git clone upstream repo
β 2. Scanner β detect files using VS Code API
β 3. Steps pipeline (5 registered generators):
β ββ language-client β LanguageClient code (module/binary server)
β ββ source β Copy + 5 AST transforms (import-mapping, class-to-factory,
β β provider-register, enum-offset, strip-volar)
β ββ bridge β Bridge code from BRIDGE_TEMPLATES (tsserver-forward)
β ββ snippets β Copy snippets JSON + stub entry
β ββ mark-unsupported β Remove unsupported API calls
β 4. Text replacements (.fileName, .uri.fsPath, getWordRangeAtPosition, WorkspaceEdit)
β 5. Plugin patches (per-entry find/replace from registry)
β 6. Generate package.json + esbuild.mjs + server-patches.json
β 7. npm install + esbuild β lib/index.js
β Output: coc plugin package at ~/.config/coc/extensions/node_modules/coc-<name>
Three test suites, each catching different issues:
npm test # Unit tests (167) + fixture tests + test coverage check
npm run test:full # Unit tests + registry baseline diff
npm run test:smoke # Registry smoke test (all 134 entries β validates output structure)| Suite | What it catches | CI |
|---|---|---|
npm test |
Transform/fixture correctness (fast, ~1s) | β |
npm run test:full |
Unintended side effects on all 134 registry entries | β (manual) |
npm run test:smoke |
Registry entry conversion completeness | β |
Baseline diff (npm run diff:baseline / npm run diff:check):
Before changing converter code, snapshot current output; after changes, compare to detect which plugins are affected. See AGENTS.md for full workflow.
Pre-push hook β git push automatically runs npm test + npm run test:smoke. Configure once:
git config core.hooksPath .githooks
# Or just run npm install (pre-configured via postinstall)Skip with git push --no-verify (use sparingly).
GitHub Actions CI β three sequential jobs:
unit(Node 20/22): unit tests + fixture testsdiff: registry baseline check (detects unintended converter side effects)smoke: full registry conversion (validates output structure)
# Check current mode
bash switch.sh status
# Use local development version
bash switch.sh local
# Use npm published version
bash switch.sh npmOr via npm scripts:
npm run switch:status
npm run switch:local
npm run switch:npmNote for npm 11+:
switch.sh npmtemporarily removesfile:dependencies fromextensions/package.jsonto avoid reify errors, then restores them automatically.
After switching, run :CocRestart in Neovim.
npm run build # build everything
cd plugin && npm run build # build plugin only- Linux β Fully supported
- macOS β Fully supported
- Windows β Not supported (compatibility plans in
docs/windows-compatibility.md, but pipeline currently requires Unix shell commands)
| Editor | TUI | Notes |
|---|---|---|
| Neovim 0.8+ | β Full floating window + extmark | Recommended, full Mason-style experience |
| Vim 9.0+ | β Split window + prop_add | Bottom split, no backdrop, no live search |
These must be installed and available on PATH:
| Command | Required by | Notes |
|---|---|---|
git |
Source download & update checks | |
node / npm / npx |
Plugin build, converter runtime | Node.js >= 18 |
curl |
Registry fetch fallback, binary server download | |
unzip |
Binary server extraction | |
tar / gunzip |
Binary server extraction | |
python3 |
Pip package installation (e.g. ansible-lint) | Only if plugin requires pip packages |
pip (via python3 -m pip) |
Python dependency installation | Only if plugin requires pip packages |
All commands are pre-installed on typical macOS/Linux development machines or available via the system package manager (apt, brew, etc.).
Close the TUI β it will auto-run :CocRestart. Or manually run :CocRestart.
Browse the registry website or check registry.json. Includes LSP servers, direct-API plugins, and snippet extensions for most languages.
The converter rewrites VS Code API calls to coc.nvim equivalents. You get the same functionality without needing VS Code.
Yes! See CONTRIBUTING.md for the full workflow. In short:
- Add an entry to the registry repo
- Run
npm test+npm run test:smoketo verify - Submit a PR
- π¬ Discussions
- π Issues
- π API mapping docs Β· Converter design Β· Registry website
- β Star the repo if you find it useful!

