VSCode 源码解读

面向使用 Cursor、Windsurf、Trae、VSCodium 等 VSCode 系工具做开发的程序员。

读完应能理解 VSCode 的整体架构、插件(Extension)的制作 / 使用 / 配置原理,以及这些下游 fork 与官方 VSCode 的关系。


目录

  1. 全局架构总览
  2. [进程模型:为什么 VSCode 不会卡死](#进程模型:为什么 VSCode 不会卡死)
  3. 启动流程
  4. 源码目录结构与分层
  5. 依赖注入与服务系统
  6. 编辑器核心:Monaco
  7. [扩展系统:Extension Host 架构](#扩展系统:Extension Host 架构)
  8. 扩展开发全解析
  9. [Contribution Points:声明式扩展](#Contribution Points:声明式扩展)
  10. [Activation Events:懒加载的魔法](#Activation Events:懒加载的魔法)
  11. [Language Server Protocol (LSP)](#Language Server Protocol (LSP))
  12. [配置系统:settings.json 的背后](#配置系统:settings.json 的背后)
  13. [关键子系统:终端 / 调试 / 主题](#关键子系统:终端 / 调试 / 主题)
  14. 远程开发架构
  15. [AI / Copilot 集成原理](#AI / Copilot 集成原理)
  16. [Cursor 等 Fork 与 VSCode 的关系](#Cursor 等 Fork 与 VSCode 的关系)
  17. 实战:开发一个插件
  18. 关键源码文件索引
  19. [VSCode API 速查表](#VSCode API 速查表)

1. 全局架构总览

VS Code 本质上是一个 Electron 应用 ,但它的架构远比普通 Electron 应用复杂。核心设计哲学是:主进程负责 UI 与原生能力,插件在独立进程中运行,两者通过 IPC / JSON-RPC 通信。
#mermaid-svg-fNaB4in2su4rbttW{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fNaB4in2su4rbttW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fNaB4in2su4rbttW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fNaB4in2su4rbttW .error-icon{fill:#552222;}#mermaid-svg-fNaB4in2su4rbttW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fNaB4in2su4rbttW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fNaB4in2su4rbttW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fNaB4in2su4rbttW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fNaB4in2su4rbttW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fNaB4in2su4rbttW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fNaB4in2su4rbttW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fNaB4in2su4rbttW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fNaB4in2su4rbttW .marker.cross{stroke:#333333;}#mermaid-svg-fNaB4in2su4rbttW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fNaB4in2su4rbttW p{margin:0;}#mermaid-svg-fNaB4in2su4rbttW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fNaB4in2su4rbttW .cluster-label text{fill:#333;}#mermaid-svg-fNaB4in2su4rbttW .cluster-label span{color:#333;}#mermaid-svg-fNaB4in2su4rbttW .cluster-label span p{background-color:transparent;}#mermaid-svg-fNaB4in2su4rbttW .label text,#mermaid-svg-fNaB4in2su4rbttW span{fill:#333;color:#333;}#mermaid-svg-fNaB4in2su4rbttW .node rect,#mermaid-svg-fNaB4in2su4rbttW .node circle,#mermaid-svg-fNaB4in2su4rbttW .node ellipse,#mermaid-svg-fNaB4in2su4rbttW .node polygon,#mermaid-svg-fNaB4in2su4rbttW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fNaB4in2su4rbttW .rough-node .label text,#mermaid-svg-fNaB4in2su4rbttW .node .label text,#mermaid-svg-fNaB4in2su4rbttW .image-shape .label,#mermaid-svg-fNaB4in2su4rbttW .icon-shape .label{text-anchor:middle;}#mermaid-svg-fNaB4in2su4rbttW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fNaB4in2su4rbttW .rough-node .label,#mermaid-svg-fNaB4in2su4rbttW .node .label,#mermaid-svg-fNaB4in2su4rbttW .image-shape .label,#mermaid-svg-fNaB4in2su4rbttW .icon-shape .label{text-align:center;}#mermaid-svg-fNaB4in2su4rbttW .node.clickable{cursor:pointer;}#mermaid-svg-fNaB4in2su4rbttW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fNaB4in2su4rbttW .arrowheadPath{fill:#333333;}#mermaid-svg-fNaB4in2su4rbttW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fNaB4in2su4rbttW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fNaB4in2su4rbttW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fNaB4in2su4rbttW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fNaB4in2su4rbttW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fNaB4in2su4rbttW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fNaB4in2su4rbttW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fNaB4in2su4rbttW .cluster text{fill:#333;}#mermaid-svg-fNaB4in2su4rbttW .cluster span{color:#333;}#mermaid-svg-fNaB4in2su4rbttW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fNaB4in2su4rbttW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fNaB4in2su4rbttW rect.text{fill:none;stroke-width:0;}#mermaid-svg-fNaB4in2su4rbttW .icon-shape,#mermaid-svg-fNaB4in2su4rbttW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fNaB4in2su4rbttW .icon-shape p,#mermaid-svg-fNaB4in2su4rbttW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fNaB4in2su4rbttW .icon-shape .label rect,#mermaid-svg-fNaB4in2su4rbttW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fNaB4in2su4rbttW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fNaB4in2su4rbttW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fNaB4in2su4rbttW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Electron Shell
IPC
IPC · JSON-RPC
Extension Host · Node.js / Web Worker
所有插件运行在这里
独立进程 · 崩溃不影响 UI
通过 JSON-RPC 通信
Main Process · Node.js
窗口管理
原生菜单
文件系统
子进程管理
Renderer Process · Chromium
Workbench UI
Editor · Monaco
Terminal
Debug UI

三层架构的关键点:

层级 运行时 职责 插件能否触及
Main Process Node.js 窗口管理、原生集成、生命周期 ❌ 不直接访问
Renderer Process Chromium 渲染 UI、编辑器、终端 ❌ 不能操作 DOM
Extension Host Node.js / Web Worker 运行插件逻辑 ✅ 插件的唯一运行空间

一条主线记住所有细节:分层 + 多进程 + 依赖注入。上层(workbench)依赖下层(editor/platform/base),但反过来不允许;插件永远跑在独立进程,通过强类型 RPC 与主进程对话。


2. 进程模型:为什么 VSCode 不会卡死

这是 VSCode 最重要的架构决策之一。

2.1 为什么插件不能访问 DOM?

VS Code 明确禁止插件直接操作 DOM。原因:

  1. 稳定性:一个坏插件的 CSS 不应该让整个编辑器崩溃;
  2. 性能:DOM 结构是内部实现,随时可能重构;
  3. 跨平台:Web 版(vscode.dev)和桌面版共用同一套插件 API。
typescript 复制代码
// ❌ 你永远不能这样做(在 VS Code 插件中)
document.querySelector('.editor')?.style.color = 'red';

// ✅ 你必须通过 API
vscode.workspace.getConfiguration().update('editor.fontSize', 14);

2.2 多 Extension Host 的设计

VSCode 可以同时运行多个 Extension Host,按运行位置分为三类:LocalProcess(本地 Node)、LocalWebWorker(浏览器 Web Worker)、Remote(远端 SSH/容器/WSL)。

配置 Local EH Web EH Remote EH
桌面版
远程开发 (SSH/Container/WSL)
vscode.dev (Web)
Web + Codespaces

2.3 进程模型的完整视图

#mermaid-svg-IoKQemLND6Heite3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-IoKQemLND6Heite3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-IoKQemLND6Heite3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-IoKQemLND6Heite3 .error-icon{fill:#552222;}#mermaid-svg-IoKQemLND6Heite3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-IoKQemLND6Heite3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-IoKQemLND6Heite3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-IoKQemLND6Heite3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-IoKQemLND6Heite3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-IoKQemLND6Heite3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-IoKQemLND6Heite3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-IoKQemLND6Heite3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-IoKQemLND6Heite3 .marker.cross{stroke:#333333;}#mermaid-svg-IoKQemLND6Heite3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-IoKQemLND6Heite3 p{margin:0;}#mermaid-svg-IoKQemLND6Heite3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-IoKQemLND6Heite3 .cluster-label text{fill:#333;}#mermaid-svg-IoKQemLND6Heite3 .cluster-label span{color:#333;}#mermaid-svg-IoKQemLND6Heite3 .cluster-label span p{background-color:transparent;}#mermaid-svg-IoKQemLND6Heite3 .label text,#mermaid-svg-IoKQemLND6Heite3 span{fill:#333;color:#333;}#mermaid-svg-IoKQemLND6Heite3 .node rect,#mermaid-svg-IoKQemLND6Heite3 .node circle,#mermaid-svg-IoKQemLND6Heite3 .node ellipse,#mermaid-svg-IoKQemLND6Heite3 .node polygon,#mermaid-svg-IoKQemLND6Heite3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-IoKQemLND6Heite3 .rough-node .label text,#mermaid-svg-IoKQemLND6Heite3 .node .label text,#mermaid-svg-IoKQemLND6Heite3 .image-shape .label,#mermaid-svg-IoKQemLND6Heite3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-IoKQemLND6Heite3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-IoKQemLND6Heite3 .rough-node .label,#mermaid-svg-IoKQemLND6Heite3 .node .label,#mermaid-svg-IoKQemLND6Heite3 .image-shape .label,#mermaid-svg-IoKQemLND6Heite3 .icon-shape .label{text-align:center;}#mermaid-svg-IoKQemLND6Heite3 .node.clickable{cursor:pointer;}#mermaid-svg-IoKQemLND6Heite3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-IoKQemLND6Heite3 .arrowheadPath{fill:#333333;}#mermaid-svg-IoKQemLND6Heite3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-IoKQemLND6Heite3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-IoKQemLND6Heite3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IoKQemLND6Heite3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-IoKQemLND6Heite3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IoKQemLND6Heite3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-IoKQemLND6Heite3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-IoKQemLND6Heite3 .cluster text{fill:#333;}#mermaid-svg-IoKQemLND6Heite3 .cluster span{color:#333;}#mermaid-svg-IoKQemLND6Heite3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-IoKQemLND6Heite3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-IoKQemLND6Heite3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-IoKQemLND6Heite3 .icon-shape,#mermaid-svg-IoKQemLND6Heite3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-IoKQemLND6Heite3 .icon-shape p,#mermaid-svg-IoKQemLND6Heite3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-IoKQemLND6Heite3 .icon-shape .label rect,#mermaid-svg-IoKQemLND6Heite3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-IoKQemLND6Heite3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-IoKQemLND6Heite3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-IoKQemLND6Heite3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Renderer Process (Browser)
Electron Main Process
IPC

ipcMain/ipcRenderer
MessagePort / WebSocket

RPC 协议
Web Worker API
Extension Host Process (独立 Node.js 进程)
Extensions
Extension A

ESLint
Extension B

Git
Extension C

Python
Extension API

vscode.*

commands / languages / workspace

debug / terminal / window
Workers
Worker 1

Editor
Worker 2

Terminal
Worker N

Search
Workbench (UI + Logic)
Editor
Explorer
Terminal UI
Debug View
Search
Output Panel
Window Manager
Menu Manager
ExtensionHostServer

启动/管理子进程

为什么要多进程?

  • 稳定性隔离:扩展运行在独立进程,崩溃不会拖垮编辑器;Worker 处理计算密集任务,避免阻塞 UI。
  • 性能优化:语法分析、补全等 CPU 密集任务放 Worker;扩展进程在后台,不影响 UI 响应。
  • 安全沙箱:扩展只能通过 API 通信,无法直接访问 DOM,API 经过权限控制。

3. 启动流程

3.1 启动时序图

Extension Host Process Desktop Main workbench.desktop.main.ts Workbench Common workbench.common.main.ts Renderer Process bootstrap-esm Electron Main Process 用户 Extension Host Process Desktop Main workbench.desktop.main.ts Workbench Common workbench.common.main.ts Renderer Process bootstrap-esm Electron Main Process 用户 #mermaid-svg-UFNpThqanAkfiC2D{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UFNpThqanAkfiC2D .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UFNpThqanAkfiC2D .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UFNpThqanAkfiC2D .error-icon{fill:#552222;}#mermaid-svg-UFNpThqanAkfiC2D .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UFNpThqanAkfiC2D .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UFNpThqanAkfiC2D .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UFNpThqanAkfiC2D .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UFNpThqanAkfiC2D .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UFNpThqanAkfiC2D .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UFNpThqanAkfiC2D .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UFNpThqanAkfiC2D .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UFNpThqanAkfiC2D .marker.cross{stroke:#333333;}#mermaid-svg-UFNpThqanAkfiC2D svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UFNpThqanAkfiC2D p{margin:0;}#mermaid-svg-UFNpThqanAkfiC2D .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UFNpThqanAkfiC2D text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-UFNpThqanAkfiC2D .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UFNpThqanAkfiC2D .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-UFNpThqanAkfiC2D .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-UFNpThqanAkfiC2D .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-UFNpThqanAkfiC2D #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-UFNpThqanAkfiC2D .sequenceNumber{fill:white;}#mermaid-svg-UFNpThqanAkfiC2D #sequencenumber{fill:#333;}#mermaid-svg-UFNpThqanAkfiC2D #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-UFNpThqanAkfiC2D .messageText{fill:#333;stroke:none;}#mermaid-svg-UFNpThqanAkfiC2D .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UFNpThqanAkfiC2D .labelText,#mermaid-svg-UFNpThqanAkfiC2D .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-UFNpThqanAkfiC2D .loopText,#mermaid-svg-UFNpThqanAkfiC2D .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-UFNpThqanAkfiC2D .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UFNpThqanAkfiC2D .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UFNpThqanAkfiC2D .noteText,#mermaid-svg-UFNpThqanAkfiC2D .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-UFNpThqanAkfiC2D .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UFNpThqanAkfiC2D .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UFNpThqanAkfiC2D .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UFNpThqanAkfiC2D .actorPopupMenu{position:absolute;}#mermaid-svg-UFNpThqanAkfiC2D .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-UFNpThqanAkfiC2D .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UFNpThqanAkfiC2D .actor-man circle,#mermaid-svg-UFNpThqanAkfiC2D line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-UFNpThqanAkfiC2D :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动 VSCode 创建 BrowserWindow 加载公共模块 加载桌面端模块 启动扩展宿主进程 VSCode 就绪

3.2 关键启动文件解析

bootstrap-esm.ts --- ESM 引导入口。这是 VSCode 启动时最先加载的文件,负责:

  • ESM 模块解析 Hook :覆盖 Node.js 的 ESM 解析逻辑,支持从 ASAR 归档(node_modules.asar)加载模块;
  • 全局变量设置 :注入 _VSCODE_PRODUCT_JSON_VSCODE_PACKAGE_JSON 等;
  • 入口动态导入:根据运行模式(CLI / 桌面 / Web)加载对应的 main 文件。

workbench.common.main.ts --- 公共模块注册。这是整个 Workbench 的「总装配」文件,按顺序导入并初始化:

  1. Editor 模块editor.all.js --- 加载 Monaco Editor 所有功能;
  2. 扩展宿主桥接extensionHost.contribution.js --- 建立主线程与扩展进程的通信;
  3. Workbench 贡献:文件树、标签页、侧边栏等 UI 组件;
  4. API 扩展点:菜单、配置、视图等扩展点注册;
  5. 贡献模块:搜索、调试、终端、SCM 等功能模块。

workbench.desktop.main.ts --- 桌面端特化。在公共模块之上,额外注册 Electron 桌面特有的服务:extensionHostStarter(启动扩展宿主进程)、lifecycleService(窗口生命周期)、nativeHostService(原生窗口操作)、secretStorageServiceencryptionServiceupdateService 等。


4. 源码目录结构与分层

4.1 顶层目录

复制代码
vscode/
├── src/
│   ├── vs/                        ← 核心源码(最重要的目录)
│   │   ├── base/                  ← 基础工具库(事件系统、DOM 工具等)
│   │   ├── code/                  ← Electron 主进程入口
│   │   ├── editor/                ← Monaco Editor 核心(可独立使用)
│   │   ├── platform/              ← 平台抽象层(文件系统、IPC、进程)
│   │   └── workbench/             ← Workbench UI(最大的子系统)
│   │       ├── workbench.common.main.ts   ← 公共模块入口
│   │       ├── workbench.sandbox.main.ts  ← 沙箱模块入口
│   │       ├── api/               ← 插件 API 实现(VS Code 侧)
│   │       ├── contrib/           ← 内置功能(也是以「插件」形式存在)
│   │       └── services/          ← 核心服务层
│   │
│   ├── vscode-dts/                ← VS Code API 类型定义(.d.ts 文件)
│   ├── bootstrap-*.ts             ← 各种启动引导文件
│   ├── main.ts                    ← Electron 主进程入口
│   └── cli.ts                     ← `code` CLI 入口
│
├── extensions/                    ← 内置插件(!很多功能本身就是插件)
│   ├── typescript-language-features/  ← TypeScript/JS 语言支持
│   ├── markdown-language-features/    ← Markdown 支持
│   ├── git/                       ← Git 集成
│   └── ...
│
├── remote/                        ← 远程开发相关(remote-agent 等)
├── cli/                           ← VS Code CLI(Rust 编写)
├── build/                         ← 构建脚本和配置
├── test/                          ← 测试
└── resources/                     ← 图标、本地化资源等

4.2 src/vs 的严格分层

src/vs 是整个产品的代码根。它严格分层,依赖方向只能从上往下:
#mermaid-svg-mOgv539z6Vaie9d6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mOgv539z6Vaie9d6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mOgv539z6Vaie9d6 .error-icon{fill:#552222;}#mermaid-svg-mOgv539z6Vaie9d6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mOgv539z6Vaie9d6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mOgv539z6Vaie9d6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mOgv539z6Vaie9d6 .marker.cross{stroke:#333333;}#mermaid-svg-mOgv539z6Vaie9d6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mOgv539z6Vaie9d6 p{margin:0;}#mermaid-svg-mOgv539z6Vaie9d6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mOgv539z6Vaie9d6 .cluster-label text{fill:#333;}#mermaid-svg-mOgv539z6Vaie9d6 .cluster-label span{color:#333;}#mermaid-svg-mOgv539z6Vaie9d6 .cluster-label span p{background-color:transparent;}#mermaid-svg-mOgv539z6Vaie9d6 .label text,#mermaid-svg-mOgv539z6Vaie9d6 span{fill:#333;color:#333;}#mermaid-svg-mOgv539z6Vaie9d6 .node rect,#mermaid-svg-mOgv539z6Vaie9d6 .node circle,#mermaid-svg-mOgv539z6Vaie9d6 .node ellipse,#mermaid-svg-mOgv539z6Vaie9d6 .node polygon,#mermaid-svg-mOgv539z6Vaie9d6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mOgv539z6Vaie9d6 .rough-node .label text,#mermaid-svg-mOgv539z6Vaie9d6 .node .label text,#mermaid-svg-mOgv539z6Vaie9d6 .image-shape .label,#mermaid-svg-mOgv539z6Vaie9d6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-mOgv539z6Vaie9d6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mOgv539z6Vaie9d6 .rough-node .label,#mermaid-svg-mOgv539z6Vaie9d6 .node .label,#mermaid-svg-mOgv539z6Vaie9d6 .image-shape .label,#mermaid-svg-mOgv539z6Vaie9d6 .icon-shape .label{text-align:center;}#mermaid-svg-mOgv539z6Vaie9d6 .node.clickable{cursor:pointer;}#mermaid-svg-mOgv539z6Vaie9d6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mOgv539z6Vaie9d6 .arrowheadPath{fill:#333333;}#mermaid-svg-mOgv539z6Vaie9d6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mOgv539z6Vaie9d6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mOgv539z6Vaie9d6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mOgv539z6Vaie9d6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mOgv539z6Vaie9d6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mOgv539z6Vaie9d6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mOgv539z6Vaie9d6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mOgv539z6Vaie9d6 .cluster text{fill:#333;}#mermaid-svg-mOgv539z6Vaie9d6 .cluster span{color:#333;}#mermaid-svg-mOgv539z6Vaie9d6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mOgv539z6Vaie9d6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mOgv539z6Vaie9d6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-mOgv539z6Vaie9d6 .icon-shape,#mermaid-svg-mOgv539z6Vaie9d6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mOgv539z6Vaie9d6 .icon-shape p,#mermaid-svg-mOgv539z6Vaie9d6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mOgv539z6Vaie9d6 .icon-shape .label rect,#mermaid-svg-mOgv539z6Vaie9d6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mOgv539z6Vaie9d6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mOgv539z6Vaie9d6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mOgv539z6Vaie9d6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} code/ · 产品外壳
electron-main
electron-sandbox
electron-utility
workbench/ · 工作台
contrib · 文件树/调试/终端
services · 核心服务
api · 扩展 API 宿主端
editor/ · Monaco 编辑器
common/model · 文本模型
browser · 视图渲染
common/languages · 语言接口
platform/ · 平台服务
configuration · 配置
instantiation · 依赖注入
files · 文件服务
storage/keybinding/telemetry
base/ · 基础设施
common · URI/路径/日志/事件
browser · DOM 工具
node · fs/流

记忆口诀:base → platform → editor → workbench → code。上层能 import 下层,下层绝对不能反向引用(会在架构检查里报错)。

关键洞察:extensions/ 目录 ------ VS Code 的很多「内置功能」本身就是插件。Git 支持、TypeScript 语言支持、Markdown 预览、Emmet 等全部以插件形式存在。这意味着:你可以通过阅读这些内置插件源码来学习如何写插件;VS Code 的插件 API 足够强大,强大到能实现核心功能;内置插件与第三方插件使用完全相同的 API。

4.3 Target Environment 命名约定

同一个 common 接口,要在不同运行时实现。VSCode 用目录后缀约定「这个文件跑在什么环境」:

目录后缀 运行环境 可用能力
common 所有环境通用 纯逻辑、无平台 API
browser 浏览器 / DOM DOM、fetch(无 Node)
node Node.js fs、child_process 等
electron-sandbox 渲染进程窗口 受限的 Electron 渲染端
electron-main 主进程 完整 Electron、窗口管理
electron-utility Utility 进程 独立辅助进程

例如 IFileServicecommon 接口、node 实现(disk)、browser 实现(web)。import 时根据当前 build target 选对应文件。


5. 依赖注入与服务系统

5.1 为什么用 DI?

VSCode 不用全局单例,而用一套自研的 依赖注入(DI) ,核心位于 src/vs/platform/instantiation/。原因是:同一份代码要跑在 主进程 / 渲染进程 / 扩展宿主 / Web Worker / 远端 不同环境,每个环境提供的服务实现不同(文件服务在 Web 下是 fetch,在 Node 下是 fs)。DI 让「接口不变、实现随环境替换」。

typescript 复制代码
// 1. 定义服务标识符(通常是 interface)
export const IMyService = createDecorator<IMyService>('myService');

// 2. 实现服务
export class MyService implements IMyService { /* ... */ }

// 3. 注册服务(单例)
registerSingleton(IMyService, MyService);

// 4. 在构造函数中注入(服务依赖写在末尾)
constructor(
  @IMyService private readonly myService: IMyService,
  @IConfigurationService private readonly configService: IConfigurationService,
) {}

5.2 DI 容器工作方式

#mermaid-svg-XSDIXAMeib761tmp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XSDIXAMeib761tmp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XSDIXAMeib761tmp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XSDIXAMeib761tmp .error-icon{fill:#552222;}#mermaid-svg-XSDIXAMeib761tmp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XSDIXAMeib761tmp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XSDIXAMeib761tmp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XSDIXAMeib761tmp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XSDIXAMeib761tmp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XSDIXAMeib761tmp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XSDIXAMeib761tmp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XSDIXAMeib761tmp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XSDIXAMeib761tmp .marker.cross{stroke:#333333;}#mermaid-svg-XSDIXAMeib761tmp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XSDIXAMeib761tmp p{margin:0;}#mermaid-svg-XSDIXAMeib761tmp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XSDIXAMeib761tmp .cluster-label text{fill:#333;}#mermaid-svg-XSDIXAMeib761tmp .cluster-label span{color:#333;}#mermaid-svg-XSDIXAMeib761tmp .cluster-label span p{background-color:transparent;}#mermaid-svg-XSDIXAMeib761tmp .label text,#mermaid-svg-XSDIXAMeib761tmp span{fill:#333;color:#333;}#mermaid-svg-XSDIXAMeib761tmp .node rect,#mermaid-svg-XSDIXAMeib761tmp .node circle,#mermaid-svg-XSDIXAMeib761tmp .node ellipse,#mermaid-svg-XSDIXAMeib761tmp .node polygon,#mermaid-svg-XSDIXAMeib761tmp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XSDIXAMeib761tmp .rough-node .label text,#mermaid-svg-XSDIXAMeib761tmp .node .label text,#mermaid-svg-XSDIXAMeib761tmp .image-shape .label,#mermaid-svg-XSDIXAMeib761tmp .icon-shape .label{text-anchor:middle;}#mermaid-svg-XSDIXAMeib761tmp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XSDIXAMeib761tmp .rough-node .label,#mermaid-svg-XSDIXAMeib761tmp .node .label,#mermaid-svg-XSDIXAMeib761tmp .image-shape .label,#mermaid-svg-XSDIXAMeib761tmp .icon-shape .label{text-align:center;}#mermaid-svg-XSDIXAMeib761tmp .node.clickable{cursor:pointer;}#mermaid-svg-XSDIXAMeib761tmp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XSDIXAMeib761tmp .arrowheadPath{fill:#333333;}#mermaid-svg-XSDIXAMeib761tmp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XSDIXAMeib761tmp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XSDIXAMeib761tmp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSDIXAMeib761tmp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XSDIXAMeib761tmp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSDIXAMeib761tmp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XSDIXAMeib761tmp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XSDIXAMeib761tmp .cluster text{fill:#333;}#mermaid-svg-XSDIXAMeib761tmp .cluster span{color:#333;}#mermaid-svg-XSDIXAMeib761tmp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XSDIXAMeib761tmp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XSDIXAMeib761tmp rect.text{fill:none;stroke-width:0;}#mermaid-svg-XSDIXAMeib761tmp .icon-shape,#mermaid-svg-XSDIXAMeib761tmp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSDIXAMeib761tmp .icon-shape p,#mermaid-svg-XSDIXAMeib761tmp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XSDIXAMeib761tmp .icon-shape .label rect,#mermaid-svg-XSDIXAMeib761tmp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSDIXAMeib761tmp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XSDIXAMeib761tmp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XSDIXAMeib761tmp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} InstantiationService (DI 容器)
解析流程
未找到
找到
单例
瞬态
工厂
请求服务
查找注册表
查找父容器 · 分层 DI
检查依赖
递归解析
创建实例
生命周期
缓存返回
新建返回
工厂函数
注册表
IConfigurationService → ConfigurationService
IKeybindingService → KeybindingService
IStorageService → StorageService
IExtensionService → NativeExtensionService

5.3 服务分层

#mermaid-svg-cfyYpwNzXctoyN2e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cfyYpwNzXctoyN2e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cfyYpwNzXctoyN2e .error-icon{fill:#552222;}#mermaid-svg-cfyYpwNzXctoyN2e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cfyYpwNzXctoyN2e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cfyYpwNzXctoyN2e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cfyYpwNzXctoyN2e .marker.cross{stroke:#333333;}#mermaid-svg-cfyYpwNzXctoyN2e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cfyYpwNzXctoyN2e p{margin:0;}#mermaid-svg-cfyYpwNzXctoyN2e .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cfyYpwNzXctoyN2e .cluster-label text{fill:#333;}#mermaid-svg-cfyYpwNzXctoyN2e .cluster-label span{color:#333;}#mermaid-svg-cfyYpwNzXctoyN2e .cluster-label span p{background-color:transparent;}#mermaid-svg-cfyYpwNzXctoyN2e .label text,#mermaid-svg-cfyYpwNzXctoyN2e span{fill:#333;color:#333;}#mermaid-svg-cfyYpwNzXctoyN2e .node rect,#mermaid-svg-cfyYpwNzXctoyN2e .node circle,#mermaid-svg-cfyYpwNzXctoyN2e .node ellipse,#mermaid-svg-cfyYpwNzXctoyN2e .node polygon,#mermaid-svg-cfyYpwNzXctoyN2e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cfyYpwNzXctoyN2e .rough-node .label text,#mermaid-svg-cfyYpwNzXctoyN2e .node .label text,#mermaid-svg-cfyYpwNzXctoyN2e .image-shape .label,#mermaid-svg-cfyYpwNzXctoyN2e .icon-shape .label{text-anchor:middle;}#mermaid-svg-cfyYpwNzXctoyN2e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cfyYpwNzXctoyN2e .rough-node .label,#mermaid-svg-cfyYpwNzXctoyN2e .node .label,#mermaid-svg-cfyYpwNzXctoyN2e .image-shape .label,#mermaid-svg-cfyYpwNzXctoyN2e .icon-shape .label{text-align:center;}#mermaid-svg-cfyYpwNzXctoyN2e .node.clickable{cursor:pointer;}#mermaid-svg-cfyYpwNzXctoyN2e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cfyYpwNzXctoyN2e .arrowheadPath{fill:#333333;}#mermaid-svg-cfyYpwNzXctoyN2e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cfyYpwNzXctoyN2e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cfyYpwNzXctoyN2e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cfyYpwNzXctoyN2e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cfyYpwNzXctoyN2e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cfyYpwNzXctoyN2e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cfyYpwNzXctoyN2e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cfyYpwNzXctoyN2e .cluster text{fill:#333;}#mermaid-svg-cfyYpwNzXctoyN2e .cluster span{color:#333;}#mermaid-svg-cfyYpwNzXctoyN2e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cfyYpwNzXctoyN2e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cfyYpwNzXctoyN2e rect.text{fill:none;stroke-width:0;}#mermaid-svg-cfyYpwNzXctoyN2e .icon-shape,#mermaid-svg-cfyYpwNzXctoyN2e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cfyYpwNzXctoyN2e .icon-shape p,#mermaid-svg-cfyYpwNzXctoyN2e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cfyYpwNzXctoyN2e .icon-shape .label rect,#mermaid-svg-cfyYpwNzXctoyN2e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cfyYpwNzXctoyN2e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cfyYpwNzXctoyN2e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cfyYpwNzXctoyN2e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Platform Services
IConfigurationService · 配置读取
IStorageService · 键值存储
IKeybindingService · 快捷键系统
ILogService · 日志服务
ITelemetryService · 遥测数据
Workbench Services
IEditorService · 编辑器管理
IFilesService · 文件操作
ITerminalService · 终端管理
IDebugService · 调试管理
IExtensionService · 扩展管理
Contribution Services
搜索服务
Git 服务
调试服务
终端服务

5.4 事件系统

VSCode 使用自研的事件发射器,比 Node.js 的 EventEmitter 更类型安全:

typescript 复制代码
import { Emitter, Event } from 'vs/base/common/event';

class MyService {
    private _onDidChange = new Emitter<string>();
    // 对外暴露只读事件
    readonly onDidChange: Event<string> = this._onDidChange.event;

    doSomething() {
        this._onDidChange.fire('changed');
    }
}

myService.onDidChange(value => console.log(value)); // 'changed'

6. 编辑器核心:Monaco

Monaco 是 VSCode 的编辑器核心,同时也是一个独立的开源项目(microsoft/monaco-editor),可被任意网页嵌入。
#mermaid-svg-O4gE96TCtgDA5Tts{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-O4gE96TCtgDA5Tts .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-O4gE96TCtgDA5Tts .error-icon{fill:#552222;}#mermaid-svg-O4gE96TCtgDA5Tts .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-O4gE96TCtgDA5Tts .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-O4gE96TCtgDA5Tts .marker{fill:#333333;stroke:#333333;}#mermaid-svg-O4gE96TCtgDA5Tts .marker.cross{stroke:#333333;}#mermaid-svg-O4gE96TCtgDA5Tts svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-O4gE96TCtgDA5Tts p{margin:0;}#mermaid-svg-O4gE96TCtgDA5Tts .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-O4gE96TCtgDA5Tts .cluster-label text{fill:#333;}#mermaid-svg-O4gE96TCtgDA5Tts .cluster-label span{color:#333;}#mermaid-svg-O4gE96TCtgDA5Tts .cluster-label span p{background-color:transparent;}#mermaid-svg-O4gE96TCtgDA5Tts .label text,#mermaid-svg-O4gE96TCtgDA5Tts span{fill:#333;color:#333;}#mermaid-svg-O4gE96TCtgDA5Tts .node rect,#mermaid-svg-O4gE96TCtgDA5Tts .node circle,#mermaid-svg-O4gE96TCtgDA5Tts .node ellipse,#mermaid-svg-O4gE96TCtgDA5Tts .node polygon,#mermaid-svg-O4gE96TCtgDA5Tts .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-O4gE96TCtgDA5Tts .rough-node .label text,#mermaid-svg-O4gE96TCtgDA5Tts .node .label text,#mermaid-svg-O4gE96TCtgDA5Tts .image-shape .label,#mermaid-svg-O4gE96TCtgDA5Tts .icon-shape .label{text-anchor:middle;}#mermaid-svg-O4gE96TCtgDA5Tts .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-O4gE96TCtgDA5Tts .rough-node .label,#mermaid-svg-O4gE96TCtgDA5Tts .node .label,#mermaid-svg-O4gE96TCtgDA5Tts .image-shape .label,#mermaid-svg-O4gE96TCtgDA5Tts .icon-shape .label{text-align:center;}#mermaid-svg-O4gE96TCtgDA5Tts .node.clickable{cursor:pointer;}#mermaid-svg-O4gE96TCtgDA5Tts .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-O4gE96TCtgDA5Tts .arrowheadPath{fill:#333333;}#mermaid-svg-O4gE96TCtgDA5Tts .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-O4gE96TCtgDA5Tts .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-O4gE96TCtgDA5Tts .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-O4gE96TCtgDA5Tts .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-O4gE96TCtgDA5Tts .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-O4gE96TCtgDA5Tts .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-O4gE96TCtgDA5Tts .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-O4gE96TCtgDA5Tts .cluster text{fill:#333;}#mermaid-svg-O4gE96TCtgDA5Tts .cluster span{color:#333;}#mermaid-svg-O4gE96TCtgDA5Tts div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-O4gE96TCtgDA5Tts .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-O4gE96TCtgDA5Tts rect.text{fill:none;stroke-width:0;}#mermaid-svg-O4gE96TCtgDA5Tts .icon-shape,#mermaid-svg-O4gE96TCtgDA5Tts .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-O4gE96TCtgDA5Tts .icon-shape p,#mermaid-svg-O4gE96TCtgDA5Tts .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-O4gE96TCtgDA5Tts .icon-shape .label rect,#mermaid-svg-O4gE96TCtgDA5Tts .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-O4gE96TCtgDA5Tts .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-O4gE96TCtgDA5Tts .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-O4gE96TCtgDA5Tts :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Worker 计算层
Tokenization · 语法高亮
Word Wrap
Indentation
Links Detection
ViewModel 视图模型
折叠状态
光标位置
选区状态
可见区域
Model 数据层
ITextModel
getValue
getLineCount
applyEdits
onDidChangeContent
View 视图层
Text Renderer
Decoration Layers
Overlay Widgets
Minimap
Glyph Margin
Indentation Guide
ICodeEditor (接口)
getModel → ITextModel
getPosition → Position
revealPosition → void
executeEdits → void

6.1 核心数据结构

typescript 复制代码
interface ITextModel {
  readonly uri: URI;
  readonly languageId: string;
  readonly versionId: number;

  getValue(): string;
  getLineCount(): number;
  getLineContent(lineNumber: number): string;
  getWordAtPosition(position: IPosition): IWordAtPosition | null;

  applyEdits(edits: IIdentifiedSingleEditOperation[]): void;
  onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;
}

interface IPosition { lineNumber: number; column: number; }  // 1-based
interface IRange {
  startLineNumber: number; startColumn: number;
  endLineNumber: number;   endColumn: number;
}

核心概念 :Model(ITextModel,文本内容内存表示,支持增量更新)→ View(将 Model 渲染为 DOM)→ ViewModel(连接 Model 和 View,处理坐标转换)→ Worker(计算密集任务)。

6.2 文档编辑流程

#mermaid-svg-WBhxoOAlrtJ882Cl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WBhxoOAlrtJ882Cl .error-icon{fill:#552222;}#mermaid-svg-WBhxoOAlrtJ882Cl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WBhxoOAlrtJ882Cl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WBhxoOAlrtJ882Cl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WBhxoOAlrtJ882Cl .marker.cross{stroke:#333333;}#mermaid-svg-WBhxoOAlrtJ882Cl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WBhxoOAlrtJ882Cl p{margin:0;}#mermaid-svg-WBhxoOAlrtJ882Cl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster-label text{fill:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster-label span{color:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster-label span p{background-color:transparent;}#mermaid-svg-WBhxoOAlrtJ882Cl .label text,#mermaid-svg-WBhxoOAlrtJ882Cl span{fill:#333;color:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl .node rect,#mermaid-svg-WBhxoOAlrtJ882Cl .node circle,#mermaid-svg-WBhxoOAlrtJ882Cl .node ellipse,#mermaid-svg-WBhxoOAlrtJ882Cl .node polygon,#mermaid-svg-WBhxoOAlrtJ882Cl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WBhxoOAlrtJ882Cl .rough-node .label text,#mermaid-svg-WBhxoOAlrtJ882Cl .node .label text,#mermaid-svg-WBhxoOAlrtJ882Cl .image-shape .label,#mermaid-svg-WBhxoOAlrtJ882Cl .icon-shape .label{text-anchor:middle;}#mermaid-svg-WBhxoOAlrtJ882Cl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WBhxoOAlrtJ882Cl .rough-node .label,#mermaid-svg-WBhxoOAlrtJ882Cl .node .label,#mermaid-svg-WBhxoOAlrtJ882Cl .image-shape .label,#mermaid-svg-WBhxoOAlrtJ882Cl .icon-shape .label{text-align:center;}#mermaid-svg-WBhxoOAlrtJ882Cl .node.clickable{cursor:pointer;}#mermaid-svg-WBhxoOAlrtJ882Cl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WBhxoOAlrtJ882Cl .arrowheadPath{fill:#333333;}#mermaid-svg-WBhxoOAlrtJ882Cl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WBhxoOAlrtJ882Cl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WBhxoOAlrtJ882Cl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WBhxoOAlrtJ882Cl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WBhxoOAlrtJ882Cl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WBhxoOAlrtJ882Cl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster text{fill:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl .cluster span{color:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WBhxoOAlrtJ882Cl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WBhxoOAlrtJ882Cl rect.text{fill:none;stroke-width:0;}#mermaid-svg-WBhxoOAlrtJ882Cl .icon-shape,#mermaid-svg-WBhxoOAlrtJ882Cl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WBhxoOAlrtJ882Cl .icon-shape p,#mermaid-svg-WBhxoOAlrtJ882Cl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WBhxoOAlrtJ882Cl .icon-shape .label rect,#mermaid-svg-WBhxoOAlrtJ882Cl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WBhxoOAlrtJ882Cl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WBhxoOAlrtJ882Cl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WBhxoOAlrtJ882Cl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 用户编辑 → keydown
Editor 处理输入
model.applyEdits
ContentChange 计算
Model 数据更新
触发 onDidChangeContent
View 重渲染
计算受影响行
重新布局 Layout
重新绘制 Render
通知 Worker 更新语法高亮
Worker 重新 Tokenize
返回新 Token 数据
View 更新高亮层

6.3 Worker 机制

Worker 负责处理计算密集型任务(语法高亮 tokenize、自动换行、缩进、链接检测),避免阻塞主线程 UI。语法高亮基于 vscode-textmate(TextMate grammar)+ vscode-oniguruma(Oniguruma 正则引擎);终端基于 @xterm/xterm


7. 扩展系统:Extension Host 架构

7.1 为什么需要 Extension Host?

VSCode 选择让插件运行在独立进程中,而非 Renderer 进程。对比:
#mermaid-svg-1UyFZGMGSrENPkjL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-1UyFZGMGSrENPkjL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-1UyFZGMGSrENPkjL .error-icon{fill:#552222;}#mermaid-svg-1UyFZGMGSrENPkjL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-1UyFZGMGSrENPkjL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-1UyFZGMGSrENPkjL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-1UyFZGMGSrENPkjL .marker.cross{stroke:#333333;}#mermaid-svg-1UyFZGMGSrENPkjL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-1UyFZGMGSrENPkjL p{margin:0;}#mermaid-svg-1UyFZGMGSrENPkjL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-1UyFZGMGSrENPkjL .cluster-label text{fill:#333;}#mermaid-svg-1UyFZGMGSrENPkjL .cluster-label span{color:#333;}#mermaid-svg-1UyFZGMGSrENPkjL .cluster-label span p{background-color:transparent;}#mermaid-svg-1UyFZGMGSrENPkjL .label text,#mermaid-svg-1UyFZGMGSrENPkjL span{fill:#333;color:#333;}#mermaid-svg-1UyFZGMGSrENPkjL .node rect,#mermaid-svg-1UyFZGMGSrENPkjL .node circle,#mermaid-svg-1UyFZGMGSrENPkjL .node ellipse,#mermaid-svg-1UyFZGMGSrENPkjL .node polygon,#mermaid-svg-1UyFZGMGSrENPkjL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-1UyFZGMGSrENPkjL .rough-node .label text,#mermaid-svg-1UyFZGMGSrENPkjL .node .label text,#mermaid-svg-1UyFZGMGSrENPkjL .image-shape .label,#mermaid-svg-1UyFZGMGSrENPkjL .icon-shape .label{text-anchor:middle;}#mermaid-svg-1UyFZGMGSrENPkjL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-1UyFZGMGSrENPkjL .rough-node .label,#mermaid-svg-1UyFZGMGSrENPkjL .node .label,#mermaid-svg-1UyFZGMGSrENPkjL .image-shape .label,#mermaid-svg-1UyFZGMGSrENPkjL .icon-shape .label{text-align:center;}#mermaid-svg-1UyFZGMGSrENPkjL .node.clickable{cursor:pointer;}#mermaid-svg-1UyFZGMGSrENPkjL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-1UyFZGMGSrENPkjL .arrowheadPath{fill:#333333;}#mermaid-svg-1UyFZGMGSrENPkjL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-1UyFZGMGSrENPkjL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-1UyFZGMGSrENPkjL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1UyFZGMGSrENPkjL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-1UyFZGMGSrENPkjL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1UyFZGMGSrENPkjL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-1UyFZGMGSrENPkjL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-1UyFZGMGSrENPkjL .cluster text{fill:#333;}#mermaid-svg-1UyFZGMGSrENPkjL .cluster span{color:#333;}#mermaid-svg-1UyFZGMGSrENPkjL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-1UyFZGMGSrENPkjL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-1UyFZGMGSrENPkjL rect.text{fill:none;stroke-width:0;}#mermaid-svg-1UyFZGMGSrENPkjL .icon-shape,#mermaid-svg-1UyFZGMGSrENPkjL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-1UyFZGMGSrENPkjL .icon-shape p,#mermaid-svg-1UyFZGMGSrENPkjL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-1UyFZGMGSrENPkjL .icon-shape .label rect,#mermaid-svg-1UyFZGMGSrENPkjL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-1UyFZGMGSrENPkjL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-1UyFZGMGSrENPkjL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-1UyFZGMGSrENPkjL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ✅ 方式 B · VSCode 采用
JSON-RPC
Extension Host
Extension A
Extension B
Renderer Process
UI
❌ 方式 A · VSCode 不采用
Renderer Process
UI
Plugin

方式 A 的问题:插件能直接操作 DOM、访问所有 Web API,一个插件卡住 = 整个 UI 卡住。方式 B 的好处:进程隔离、崩溃不影响 UI、扩展与 UI 通过 JSON-RPC 通信。

7.2 扩展系统架构

#mermaid-svg-8XNjVKQLjt57otK4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8XNjVKQLjt57otK4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8XNjVKQLjt57otK4 .error-icon{fill:#552222;}#mermaid-svg-8XNjVKQLjt57otK4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8XNjVKQLjt57otK4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8XNjVKQLjt57otK4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8XNjVKQLjt57otK4 .marker.cross{stroke:#333333;}#mermaid-svg-8XNjVKQLjt57otK4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8XNjVKQLjt57otK4 p{margin:0;}#mermaid-svg-8XNjVKQLjt57otK4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8XNjVKQLjt57otK4 .cluster-label text{fill:#333;}#mermaid-svg-8XNjVKQLjt57otK4 .cluster-label span{color:#333;}#mermaid-svg-8XNjVKQLjt57otK4 .cluster-label span p{background-color:transparent;}#mermaid-svg-8XNjVKQLjt57otK4 .label text,#mermaid-svg-8XNjVKQLjt57otK4 span{fill:#333;color:#333;}#mermaid-svg-8XNjVKQLjt57otK4 .node rect,#mermaid-svg-8XNjVKQLjt57otK4 .node circle,#mermaid-svg-8XNjVKQLjt57otK4 .node ellipse,#mermaid-svg-8XNjVKQLjt57otK4 .node polygon,#mermaid-svg-8XNjVKQLjt57otK4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8XNjVKQLjt57otK4 .rough-node .label text,#mermaid-svg-8XNjVKQLjt57otK4 .node .label text,#mermaid-svg-8XNjVKQLjt57otK4 .image-shape .label,#mermaid-svg-8XNjVKQLjt57otK4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-8XNjVKQLjt57otK4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8XNjVKQLjt57otK4 .rough-node .label,#mermaid-svg-8XNjVKQLjt57otK4 .node .label,#mermaid-svg-8XNjVKQLjt57otK4 .image-shape .label,#mermaid-svg-8XNjVKQLjt57otK4 .icon-shape .label{text-align:center;}#mermaid-svg-8XNjVKQLjt57otK4 .node.clickable{cursor:pointer;}#mermaid-svg-8XNjVKQLjt57otK4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8XNjVKQLjt57otK4 .arrowheadPath{fill:#333333;}#mermaid-svg-8XNjVKQLjt57otK4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8XNjVKQLjt57otK4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8XNjVKQLjt57otK4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8XNjVKQLjt57otK4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8XNjVKQLjt57otK4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8XNjVKQLjt57otK4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8XNjVKQLjt57otK4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8XNjVKQLjt57otK4 .cluster text{fill:#333;}#mermaid-svg-8XNjVKQLjt57otK4 .cluster span{color:#333;}#mermaid-svg-8XNjVKQLjt57otK4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8XNjVKQLjt57otK4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8XNjVKQLjt57otK4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-8XNjVKQLjt57otK4 .icon-shape,#mermaid-svg-8XNjVKQLjt57otK4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8XNjVKQLjt57otK4 .icon-shape p,#mermaid-svg-8XNjVKQLjt57otK4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8XNjVKQLjt57otK4 .icon-shape .label rect,#mermaid-svg-8XNjVKQLjt57otK4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8XNjVKQLjt57otK4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8XNjVKQLjt57otK4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8XNjVKQLjt57otK4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RPC · Request/Response
Extension Host Process (独立 Node.js 进程)
Extensions
Extension A
Extension B
Extension N
RPC Proxy
API → RPC 转换

registerCommand() → sendRequest
Extension API vscode.*
commands
languages
workspace
debug
terminal
window
notebook
webview
chat
主线程 (Main Thread)
MainThread* RPC Handler
mainThreadCommands · 命令注册
mainThreadConfiguration · 配置读写
mainThreadLanguageFeatures · 语言特性
mainThreadDebugService · 调试控制
mainThreadTerminalService · 终端控制
mainThreadFileSystem · 文件系统
mainThreadWebviewManager · Webview
ExtensionHostService 宿主管理
启动扩展宿主

管理进程状态

处理重启
ExtensionService 服务层
扩展生命周期管理

扫描/安装/激活/停用
主线程

MainThread 桥接文件(部分):

文件 功能
mainThreadCommands.ts 命令注册与执行
mainThreadConfiguration.ts 配置读取与变更
mainThreadLanguageFeatures.ts 语言服务
mainThreadLanguages.ts 语言注册
mainThreadFileSystem.ts 文件系统访问
mainThreadDocuments.ts 文档管理
mainThreadTerminalService.ts 终端控制
mainThreadDebugService.ts 调试控制
mainThreadWebviewManager.ts Webview 管理
mainThreadTreeViews.ts 树形视图
mainThreadSCM.ts 源代码管理
mainThreadNotebook.ts Notebook 管理
mainThreadChatAgents2.ts Chat Agent

7.3 扩展生命周期与加载

#mermaid-svg-g3qkXjBW8U8sHnjb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-g3qkXjBW8U8sHnjb .error-icon{fill:#552222;}#mermaid-svg-g3qkXjBW8U8sHnjb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-g3qkXjBW8U8sHnjb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-g3qkXjBW8U8sHnjb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-g3qkXjBW8U8sHnjb .marker.cross{stroke:#333333;}#mermaid-svg-g3qkXjBW8U8sHnjb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-g3qkXjBW8U8sHnjb p{margin:0;}#mermaid-svg-g3qkXjBW8U8sHnjb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster-label text{fill:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster-label span{color:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster-label span p{background-color:transparent;}#mermaid-svg-g3qkXjBW8U8sHnjb .label text,#mermaid-svg-g3qkXjBW8U8sHnjb span{fill:#333;color:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb .node rect,#mermaid-svg-g3qkXjBW8U8sHnjb .node circle,#mermaid-svg-g3qkXjBW8U8sHnjb .node ellipse,#mermaid-svg-g3qkXjBW8U8sHnjb .node polygon,#mermaid-svg-g3qkXjBW8U8sHnjb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-g3qkXjBW8U8sHnjb .rough-node .label text,#mermaid-svg-g3qkXjBW8U8sHnjb .node .label text,#mermaid-svg-g3qkXjBW8U8sHnjb .image-shape .label,#mermaid-svg-g3qkXjBW8U8sHnjb .icon-shape .label{text-anchor:middle;}#mermaid-svg-g3qkXjBW8U8sHnjb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-g3qkXjBW8U8sHnjb .rough-node .label,#mermaid-svg-g3qkXjBW8U8sHnjb .node .label,#mermaid-svg-g3qkXjBW8U8sHnjb .image-shape .label,#mermaid-svg-g3qkXjBW8U8sHnjb .icon-shape .label{text-align:center;}#mermaid-svg-g3qkXjBW8U8sHnjb .node.clickable{cursor:pointer;}#mermaid-svg-g3qkXjBW8U8sHnjb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-g3qkXjBW8U8sHnjb .arrowheadPath{fill:#333333;}#mermaid-svg-g3qkXjBW8U8sHnjb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-g3qkXjBW8U8sHnjb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-g3qkXjBW8U8sHnjb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-g3qkXjBW8U8sHnjb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-g3qkXjBW8U8sHnjb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-g3qkXjBW8U8sHnjb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster text{fill:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb .cluster span{color:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-g3qkXjBW8U8sHnjb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-g3qkXjBW8U8sHnjb rect.text{fill:none;stroke-width:0;}#mermaid-svg-g3qkXjBW8U8sHnjb .icon-shape,#mermaid-svg-g3qkXjBW8U8sHnjb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-g3qkXjBW8U8sHnjb .icon-shape p,#mermaid-svg-g3qkXjBW8U8sHnjb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-g3qkXjBW8U8sHnjb .icon-shape .label rect,#mermaid-svg-g3qkXjBW8U8sHnjb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-g3qkXjBW8U8sHnjb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-g3qkXjBW8U8sHnjb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-g3qkXjBW8U8sHnjb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运行期关键事件
onDidChangeConfiguration
onDidChangeWorkspaceFolders
onDidChangeTextDocument
onDidChangeActiveTextEditor
onDidOpenTextDocument / onDidCloseTextDocument
发现
扫描
安装
激活
运行
停用
卸载
#mermaid-svg-L4c4nJNzSoXjav80{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-L4c4nJNzSoXjav80 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-L4c4nJNzSoXjav80 .error-icon{fill:#552222;}#mermaid-svg-L4c4nJNzSoXjav80 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-L4c4nJNzSoXjav80 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-L4c4nJNzSoXjav80 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-L4c4nJNzSoXjav80 .marker.cross{stroke:#333333;}#mermaid-svg-L4c4nJNzSoXjav80 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-L4c4nJNzSoXjav80 p{margin:0;}#mermaid-svg-L4c4nJNzSoXjav80 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-L4c4nJNzSoXjav80 .cluster-label text{fill:#333;}#mermaid-svg-L4c4nJNzSoXjav80 .cluster-label span{color:#333;}#mermaid-svg-L4c4nJNzSoXjav80 .cluster-label span p{background-color:transparent;}#mermaid-svg-L4c4nJNzSoXjav80 .label text,#mermaid-svg-L4c4nJNzSoXjav80 span{fill:#333;color:#333;}#mermaid-svg-L4c4nJNzSoXjav80 .node rect,#mermaid-svg-L4c4nJNzSoXjav80 .node circle,#mermaid-svg-L4c4nJNzSoXjav80 .node ellipse,#mermaid-svg-L4c4nJNzSoXjav80 .node polygon,#mermaid-svg-L4c4nJNzSoXjav80 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-L4c4nJNzSoXjav80 .rough-node .label text,#mermaid-svg-L4c4nJNzSoXjav80 .node .label text,#mermaid-svg-L4c4nJNzSoXjav80 .image-shape .label,#mermaid-svg-L4c4nJNzSoXjav80 .icon-shape .label{text-anchor:middle;}#mermaid-svg-L4c4nJNzSoXjav80 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-L4c4nJNzSoXjav80 .rough-node .label,#mermaid-svg-L4c4nJNzSoXjav80 .node .label,#mermaid-svg-L4c4nJNzSoXjav80 .image-shape .label,#mermaid-svg-L4c4nJNzSoXjav80 .icon-shape .label{text-align:center;}#mermaid-svg-L4c4nJNzSoXjav80 .node.clickable{cursor:pointer;}#mermaid-svg-L4c4nJNzSoXjav80 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-L4c4nJNzSoXjav80 .arrowheadPath{fill:#333333;}#mermaid-svg-L4c4nJNzSoXjav80 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-L4c4nJNzSoXjav80 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-L4c4nJNzSoXjav80 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-L4c4nJNzSoXjav80 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-L4c4nJNzSoXjav80 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-L4c4nJNzSoXjav80 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-L4c4nJNzSoXjav80 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-L4c4nJNzSoXjav80 .cluster text{fill:#333;}#mermaid-svg-L4c4nJNzSoXjav80 .cluster span{color:#333;}#mermaid-svg-L4c4nJNzSoXjav80 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-L4c4nJNzSoXjav80 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-L4c4nJNzSoXjav80 rect.text{fill:none;stroke-width:0;}#mermaid-svg-L4c4nJNzSoXjav80 .icon-shape,#mermaid-svg-L4c4nJNzSoXjav80 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-L4c4nJNzSoXjav80 .icon-shape p,#mermaid-svg-L4c4nJNzSoXjav80 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-L4c4nJNzSoXjav80 .icon-shape .label rect,#mermaid-svg-L4c4nJNzSoXjav80 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-L4c4nJNzSoXjav80 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-L4c4nJNzSoXjav80 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-L4c4nJNzSoXjav80 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VS Code 启动
扫描所有已安装插件

读取 package.json
根据 activationEvents

构建触发器映射
等待触发条件满足...
触发条件满足
在 Extension Host 中加载插件
require extension.js
调用 activate(context)
注册命令 · 事件监听等
插件运行中

通过 API 与 VS Code 交互

关键优化:懒激活(Lazy Activation) ------ VSCode 不会在启动时加载所有插件,只有当触发条件满足时才加载。例如 TypeScript 插件只在打开 .ts 文件时激活;Git 插件只在打开有 .git 的工作区时激活。

7.4 扩展宿主启动(简化)

typescript 复制代码
class ExtensionHostStarter {
  async startExtensionHost(extensionHostId: string): Promise<void> {
    const environment = await this.prepareEnvironment();
    // 1. Fork 新的 Node.js 进程
    const extensionHostProcess = fork(
      'bootstrap-fork.js',
      ['--type=extensionHost', `--id=${extensionHostId}`],
      { env: environment }
    );
    // 2. 建立 IPC 连接 + 注册 RPC 通道
    const connection = new MessagePort();
    extensionHostProcess.send('init', { port: connection, services: [...] });
    this.rpcProtocol.attach(connection);
    // 3. 加载扩展
    await this.loadExtensionsInHost(extensionHostId);
  }
}

8. 扩展开发全解析

8.1 扩展类型

#mermaid-svg-FxsIZpjtfPrzKtGA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FxsIZpjtfPrzKtGA .error-icon{fill:#552222;}#mermaid-svg-FxsIZpjtfPrzKtGA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FxsIZpjtfPrzKtGA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FxsIZpjtfPrzKtGA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FxsIZpjtfPrzKtGA .marker.cross{stroke:#333333;}#mermaid-svg-FxsIZpjtfPrzKtGA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FxsIZpjtfPrzKtGA p{margin:0;}#mermaid-svg-FxsIZpjtfPrzKtGA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster-label text{fill:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster-label span{color:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster-label span p{background-color:transparent;}#mermaid-svg-FxsIZpjtfPrzKtGA .label text,#mermaid-svg-FxsIZpjtfPrzKtGA span{fill:#333;color:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA .node rect,#mermaid-svg-FxsIZpjtfPrzKtGA .node circle,#mermaid-svg-FxsIZpjtfPrzKtGA .node ellipse,#mermaid-svg-FxsIZpjtfPrzKtGA .node polygon,#mermaid-svg-FxsIZpjtfPrzKtGA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FxsIZpjtfPrzKtGA .rough-node .label text,#mermaid-svg-FxsIZpjtfPrzKtGA .node .label text,#mermaid-svg-FxsIZpjtfPrzKtGA .image-shape .label,#mermaid-svg-FxsIZpjtfPrzKtGA .icon-shape .label{text-anchor:middle;}#mermaid-svg-FxsIZpjtfPrzKtGA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FxsIZpjtfPrzKtGA .rough-node .label,#mermaid-svg-FxsIZpjtfPrzKtGA .node .label,#mermaid-svg-FxsIZpjtfPrzKtGA .image-shape .label,#mermaid-svg-FxsIZpjtfPrzKtGA .icon-shape .label{text-align:center;}#mermaid-svg-FxsIZpjtfPrzKtGA .node.clickable{cursor:pointer;}#mermaid-svg-FxsIZpjtfPrzKtGA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FxsIZpjtfPrzKtGA .arrowheadPath{fill:#333333;}#mermaid-svg-FxsIZpjtfPrzKtGA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FxsIZpjtfPrzKtGA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FxsIZpjtfPrzKtGA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FxsIZpjtfPrzKtGA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FxsIZpjtfPrzKtGA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FxsIZpjtfPrzKtGA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster text{fill:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA .cluster span{color:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FxsIZpjtfPrzKtGA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FxsIZpjtfPrzKtGA rect.text{fill:none;stroke-width:0;}#mermaid-svg-FxsIZpjtfPrzKtGA .icon-shape,#mermaid-svg-FxsIZpjtfPrzKtGA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FxsIZpjtfPrzKtGA .icon-shape p,#mermaid-svg-FxsIZpjtfPrzKtGA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FxsIZpjtfPrzKtGA .icon-shape .label rect,#mermaid-svg-FxsIZpjtfPrzKtGA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FxsIZpjtfPrzKtGA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FxsIZpjtfPrzKtGA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FxsIZpjtfPrzKtGA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VSCode 扩展类型

  1. Language Extension · 语言扩展

语法高亮/代码片段/语言配置
2. Theme Extension · 主题扩展

颜色主题/图标主题
3. Declarative Extension · 声明式扩展

仅 package.json 贡献点声明
4. Programmatic Extension · 编程式扩展

需要 activate() 入口
5. Webview Extension · Webview 扩展

嵌入自定义 HTML/JS 界面
6. Debug Adapter · 调试适配器

实现 Debug Adapter Protocol
7. LSP Client · 语言服务器客户端

实现 Language Server Protocol
8. Notebook Extension · Notebook 扩展

自定义渲染和执行

8.2 最小结构与入口

复制代码
my-extension/
├── package.json       ← 插件清单(最重要!)
├── src/
│   └── extension.ts   ← 入口文件
├── tsconfig.json
└── .vscode/
    └── launch.json    ← 调试配置
typescript 复制代码
import * as vscode from 'vscode';

// 插件激活时调用(只调用一次)
export function activate(context: vscode.ExtensionContext) {
    const disposable = vscode.commands.registerCommand(
        'myExt.doSomething',
        () => vscode.window.showInformationMessage('Hello from My Extension!')
    );
    // 必须将 disposable 加入 subscriptions,否则卸载时不会清理
    context.subscriptions.push(disposable);
}

// 插件卸载时调用(可选)
export function deactivate() {}

8.3 Extension Context

context 对象是插件的「身份证」,提供:

typescript 复制代码
interface ExtensionContext {
    subscriptions: Disposable[];        // 需要清理的资源
    workspaceState: Memento;            // 工作区级持久化存储
    globalState: Memento;               // 全局级持久化存储
    secrets: SecretStorage;             // 安全存储(存 token 等)
    storageUri: Uri;                    // 大文件存储路径
    extensionUri: Uri;                  // 插件自身的 URI
    extension: Extension<any>;          // 插件元数据
    environmentVariableCollection: EnvironmentVariableCollection;
    extensionMode: ExtensionMode;       // Development / Production
}

8.4 package.json 配置详解

jsonc 复制代码
{
    "name": "my-extension",
    "displayName": "My Extension",
    "description": "A sample VSCode extension",
    "version": "1.0.0",
    "publisher": "publisher-name",
    "engines": { "vscode": "^1.80.0" },   // 最低兼容版本
    "main": "./out/extension.js",          // Node.js 入口
    "browser": "./out/browser.js",         // Web 入口(可选)
    "activationEvents": [
        "onCommand:myExtension.sayHello",
        "onLanguage:javascript",
        "onView:myExtension.panel",
        "workspaceContains:package.json"
    ],
    "contributes": {
        "commands": [
            { "command": "myExtension.sayHello", "title": "Say Hello", "category": "My Extension" }
        ],
        "keybindings": [
            { "command": "myExtension.sayHello", "key": "ctrl+shift+h", "mac": "cmd+shift+h" }
        ],
        "configuration": {
            "title": "My Extension Settings",
            "properties": {
                "myExtension.enabled": { "type": "boolean", "default": true, "description": "Enable the extension" }
            }
        },
        "viewsContainers": {
            "activitybar": [ { "id": "my-explorer", "title": "My Explorer", "icon": "resources/icon.svg" } ]
        },
        "views": {
            "my-explorer": [ { "id": "myExtension.panel", "name": "My Panel", "type": "webview" } ]
        },
        "menus": {
            "view/item/context": [ { "command": "myExtension.sayHello", "when": "view == myExtension.panel" } ]
        },
        "languages": [ { "id": "mylang", "extensions": [".mlg"], "aliases": ["MyLang"] } ],
        "grammars": [ { "language": "mylang", "scopeName": "source.mylang", "path": "./syntaxes/mylang.tmLanguage.json" } ],
        "snippets": [ { "language": "mylang", "path": "./snippets/mylang.json" } ]
    }
}

8.5 扩展 API 核心模块

typescript 复制代码
// 1. commands --- 命令系统
vscode.commands.registerCommand('myCmd', (arg1, arg2) => { /* ... */ });
vscode.commands.executeCommand('setEditorFontSize', 16);

// 2. window --- 窗口管理
vscode.window.showInformationMessage('Hello');
const channel = vscode.window.createOutputChannel('My Channel');

// 3. languages --- 语言服务
vscode.languages.registerCompletionItemProvider('javascript', {
  provideCompletionItems(document, position) { return [new vscode.CompletionItem('hello')]; }
});

// 4. workspace --- 工作区
const config = vscode.workspace.getConfiguration('myExtension');
vscode.workspace.onDidChangeConfiguration(e => {
  if (e.affectsConfiguration('myExtension.enabled')) { /* ... */ }
});

// 5. terminal --- 终端
const terminal = vscode.window.createTerminal('My Terminal');
terminal.sendText('ls -la');

// 6. debug --- 调试
vscode.debug.startDebugging(workspaceFolder, config);

// 7. chat --- Chat API(1.134 内置)
vscode.chat.requestChatResponse({ prompt: 'Hello' });

vscode.* API 对象由 extHost.api.impl.tscreateApiFactoryAndRegisterActors 构建,会为每个扩展返回定制版 API(按扩展 id、申请到的 API 版本裁剪能力)。这就是两个扩展调用同名 API 可能能力不同的原因。

8.6 Webview 开发

Webview 是扩展中实现自定义 UI 的核心机制,扩展与 Webview 通过 postMessage 双向通信:
acquireVsCodeApi() Webview HTML Webview Panel 扩展代码 acquireVsCodeApi() Webview HTML Webview Panel 扩展代码 #mermaid-svg-lRuLglOjVT1rczuu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lRuLglOjVT1rczuu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lRuLglOjVT1rczuu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lRuLglOjVT1rczuu .error-icon{fill:#552222;}#mermaid-svg-lRuLglOjVT1rczuu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lRuLglOjVT1rczuu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lRuLglOjVT1rczuu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lRuLglOjVT1rczuu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lRuLglOjVT1rczuu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lRuLglOjVT1rczuu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lRuLglOjVT1rczuu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lRuLglOjVT1rczuu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lRuLglOjVT1rczuu .marker.cross{stroke:#333333;}#mermaid-svg-lRuLglOjVT1rczuu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lRuLglOjVT1rczuu p{margin:0;}#mermaid-svg-lRuLglOjVT1rczuu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lRuLglOjVT1rczuu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-lRuLglOjVT1rczuu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lRuLglOjVT1rczuu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-lRuLglOjVT1rczuu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-lRuLglOjVT1rczuu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-lRuLglOjVT1rczuu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-lRuLglOjVT1rczuu .sequenceNumber{fill:white;}#mermaid-svg-lRuLglOjVT1rczuu #sequencenumber{fill:#333;}#mermaid-svg-lRuLglOjVT1rczuu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-lRuLglOjVT1rczuu .messageText{fill:#333;stroke:none;}#mermaid-svg-lRuLglOjVT1rczuu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lRuLglOjVT1rczuu .labelText,#mermaid-svg-lRuLglOjVT1rczuu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-lRuLglOjVT1rczuu .loopText,#mermaid-svg-lRuLglOjVT1rczuu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-lRuLglOjVT1rczuu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lRuLglOjVT1rczuu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-lRuLglOjVT1rczuu .noteText,#mermaid-svg-lRuLglOjVT1rczuu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-lRuLglOjVT1rczuu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lRuLglOjVT1rczuu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lRuLglOjVT1rczuu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lRuLglOjVT1rczuu .actorPopupMenu{position:absolute;}#mermaid-svg-lRuLglOjVT1rczuu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-lRuLglOjVT1rczuu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lRuLglOjVT1rczuu .actor-man circle,#mermaid-svg-lRuLglOjVT1rczuu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-lRuLglOjVT1rczuu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} createWebviewPanel("'myWebview', ...") 设置 HTML("含 CSP/nonce") acquireVsCodeApi() 获取 API 对象 panel.webview.postMessage("{type:'update'"}) window.addEventListener("'message'") 接收 vscode.postMessage("{type:'click'"}) 发送 onDidReceiveMessage 接收处理

typescript 复制代码
const panel = vscode.window.createWebviewPanel(
  'myWebview', 'My Webview',
  vscode.ViewColumn.One,
  { enableScripts: true, retainContextWhenHidden: true }
);

const nonce = getNonce();   // 必须 CSP + nonce 保证安全
panel.webview.html = `
  <!DOCTYPE html>
  <html>
  <head>
    <meta http-equiv="Content-Security-Policy"
          content="default-src 'none'; script-src 'nonce-${nonce}'; style-src ${panel.webview.cspSource};">
  </head>
  <body>
    <h1>Hello from Webview!</h1>
    <script nonce="${nonce}">
      const vscode = acquireVsCodeApi();
      vscode.postMessage({ type: 'click', data: 'hello' });
      window.addEventListener('message', (event) => { /* 接收来自扩展的消息 */ });
    </script>
  </body>
  </html>
`;

panel.webview.onDidReceiveMessage(message => {
  if (message.type === 'click') vscode.window.showInformationMessage(`Clicked: ${message.data}`);
});

9. Contribution Points:声明式扩展

Contribution Points 是 package.json 中的 contributes 字段,允许你不写一行代码就能扩展 VSCode。

9.1 常用贡献点速查

Contribution Point 用途 示例
commands 注册命令(出现在命令面板) {"command": "ext.hello", "title": "Hello"}
configuration 注册设置项(出现在 settings.json) {"properties": {"ext.foo": {...}}}
keybindings 注册快捷键 {"command": "ext.hello", "key": "ctrl+h"}
menus 注册右键菜单等 {"editor/context": [...]}
languages 声明新语言 {"id": "mylang", "extensions": [".ml"]}
grammars 语法高亮 (TextMate) {"language": "mylang", "scopeName": "..."}
themes 颜色主题 {"uiThemes": [...], "path": "./theme.json"}
iconThemes 文件图标主题 {"id": "myicons", "path": "..."}
views 注册侧栏视图 {"explorer": [{"id": "myView", ...}]}
viewsContainers 注册视图容器 {"activitybar": [...]}
snippets 代码片段 {"language": "python", "path": "./snippets.json"}
debuggers 注册调试器 {"type": "mydbg", ...}
taskDefinitions 注册任务类型 {"type": "mytask", ...}
terminal 注册终端配置文件 {"profiles": [...]}
walkthroughs 注册入门引导 {"id": "welcome", ...}
chatParticipants / languageModelTools AI 对话参与者 / 工具 1.134 重点

声明式贡献的好处:VSCode 启动时静态扫描,不需要激活扩展就能把命令/配置项挂上去;只有用户真正触发(如执行命令)才激活扩展进程。

9.2 when Clause:条件控制

when 子句控制「何时显示/启用」:

jsonc 复制代码
{
    "menus": {
        "editor/context": [
            { "command": "myExt.formatPython", "when": "editorLangId == python" },
            { "command": "myExt.onlyInDebug", "when": "inDebugMode" },
            { "command": "myExt.multiCondition", "when": "editorLangId == python && !editorReadonly" }
        ]
    },
    "keybindings": [
        { "command": "myExt.save", "key": "ctrl+s", "when": "editorTextFocus && langId == mylang" }
    ]
}

常用 when 上下文变量:

变量 含义
editorLangId 当前编辑器的语言 ID
editorTextFocus 编辑器是否获得焦点
editorReadonly 编辑器是否只读
inDebugMode 是否在调试模式
isMac / isLinux / isWindows 操作系统
resourceExtname 当前文件的扩展名
resourceScheme 资源的 scheme (file, untitled, etc.)
viewId 当前激活的视图 ID
terminalFocus 终端是否获得焦点

10. Activation Events:懒加载的魔法

激活事件决定扩展何时被加载。VSCode 不会一启动就全加载,而是满足某个条件才激活对应扩展。
#mermaid-svg-uztVoeaHQSvEgOhO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uztVoeaHQSvEgOhO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uztVoeaHQSvEgOhO .error-icon{fill:#552222;}#mermaid-svg-uztVoeaHQSvEgOhO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uztVoeaHQSvEgOhO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uztVoeaHQSvEgOhO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uztVoeaHQSvEgOhO .marker.cross{stroke:#333333;}#mermaid-svg-uztVoeaHQSvEgOhO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uztVoeaHQSvEgOhO p{margin:0;}#mermaid-svg-uztVoeaHQSvEgOhO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uztVoeaHQSvEgOhO .cluster-label text{fill:#333;}#mermaid-svg-uztVoeaHQSvEgOhO .cluster-label span{color:#333;}#mermaid-svg-uztVoeaHQSvEgOhO .cluster-label span p{background-color:transparent;}#mermaid-svg-uztVoeaHQSvEgOhO .label text,#mermaid-svg-uztVoeaHQSvEgOhO span{fill:#333;color:#333;}#mermaid-svg-uztVoeaHQSvEgOhO .node rect,#mermaid-svg-uztVoeaHQSvEgOhO .node circle,#mermaid-svg-uztVoeaHQSvEgOhO .node ellipse,#mermaid-svg-uztVoeaHQSvEgOhO .node polygon,#mermaid-svg-uztVoeaHQSvEgOhO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uztVoeaHQSvEgOhO .rough-node .label text,#mermaid-svg-uztVoeaHQSvEgOhO .node .label text,#mermaid-svg-uztVoeaHQSvEgOhO .image-shape .label,#mermaid-svg-uztVoeaHQSvEgOhO .icon-shape .label{text-anchor:middle;}#mermaid-svg-uztVoeaHQSvEgOhO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uztVoeaHQSvEgOhO .rough-node .label,#mermaid-svg-uztVoeaHQSvEgOhO .node .label,#mermaid-svg-uztVoeaHQSvEgOhO .image-shape .label,#mermaid-svg-uztVoeaHQSvEgOhO .icon-shape .label{text-align:center;}#mermaid-svg-uztVoeaHQSvEgOhO .node.clickable{cursor:pointer;}#mermaid-svg-uztVoeaHQSvEgOhO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uztVoeaHQSvEgOhO .arrowheadPath{fill:#333333;}#mermaid-svg-uztVoeaHQSvEgOhO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uztVoeaHQSvEgOhO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uztVoeaHQSvEgOhO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uztVoeaHQSvEgOhO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uztVoeaHQSvEgOhO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uztVoeaHQSvEgOhO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uztVoeaHQSvEgOhO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uztVoeaHQSvEgOhO .cluster text{fill:#333;}#mermaid-svg-uztVoeaHQSvEgOhO .cluster span{color:#333;}#mermaid-svg-uztVoeaHQSvEgOhO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uztVoeaHQSvEgOhO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uztVoeaHQSvEgOhO rect.text{fill:none;stroke-width:0;}#mermaid-svg-uztVoeaHQSvEgOhO .icon-shape,#mermaid-svg-uztVoeaHQSvEgOhO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uztVoeaHQSvEgOhO .icon-shape p,#mermaid-svg-uztVoeaHQSvEgOhO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uztVoeaHQSvEgOhO .icon-shape .label rect,#mermaid-svg-uztVoeaHQSvEgOhO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uztVoeaHQSvEgOhO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uztVoeaHQSvEgOhO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uztVoeaHQSvEgOhO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Activation Events 类型
onCommand

用户执行命令时激活
onLanguage

打开特定语言文件时激活
onView

打开特定视图时激活
workspaceContains

工作区包含特定文件时激活
onStartupFinished

VSCode 启动完成后激活
*

始终激活(不推荐)

完整激活事件类型:

jsonc 复制代码
{
    "activationEvents": [
        "onLanguage:python",
        "onCommand:myExt.doSomething",
        "onNotebook:jupyter-notebook",
        "onDebug", "onDebugInitialConfigurations", "onDebugResolve:python",
        "workspaceContains:**/*.py",
        "onUri",
        "onTerminal",
        "onWebviewPanel:myWebviewType",
        "onCustomEditor:myCustomEditor",
        "onStartupFinished",
        "onFileSystem:myScheme"
    ]
}

隐式激活事件(VSCode 1.74+) :很多激活事件可由对应 contributes 自动推断,不必再显式声明

jsonc 复制代码
{
    "contributes": {
        "commands": [ { "command": "myExt.hello" } ],   // 自动隐含 "onCommand:myExt.hello"
        "languages": [ { "id": "mylang" } ]             // 自动隐含 "onLanguage:mylang"
    }
}

* 会让扩展失去懒加载优势,是被市场审核关注的信号,应尽量避免。


11. Language Server Protocol (LSP)

LSP 是 VSCode 对编程语言支持的最大贡献之一,它将语言智能(补全、跳转、诊断)从编辑器中抽离成独立服务器进程。

11.1 架构

#mermaid-svg-NS0buXEL3kDjTTWB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NS0buXEL3kDjTTWB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NS0buXEL3kDjTTWB .error-icon{fill:#552222;}#mermaid-svg-NS0buXEL3kDjTTWB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NS0buXEL3kDjTTWB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NS0buXEL3kDjTTWB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NS0buXEL3kDjTTWB .marker.cross{stroke:#333333;}#mermaid-svg-NS0buXEL3kDjTTWB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NS0buXEL3kDjTTWB p{margin:0;}#mermaid-svg-NS0buXEL3kDjTTWB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NS0buXEL3kDjTTWB .cluster-label text{fill:#333;}#mermaid-svg-NS0buXEL3kDjTTWB .cluster-label span{color:#333;}#mermaid-svg-NS0buXEL3kDjTTWB .cluster-label span p{background-color:transparent;}#mermaid-svg-NS0buXEL3kDjTTWB .label text,#mermaid-svg-NS0buXEL3kDjTTWB span{fill:#333;color:#333;}#mermaid-svg-NS0buXEL3kDjTTWB .node rect,#mermaid-svg-NS0buXEL3kDjTTWB .node circle,#mermaid-svg-NS0buXEL3kDjTTWB .node ellipse,#mermaid-svg-NS0buXEL3kDjTTWB .node polygon,#mermaid-svg-NS0buXEL3kDjTTWB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NS0buXEL3kDjTTWB .rough-node .label text,#mermaid-svg-NS0buXEL3kDjTTWB .node .label text,#mermaid-svg-NS0buXEL3kDjTTWB .image-shape .label,#mermaid-svg-NS0buXEL3kDjTTWB .icon-shape .label{text-anchor:middle;}#mermaid-svg-NS0buXEL3kDjTTWB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NS0buXEL3kDjTTWB .rough-node .label,#mermaid-svg-NS0buXEL3kDjTTWB .node .label,#mermaid-svg-NS0buXEL3kDjTTWB .image-shape .label,#mermaid-svg-NS0buXEL3kDjTTWB .icon-shape .label{text-align:center;}#mermaid-svg-NS0buXEL3kDjTTWB .node.clickable{cursor:pointer;}#mermaid-svg-NS0buXEL3kDjTTWB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NS0buXEL3kDjTTWB .arrowheadPath{fill:#333333;}#mermaid-svg-NS0buXEL3kDjTTWB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NS0buXEL3kDjTTWB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NS0buXEL3kDjTTWB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NS0buXEL3kDjTTWB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NS0buXEL3kDjTTWB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NS0buXEL3kDjTTWB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NS0buXEL3kDjTTWB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NS0buXEL3kDjTTWB .cluster text{fill:#333;}#mermaid-svg-NS0buXEL3kDjTTWB .cluster span{color:#333;}#mermaid-svg-NS0buXEL3kDjTTWB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NS0buXEL3kDjTTWB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NS0buXEL3kDjTTWB rect.text{fill:none;stroke-width:0;}#mermaid-svg-NS0buXEL3kDjTTWB .icon-shape,#mermaid-svg-NS0buXEL3kDjTTWB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NS0buXEL3kDjTTWB .icon-shape p,#mermaid-svg-NS0buXEL3kDjTTWB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NS0buXEL3kDjTTWB .icon-shape .label rect,#mermaid-svg-NS0buXEL3kDjTTWB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NS0buXEL3kDjTTWB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NS0buXEL3kDjTTWB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NS0buXEL3kDjTTWB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} LSP · JSON-RPC

stdio / TCP / WebSocket
Language Server · 独立进程
处理: 语法分析
处理: 补全计算
处理: 诊断生成
返回: CompletionItem
返回: Diagnostic
返回: Location
VS Code · Client
发送: 文件变更
发送: 光标位置
发送: 保存事件
接收: 补全列表
接收: 诊断信息
接收: 跳转位置

11.2 LSP 核心能力映射

LSP 方法 VS Code 中的效果 对应 API
textDocument/completion IntelliSense 自动补全 registerCompletionItemProvider
textDocument/hover 鼠标悬停提示 registerHoverProvider
textDocument/definition 跳转到定义 (F12) registerDefinitionProvider
textDocument/references 查找引用 (Shift+F12) registerReferenceProvider
textDocument/rename 重命名符号 (F2) registerRenameProvider
textDocument/formatting 格式化文档 registerDocumentFormattingEditProvider
textDocument/publishDiagnostics 波浪线错误/警告 createDiagnosticCollection
textDocument/codeAction 快速修复(灯泡) registerCodeActionsProvider
textDocument/codeLens CodeLens(行内链接) registerCodeLensProvider
textDocument/documentSymbol 大纲视图符号 registerDocumentSymbolProvider
textDocument/foldingRange 代码折叠 registerFoldingRangeProvider
textDocument/semanticTokens 语义高亮 registerDocumentSemanticTokensProvider

11.3 为什么 LSP 重要?

  1. 语言服务器可复用:一个 Python Language Server 可被 VS Code、Vim、Emacs 共用;
  2. 性能:语言分析运行在独立进程,不阻塞 UI;
  3. 语言无关:服务器可用任何语言实现(pylance 用 TS,rust-analyzer 用 Rust);
  4. 增量更新:只传输变更的部分,而非整个文件。

12. 配置系统:settings.json 的背后

12.1 配置分层(准确模型)

VSCode 的配置是一套分层覆盖 模型,实现在 platform/configuration。底层 ConfigurationTarget 枚举揭示了真实优先级(从低到高):
#mermaid-svg-MD0TxURJK8rfVEqY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MD0TxURJK8rfVEqY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MD0TxURJK8rfVEqY .error-icon{fill:#552222;}#mermaid-svg-MD0TxURJK8rfVEqY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MD0TxURJK8rfVEqY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MD0TxURJK8rfVEqY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MD0TxURJK8rfVEqY .marker.cross{stroke:#333333;}#mermaid-svg-MD0TxURJK8rfVEqY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MD0TxURJK8rfVEqY p{margin:0;}#mermaid-svg-MD0TxURJK8rfVEqY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MD0TxURJK8rfVEqY .cluster-label text{fill:#333;}#mermaid-svg-MD0TxURJK8rfVEqY .cluster-label span{color:#333;}#mermaid-svg-MD0TxURJK8rfVEqY .cluster-label span p{background-color:transparent;}#mermaid-svg-MD0TxURJK8rfVEqY .label text,#mermaid-svg-MD0TxURJK8rfVEqY span{fill:#333;color:#333;}#mermaid-svg-MD0TxURJK8rfVEqY .node rect,#mermaid-svg-MD0TxURJK8rfVEqY .node circle,#mermaid-svg-MD0TxURJK8rfVEqY .node ellipse,#mermaid-svg-MD0TxURJK8rfVEqY .node polygon,#mermaid-svg-MD0TxURJK8rfVEqY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MD0TxURJK8rfVEqY .rough-node .label text,#mermaid-svg-MD0TxURJK8rfVEqY .node .label text,#mermaid-svg-MD0TxURJK8rfVEqY .image-shape .label,#mermaid-svg-MD0TxURJK8rfVEqY .icon-shape .label{text-anchor:middle;}#mermaid-svg-MD0TxURJK8rfVEqY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MD0TxURJK8rfVEqY .rough-node .label,#mermaid-svg-MD0TxURJK8rfVEqY .node .label,#mermaid-svg-MD0TxURJK8rfVEqY .image-shape .label,#mermaid-svg-MD0TxURJK8rfVEqY .icon-shape .label{text-align:center;}#mermaid-svg-MD0TxURJK8rfVEqY .node.clickable{cursor:pointer;}#mermaid-svg-MD0TxURJK8rfVEqY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MD0TxURJK8rfVEqY .arrowheadPath{fill:#333333;}#mermaid-svg-MD0TxURJK8rfVEqY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MD0TxURJK8rfVEqY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MD0TxURJK8rfVEqY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MD0TxURJK8rfVEqY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MD0TxURJK8rfVEqY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MD0TxURJK8rfVEqY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MD0TxURJK8rfVEqY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MD0TxURJK8rfVEqY .cluster text{fill:#333;}#mermaid-svg-MD0TxURJK8rfVEqY .cluster span{color:#333;}#mermaid-svg-MD0TxURJK8rfVEqY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MD0TxURJK8rfVEqY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MD0TxURJK8rfVEqY rect.text{fill:none;stroke-width:0;}#mermaid-svg-MD0TxURJK8rfVEqY .icon-shape,#mermaid-svg-MD0TxURJK8rfVEqY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MD0TxURJK8rfVEqY .icon-shape p,#mermaid-svg-MD0TxURJK8rfVEqY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MD0TxURJK8rfVEqY .icon-shape .label rect,#mermaid-svg-MD0TxURJK8rfVEqY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MD0TxURJK8rfVEqY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MD0TxURJK8rfVEqY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MD0TxURJK8rfVEqY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DEFAULT · 代码默认值
APPLICATION · 应用级(所有窗口共享)
USER / USER_LOCAL · 用户全局配置

~/.config/Code/User/settings.json
USER_REMOTE · 远程用户配置
WORKSPACE · 工作区配置

.vscode/settings.json / *.code-workspace
WORKSPACE_FOLDER · 文件夹配置

多根工作区各文件夹
MEMORY · 运行时临时(不落盘)

最终生效值 = 最高优先级的非 undefined 层。IConfigurationService 提供 getValue / updateValue(target, ...) / inspect(key) / reloadConfigurationinspect 会返回每个层级的值,是排查「我的配置为什么没生效」的利器。

还有 Language-specific overrides

jsonc 复制代码
{
    "editor.tabSize": 4,
    "[python]": { "editor.tabSize": 4, "editor.insertSpaces": true },
    "[go]":     { "editor.tabSize": 4, "editor.insertSpaces": false }  // Go 用 tab
}

12.2 配置的注册机制

插件通过 contributes.configuration 注册配置项(自动出现在设置 UI):

jsonc 复制代码
{
    "contributes": {
        "configuration": {
            "title": "My Extension",
            "properties": {
                "myExt.apiEndpoint": {
                    "type": "string",
                    "default": "https://api.example.com",
                    "description": "API endpoint URL",
                    "scope": "resource"          // 可按文件夹配置
                },
                "myExt.maxRetries": {
                    "type": "number", "default": 3,
                    "minimum": 1, "maximum": 10
                },
                "myExt.logLevel": {
                    "type": "string",
                    "enum": ["debug", "info", "warn", "error"],
                    "default": "info"
                }
            }
        }
    }
}

配置作用域 (scope):

Scope 含义
application 应用级别,所有窗口共享
machine 机器级别,不能通过 Setting Sync 同步
window 窗口级别(默认)
resource 资源级别,可按文件夹/文件配置
language-overridable 可被语言特定设置覆盖

12.3 读取与监听配置

typescript 复制代码
import * as vscode from 'vscode';

const config = vscode.workspace.getConfiguration('myExt');
const endpoint = config.get<string>('apiEndpoint');

// 读取特定资源的配置(考虑 resource scope)
const docConfig = vscode.workspace.getConfiguration('myExt', document.uri);
const docEndpoint = docConfig.get<string>('apiEndpoint');

// 更新配置
await config.update('fontSize', 16, vscode.ConfigurationTarget.Workspace);

// 监听配置变更
vscode.workspace.onDidChangeConfiguration(e => {
    if (e.affectsConfiguration('myExt.apiEndpoint')) reloadConfig();
});

12.4 Keybindings 系统

#mermaid-svg-9jfVbWYyqvgi1dTn{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9jfVbWYyqvgi1dTn .error-icon{fill:#552222;}#mermaid-svg-9jfVbWYyqvgi1dTn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9jfVbWYyqvgi1dTn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9jfVbWYyqvgi1dTn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9jfVbWYyqvgi1dTn .marker.cross{stroke:#333333;}#mermaid-svg-9jfVbWYyqvgi1dTn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9jfVbWYyqvgi1dTn p{margin:0;}#mermaid-svg-9jfVbWYyqvgi1dTn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster-label text{fill:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster-label span{color:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster-label span p{background-color:transparent;}#mermaid-svg-9jfVbWYyqvgi1dTn .label text,#mermaid-svg-9jfVbWYyqvgi1dTn span{fill:#333;color:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn .node rect,#mermaid-svg-9jfVbWYyqvgi1dTn .node circle,#mermaid-svg-9jfVbWYyqvgi1dTn .node ellipse,#mermaid-svg-9jfVbWYyqvgi1dTn .node polygon,#mermaid-svg-9jfVbWYyqvgi1dTn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9jfVbWYyqvgi1dTn .rough-node .label text,#mermaid-svg-9jfVbWYyqvgi1dTn .node .label text,#mermaid-svg-9jfVbWYyqvgi1dTn .image-shape .label,#mermaid-svg-9jfVbWYyqvgi1dTn .icon-shape .label{text-anchor:middle;}#mermaid-svg-9jfVbWYyqvgi1dTn .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9jfVbWYyqvgi1dTn .rough-node .label,#mermaid-svg-9jfVbWYyqvgi1dTn .node .label,#mermaid-svg-9jfVbWYyqvgi1dTn .image-shape .label,#mermaid-svg-9jfVbWYyqvgi1dTn .icon-shape .label{text-align:center;}#mermaid-svg-9jfVbWYyqvgi1dTn .node.clickable{cursor:pointer;}#mermaid-svg-9jfVbWYyqvgi1dTn .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9jfVbWYyqvgi1dTn .arrowheadPath{fill:#333333;}#mermaid-svg-9jfVbWYyqvgi1dTn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9jfVbWYyqvgi1dTn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9jfVbWYyqvgi1dTn .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9jfVbWYyqvgi1dTn .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9jfVbWYyqvgi1dTn .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9jfVbWYyqvgi1dTn .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster text{fill:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn .cluster span{color:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9jfVbWYyqvgi1dTn .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9jfVbWYyqvgi1dTn rect.text{fill:none;stroke-width:0;}#mermaid-svg-9jfVbWYyqvgi1dTn .icon-shape,#mermaid-svg-9jfVbWYyqvgi1dTn .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9jfVbWYyqvgi1dTn .icon-shape p,#mermaid-svg-9jfVbWYyqvgi1dTn .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9jfVbWYyqvgi1dTn .icon-shape .label rect,#mermaid-svg-9jfVbWYyqvgi1dTn .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9jfVbWYyqvgi1dTn .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9jfVbWYyqvgi1dTn .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9jfVbWYyqvgi1dTn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 规则来源
匹配逻辑

  1. 精确匹配 ctrl+s
  2. 前缀匹配 ctrl+k → s
  3. 条件匹配 when:editorFocus
  4. 冲突解决 用户 > 扩展 > 默认
    IKeybindingService
    resolveKeybinding · keybinding → Command
    dispatchCommand · command, args
    默认规则 keybindings.json
    用户规则 keybindings.json
    扩展规则 commands + menus

12.5 Storage 系统

typescript 复制代码
// 全局存储(跨工作区)
await context.globalState.update('myKey', 'myValue');
const value = context.globalState.get('myKey');

// 工作区存储(当前工作区)
await context.workspaceState.update('workspaceKey', 'workspaceValue');

// Secret Storage(加密存储,存 token)
await context.secrets.store('apiKey', 'sk-****xxxx');
const apiKey = await context.secrets.get('apiKey');

13. 关键子系统:终端 / 调试 / 主题

13.1 终端系统

#mermaid-svg-DBTzXrygcr2j98ul{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DBTzXrygcr2j98ul .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DBTzXrygcr2j98ul .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DBTzXrygcr2j98ul .error-icon{fill:#552222;}#mermaid-svg-DBTzXrygcr2j98ul .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DBTzXrygcr2j98ul .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DBTzXrygcr2j98ul .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DBTzXrygcr2j98ul .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DBTzXrygcr2j98ul .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DBTzXrygcr2j98ul .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DBTzXrygcr2j98ul .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DBTzXrygcr2j98ul .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DBTzXrygcr2j98ul .marker.cross{stroke:#333333;}#mermaid-svg-DBTzXrygcr2j98ul svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DBTzXrygcr2j98ul p{margin:0;}#mermaid-svg-DBTzXrygcr2j98ul .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DBTzXrygcr2j98ul .cluster-label text{fill:#333;}#mermaid-svg-DBTzXrygcr2j98ul .cluster-label span{color:#333;}#mermaid-svg-DBTzXrygcr2j98ul .cluster-label span p{background-color:transparent;}#mermaid-svg-DBTzXrygcr2j98ul .label text,#mermaid-svg-DBTzXrygcr2j98ul span{fill:#333;color:#333;}#mermaid-svg-DBTzXrygcr2j98ul .node rect,#mermaid-svg-DBTzXrygcr2j98ul .node circle,#mermaid-svg-DBTzXrygcr2j98ul .node ellipse,#mermaid-svg-DBTzXrygcr2j98ul .node polygon,#mermaid-svg-DBTzXrygcr2j98ul .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DBTzXrygcr2j98ul .rough-node .label text,#mermaid-svg-DBTzXrygcr2j98ul .node .label text,#mermaid-svg-DBTzXrygcr2j98ul .image-shape .label,#mermaid-svg-DBTzXrygcr2j98ul .icon-shape .label{text-anchor:middle;}#mermaid-svg-DBTzXrygcr2j98ul .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DBTzXrygcr2j98ul .rough-node .label,#mermaid-svg-DBTzXrygcr2j98ul .node .label,#mermaid-svg-DBTzXrygcr2j98ul .image-shape .label,#mermaid-svg-DBTzXrygcr2j98ul .icon-shape .label{text-align:center;}#mermaid-svg-DBTzXrygcr2j98ul .node.clickable{cursor:pointer;}#mermaid-svg-DBTzXrygcr2j98ul .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DBTzXrygcr2j98ul .arrowheadPath{fill:#333333;}#mermaid-svg-DBTzXrygcr2j98ul .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DBTzXrygcr2j98ul .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DBTzXrygcr2j98ul .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DBTzXrygcr2j98ul .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DBTzXrygcr2j98ul .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DBTzXrygcr2j98ul .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DBTzXrygcr2j98ul .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DBTzXrygcr2j98ul .cluster text{fill:#333;}#mermaid-svg-DBTzXrygcr2j98ul .cluster span{color:#333;}#mermaid-svg-DBTzXrygcr2j98ul div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DBTzXrygcr2j98ul .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DBTzXrygcr2j98ul rect.text{fill:none;stroke-width:0;}#mermaid-svg-DBTzXrygcr2j98ul .icon-shape,#mermaid-svg-DBTzXrygcr2j98ul .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DBTzXrygcr2j98ul .icon-shape p,#mermaid-svg-DBTzXrygcr2j98ul .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DBTzXrygcr2j98ul .icon-shape .label rect,#mermaid-svg-DBTzXrygcr2j98ul .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DBTzXrygcr2j98ul .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DBTzXrygcr2j98ul .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DBTzXrygcr2j98ul :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} PTY 进程
终端实例
关键技术
node-pty · Node.js 伪终端
xterm.js · 终端渲染引擎
Shell Integration · 深度 shell 集成
TerminalService (主线程)
终端实例管理 · 配置与主题
Terminal 1 Worker
Terminal 2 Worker
Terminal N Worker
PTY Process bash/zsh
PTY Process powershell
PTY Process cmd

13.2 调试系统(Debug Adapter Protocol)

#mermaid-svg-RNFnpL2bXpYyOWUI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-RNFnpL2bXpYyOWUI .error-icon{fill:#552222;}#mermaid-svg-RNFnpL2bXpYyOWUI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-RNFnpL2bXpYyOWUI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-RNFnpL2bXpYyOWUI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-RNFnpL2bXpYyOWUI .marker.cross{stroke:#333333;}#mermaid-svg-RNFnpL2bXpYyOWUI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-RNFnpL2bXpYyOWUI p{margin:0;}#mermaid-svg-RNFnpL2bXpYyOWUI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster-label text{fill:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster-label span{color:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster-label span p{background-color:transparent;}#mermaid-svg-RNFnpL2bXpYyOWUI .label text,#mermaid-svg-RNFnpL2bXpYyOWUI span{fill:#333;color:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI .node rect,#mermaid-svg-RNFnpL2bXpYyOWUI .node circle,#mermaid-svg-RNFnpL2bXpYyOWUI .node ellipse,#mermaid-svg-RNFnpL2bXpYyOWUI .node polygon,#mermaid-svg-RNFnpL2bXpYyOWUI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-RNFnpL2bXpYyOWUI .rough-node .label text,#mermaid-svg-RNFnpL2bXpYyOWUI .node .label text,#mermaid-svg-RNFnpL2bXpYyOWUI .image-shape .label,#mermaid-svg-RNFnpL2bXpYyOWUI .icon-shape .label{text-anchor:middle;}#mermaid-svg-RNFnpL2bXpYyOWUI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-RNFnpL2bXpYyOWUI .rough-node .label,#mermaid-svg-RNFnpL2bXpYyOWUI .node .label,#mermaid-svg-RNFnpL2bXpYyOWUI .image-shape .label,#mermaid-svg-RNFnpL2bXpYyOWUI .icon-shape .label{text-align:center;}#mermaid-svg-RNFnpL2bXpYyOWUI .node.clickable{cursor:pointer;}#mermaid-svg-RNFnpL2bXpYyOWUI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-RNFnpL2bXpYyOWUI .arrowheadPath{fill:#333333;}#mermaid-svg-RNFnpL2bXpYyOWUI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-RNFnpL2bXpYyOWUI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-RNFnpL2bXpYyOWUI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RNFnpL2bXpYyOWUI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-RNFnpL2bXpYyOWUI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RNFnpL2bXpYyOWUI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster text{fill:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI .cluster span{color:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-RNFnpL2bXpYyOWUI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-RNFnpL2bXpYyOWUI rect.text{fill:none;stroke-width:0;}#mermaid-svg-RNFnpL2bXpYyOWUI .icon-shape,#mermaid-svg-RNFnpL2bXpYyOWUI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-RNFnpL2bXpYyOWUI .icon-shape p,#mermaid-svg-RNFnpL2bXpYyOWUI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-RNFnpL2bXpYyOWUI .icon-shape .label rect,#mermaid-svg-RNFnpL2bXpYyOWUI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-RNFnpL2bXpYyOWUI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-RNFnpL2bXpYyOWUI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-RNFnpL2bXpYyOWUI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运行时
Debug Adapters
Debug Adapter Protocol (DAP)
Request · initialize/attach/launch/setBreakpoints
Event · initialized/stopped/output
DebugService (主线程)
调试会话管理 · 断点/变量/调用栈
Node Debug Adapter
Python Debug Adapter
自定义 Adapter
Node.js
Python
Custom App

13.3 主题系统

#mermaid-svg-bDaGKZQcm8nh5Qoq{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-bDaGKZQcm8nh5Qoq .error-icon{fill:#552222;}#mermaid-svg-bDaGKZQcm8nh5Qoq .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-bDaGKZQcm8nh5Qoq .marker{fill:#333333;stroke:#333333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .marker.cross{stroke:#333333;}#mermaid-svg-bDaGKZQcm8nh5Qoq svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-bDaGKZQcm8nh5Qoq p{margin:0;}#mermaid-svg-bDaGKZQcm8nh5Qoq .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster-label text{fill:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster-label span{color:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster-label span p{background-color:transparent;}#mermaid-svg-bDaGKZQcm8nh5Qoq .label text,#mermaid-svg-bDaGKZQcm8nh5Qoq span{fill:#333;color:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .node rect,#mermaid-svg-bDaGKZQcm8nh5Qoq .node circle,#mermaid-svg-bDaGKZQcm8nh5Qoq .node ellipse,#mermaid-svg-bDaGKZQcm8nh5Qoq .node polygon,#mermaid-svg-bDaGKZQcm8nh5Qoq .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .rough-node .label text,#mermaid-svg-bDaGKZQcm8nh5Qoq .node .label text,#mermaid-svg-bDaGKZQcm8nh5Qoq .image-shape .label,#mermaid-svg-bDaGKZQcm8nh5Qoq .icon-shape .label{text-anchor:middle;}#mermaid-svg-bDaGKZQcm8nh5Qoq .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .rough-node .label,#mermaid-svg-bDaGKZQcm8nh5Qoq .node .label,#mermaid-svg-bDaGKZQcm8nh5Qoq .image-shape .label,#mermaid-svg-bDaGKZQcm8nh5Qoq .icon-shape .label{text-align:center;}#mermaid-svg-bDaGKZQcm8nh5Qoq .node.clickable{cursor:pointer;}#mermaid-svg-bDaGKZQcm8nh5Qoq .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .arrowheadPath{fill:#333333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bDaGKZQcm8nh5Qoq .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-bDaGKZQcm8nh5Qoq .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bDaGKZQcm8nh5Qoq .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster text{fill:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq .cluster span{color:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-bDaGKZQcm8nh5Qoq .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-bDaGKZQcm8nh5Qoq rect.text{fill:none;stroke-width:0;}#mermaid-svg-bDaGKZQcm8nh5Qoq .icon-shape,#mermaid-svg-bDaGKZQcm8nh5Qoq .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-bDaGKZQcm8nh5Qoq .icon-shape p,#mermaid-svg-bDaGKZQcm8nh5Qoq .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-bDaGKZQcm8nh5Qoq .icon-shape .label rect,#mermaid-svg-bDaGKZQcm8nh5Qoq .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-bDaGKZQcm8nh5Qoq .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-bDaGKZQcm8nh5Qoq .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-bDaGKZQcm8nh5Qoq :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Workbench 颜色 Token
editor.background
editor.foreground
editor.selectionBackground
editorCursor.foreground
editorLineNumber.foreground
图标主题 Icon Theme
文件图标映射 · 基于扩展名/语言
目录视图图标
标签页图标
颜色主题 Color Theme
TextMate Rule · tmLanguage 定义 Token
Semantic Token · 语言服务提供语义
Theme · 定义 Token 颜色
Semantic Colors · 主题提供颜色映射

主题是一个 JSON 文件,定义两类颜色:

jsonc 复制代码
{
    "name": "My Theme",
    "type": "dark",                       // "dark" | "light" | "hc"
    "tokenColors": [                      // 1. 语法高亮(Token 颜色)
        { "scope": ["keyword", "storage.type"], "settings": { "foreground": "#C678DD", "fontStyle": "bold" } },
        { "scope": "comment", "settings": { "foreground": "#5C6370", "fontStyle": "italic" } }
    ],
    "colors": {                           // 2. UI 颜色(工作台颜色)
        "editor.background": "#282C34",
        "editor.foreground": "#ABB2BF",
        "sideBar.background": "#21252B"
    },
    "semanticHighlighting": true,         // 3. 语义高亮
    "semanticTokenColors": { "function.declaration": "#61AFEF" }
}

14. 远程开发架构

14.1 远程开发的分层

#mermaid-svg-7dUCoXQxzYYWgERr{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7dUCoXQxzYYWgERr .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7dUCoXQxzYYWgERr .error-icon{fill:#552222;}#mermaid-svg-7dUCoXQxzYYWgERr .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7dUCoXQxzYYWgERr .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7dUCoXQxzYYWgERr .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7dUCoXQxzYYWgERr .marker.cross{stroke:#333333;}#mermaid-svg-7dUCoXQxzYYWgERr svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7dUCoXQxzYYWgERr p{margin:0;}#mermaid-svg-7dUCoXQxzYYWgERr .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7dUCoXQxzYYWgERr .cluster-label text{fill:#333;}#mermaid-svg-7dUCoXQxzYYWgERr .cluster-label span{color:#333;}#mermaid-svg-7dUCoXQxzYYWgERr .cluster-label span p{background-color:transparent;}#mermaid-svg-7dUCoXQxzYYWgERr .label text,#mermaid-svg-7dUCoXQxzYYWgERr span{fill:#333;color:#333;}#mermaid-svg-7dUCoXQxzYYWgERr .node rect,#mermaid-svg-7dUCoXQxzYYWgERr .node circle,#mermaid-svg-7dUCoXQxzYYWgERr .node ellipse,#mermaid-svg-7dUCoXQxzYYWgERr .node polygon,#mermaid-svg-7dUCoXQxzYYWgERr .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7dUCoXQxzYYWgERr .rough-node .label text,#mermaid-svg-7dUCoXQxzYYWgERr .node .label text,#mermaid-svg-7dUCoXQxzYYWgERr .image-shape .label,#mermaid-svg-7dUCoXQxzYYWgERr .icon-shape .label{text-anchor:middle;}#mermaid-svg-7dUCoXQxzYYWgERr .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7dUCoXQxzYYWgERr .rough-node .label,#mermaid-svg-7dUCoXQxzYYWgERr .node .label,#mermaid-svg-7dUCoXQxzYYWgERr .image-shape .label,#mermaid-svg-7dUCoXQxzYYWgERr .icon-shape .label{text-align:center;}#mermaid-svg-7dUCoXQxzYYWgERr .node.clickable{cursor:pointer;}#mermaid-svg-7dUCoXQxzYYWgERr .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7dUCoXQxzYYWgERr .arrowheadPath{fill:#333333;}#mermaid-svg-7dUCoXQxzYYWgERr .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7dUCoXQxzYYWgERr .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7dUCoXQxzYYWgERr .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7dUCoXQxzYYWgERr .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7dUCoXQxzYYWgERr .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7dUCoXQxzYYWgERr .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7dUCoXQxzYYWgERr .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7dUCoXQxzYYWgERr .cluster text{fill:#333;}#mermaid-svg-7dUCoXQxzYYWgERr .cluster span{color:#333;}#mermaid-svg-7dUCoXQxzYYWgERr div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7dUCoXQxzYYWgERr .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7dUCoXQxzYYWgERr rect.text{fill:none;stroke-width:0;}#mermaid-svg-7dUCoXQxzYYWgERr .icon-shape,#mermaid-svg-7dUCoXQxzYYWgERr .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7dUCoXQxzYYWgERr .icon-shape p,#mermaid-svg-7dUCoXQxzYYWgERr .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7dUCoXQxzYYWgERr .icon-shape .label rect,#mermaid-svg-7dUCoXQxzYYWgERr .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7dUCoXQxzYYWgERr .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7dUCoXQxzYYWgERr .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7dUCoXQxzYYWgERr :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Remote Machine
Local Machine
SSH / Tunnel / WSL
VS Code Server · Remote Extension Host
文件系统相关的插件

语言服务器 · 调试器 · 终端

直接访问工作区文件
VS Code UI · Renderer + Extension Host
UI 相关的插件

主题 · 图标 · 代码片段等

14.2 extensionKind 的作用

jsonc 复制代码
{
    "extensionKind": ["workspace"]
    // "workspace" → 在工作区侧运行(远程机器上)
    // "ui" → 在 UI 侧运行(本地机器上)
    // ["ui", "workspace"] → 优先 UI 侧,回退到工作区侧
}

为什么重要? Git GUI 插件应在 UI 侧(需渲染 UI);代码格式化插件应在工作区侧(需访问文件);主题插件只在 UI 侧有意义。远程场景下,VSCode 会把 workspace 扩展调度到远端执行。


15. AI / Copilot 集成原理

15.1 VS Code 的 AI 扩展点

API 用途 典型场景
Chat Participant 注册 Chat 视图中的 AI 参与者 @workspace 问答
Chat Tool AI 可调用的工具 读取文件、执行搜索
Language Model API 访问大语言模型 自定义 AI 功能
Inline Chat 编辑器内联 AI 对话 Copilot Chat
Code Actions AI 驱动的代码操作 "Fix this error"
MCP (Model Context Protocol) 标准化工具协议 外部工具集成

15.2 Chat Participant 示例

typescript 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    const handler: vscode.ChatRequestHandler = async (
        request, context, stream, token
    ) => {
        const [model] = await vscode.lm.selectChatModels({ vendor: 'copilot', family: 'gpt-4o' });
        if (model) {
            const response = await model.sendRequest(
                [vscode.LanguageModelChatMessage.User(request.prompt)], {}, token
            );
            for await (const fragment of response.text) stream.markdown(fragment);
        }
    };
    const participant = vscode.chat.createChatParticipant('myExt.assistant', handler);
    participant.iconPath = vscode.Uri.joinPath(context.extensionUri, 'icon.png');
    context.subscriptions.push(participant);
}

15.3 MCP (Model Context Protocol)

jsonc 复制代码
// .vscode/mcp.json
{
    "servers": {
        "myServer": {
            "type": "stdio",
            "command": "node",
            "args": ["./mcp-server.js"]
        }
    }
}

16. Cursor 等 Fork 与 VSCode 的关系

16.1 代码层面的关系

Cursor、Windsurf、Code OSS、VSCodium 等产品都是基于 VSCode 的源码 fork。由于 VSCode 使用 MIT 许可证,这是完全合法的。
#mermaid-svg-d9G3NQelMPN4sfw9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-d9G3NQelMPN4sfw9 .error-icon{fill:#552222;}#mermaid-svg-d9G3NQelMPN4sfw9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-d9G3NQelMPN4sfw9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-d9G3NQelMPN4sfw9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-d9G3NQelMPN4sfw9 .marker.cross{stroke:#333333;}#mermaid-svg-d9G3NQelMPN4sfw9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-d9G3NQelMPN4sfw9 p{margin:0;}#mermaid-svg-d9G3NQelMPN4sfw9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster-label text{fill:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster-label span{color:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster-label span p{background-color:transparent;}#mermaid-svg-d9G3NQelMPN4sfw9 .label text,#mermaid-svg-d9G3NQelMPN4sfw9 span{fill:#333;color:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 .node rect,#mermaid-svg-d9G3NQelMPN4sfw9 .node circle,#mermaid-svg-d9G3NQelMPN4sfw9 .node ellipse,#mermaid-svg-d9G3NQelMPN4sfw9 .node polygon,#mermaid-svg-d9G3NQelMPN4sfw9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-d9G3NQelMPN4sfw9 .rough-node .label text,#mermaid-svg-d9G3NQelMPN4sfw9 .node .label text,#mermaid-svg-d9G3NQelMPN4sfw9 .image-shape .label,#mermaid-svg-d9G3NQelMPN4sfw9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-d9G3NQelMPN4sfw9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-d9G3NQelMPN4sfw9 .rough-node .label,#mermaid-svg-d9G3NQelMPN4sfw9 .node .label,#mermaid-svg-d9G3NQelMPN4sfw9 .image-shape .label,#mermaid-svg-d9G3NQelMPN4sfw9 .icon-shape .label{text-align:center;}#mermaid-svg-d9G3NQelMPN4sfw9 .node.clickable{cursor:pointer;}#mermaid-svg-d9G3NQelMPN4sfw9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-d9G3NQelMPN4sfw9 .arrowheadPath{fill:#333333;}#mermaid-svg-d9G3NQelMPN4sfw9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-d9G3NQelMPN4sfw9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-d9G3NQelMPN4sfw9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d9G3NQelMPN4sfw9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-d9G3NQelMPN4sfw9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d9G3NQelMPN4sfw9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster text{fill:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 .cluster span{color:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-d9G3NQelMPN4sfw9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-d9G3NQelMPN4sfw9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-d9G3NQelMPN4sfw9 .icon-shape,#mermaid-svg-d9G3NQelMPN4sfw9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-d9G3NQelMPN4sfw9 .icon-shape p,#mermaid-svg-d9G3NQelMPN4sfw9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-d9G3NQelMPN4sfw9 .icon-shape .label rect,#mermaid-svg-d9G3NQelMPN4sfw9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-d9G3NQelMPN4sfw9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-d9G3NQelMPN4sfw9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-d9G3NQelMPN4sfw9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 其他 Fork
VSCodium
Gitpod
更多...
Windsurf · Codeium
类似的 AI 增强
Cascade agent
Cursor
移除微软的遥测和 Marketplace
添加 AI Agent 功能
添加 Composer · Chat 等 AI UI
底层编辑器仍然是 Monaco
VS Code · microsoft/vscode · MIT License

16.2 对插件开发者的影响

方面 VS Code Cursor
插件 API 完全兼容 大部分兼容,有额外扩展
Marketplace 官方 Marketplace Open VSX + 自有注册
设置 标准 settings.json 兼容 + 额外 AI 相关设置
主题 完全兼容 完全兼容
快捷键 标准 有变化(如 Cmd+K)
配置目录 ~/.config/Code/ ~/.config/Cursor/

16.3 product.json:fork 换皮的关键杠杆

product.json 是 VSCode 与「具体发行版」之间的边界,放所有品牌与市场相关信息。fork 改这里就能换皮:

字段 含义
nameShort / nameLong 产品短名 / 全名
applicationName CLI 名(code / codium / ...)
dataFolderName 用户数据目录(.vscode / .vscode-oss
urlProtocol 协议头(vscode / vscodium
extensionsGallery 插件市场地址:serviceUrl / itemUrl / cacheUrl
builtInExtensions 内置扩展清单
extensionAllowedProposedApi Proposed API 白名单
quality 发布通道标识

最关键的 fork 杠杆是 extensionsGallery(改市场地址指向自己的插件源)和 extensionAllowedProposedApi(决定哪些扩展能用实验 API)。VSCodium 之所以默认不指向微软官方市场(版权原因),就是动这里。

16.4 Proposed API 放行机制

VSCode 有一部分 API 还没稳定(proposed),默认不对普通扩展开放:

  • 扩展在 package.jsonenabledApiProposals: ["chatParticipant"] 申明想用哪些;
  • 产品侧用 product.jsonextensionAllowedProposedApi 字段列出被放行的扩展 id;
  • 调试可用启动参数 --enable-proposed-api
  • 未放行却调用,运行时被挡掉并报警。

这就是为什么某些 VSCode 市场扩展在 Cursor / VSCodium 里行为不同:fork 的 product.json 放行策略不同。做跨编辑器兼容时,优先用稳定 API。

16.5 Cursor 如何利用 VSCode 架构

#mermaid-svg-9pjqVPP86ABMwEzH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9pjqVPP86ABMwEzH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9pjqVPP86ABMwEzH .error-icon{fill:#552222;}#mermaid-svg-9pjqVPP86ABMwEzH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9pjqVPP86ABMwEzH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9pjqVPP86ABMwEzH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9pjqVPP86ABMwEzH .marker.cross{stroke:#333333;}#mermaid-svg-9pjqVPP86ABMwEzH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9pjqVPP86ABMwEzH p{margin:0;}#mermaid-svg-9pjqVPP86ABMwEzH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9pjqVPP86ABMwEzH .cluster-label text{fill:#333;}#mermaid-svg-9pjqVPP86ABMwEzH .cluster-label span{color:#333;}#mermaid-svg-9pjqVPP86ABMwEzH .cluster-label span p{background-color:transparent;}#mermaid-svg-9pjqVPP86ABMwEzH .label text,#mermaid-svg-9pjqVPP86ABMwEzH span{fill:#333;color:#333;}#mermaid-svg-9pjqVPP86ABMwEzH .node rect,#mermaid-svg-9pjqVPP86ABMwEzH .node circle,#mermaid-svg-9pjqVPP86ABMwEzH .node ellipse,#mermaid-svg-9pjqVPP86ABMwEzH .node polygon,#mermaid-svg-9pjqVPP86ABMwEzH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9pjqVPP86ABMwEzH .rough-node .label text,#mermaid-svg-9pjqVPP86ABMwEzH .node .label text,#mermaid-svg-9pjqVPP86ABMwEzH .image-shape .label,#mermaid-svg-9pjqVPP86ABMwEzH .icon-shape .label{text-anchor:middle;}#mermaid-svg-9pjqVPP86ABMwEzH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9pjqVPP86ABMwEzH .rough-node .label,#mermaid-svg-9pjqVPP86ABMwEzH .node .label,#mermaid-svg-9pjqVPP86ABMwEzH .image-shape .label,#mermaid-svg-9pjqVPP86ABMwEzH .icon-shape .label{text-align:center;}#mermaid-svg-9pjqVPP86ABMwEzH .node.clickable{cursor:pointer;}#mermaid-svg-9pjqVPP86ABMwEzH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9pjqVPP86ABMwEzH .arrowheadPath{fill:#333333;}#mermaid-svg-9pjqVPP86ABMwEzH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9pjqVPP86ABMwEzH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9pjqVPP86ABMwEzH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9pjqVPP86ABMwEzH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9pjqVPP86ABMwEzH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9pjqVPP86ABMwEzH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9pjqVPP86ABMwEzH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9pjqVPP86ABMwEzH .cluster text{fill:#333;}#mermaid-svg-9pjqVPP86ABMwEzH .cluster span{color:#333;}#mermaid-svg-9pjqVPP86ABMwEzH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9pjqVPP86ABMwEzH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9pjqVPP86ABMwEzH rect.text{fill:none;stroke-width:0;}#mermaid-svg-9pjqVPP86ABMwEzH .icon-shape,#mermaid-svg-9pjqVPP86ABMwEzH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9pjqVPP86ABMwEzH .icon-shape p,#mermaid-svg-9pjqVPP86ABMwEzH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9pjqVPP86ABMwEzH .icon-shape .label rect,#mermaid-svg-9pjqVPP86ABMwEzH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9pjqVPP86ABMwEzH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9pjqVPP86ABMwEzH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9pjqVPP86ABMwEzH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VSCode Core (底层)
Monaco Editor
Extension Host
DI Container
RPC Protocol
LSP/DAP
Cursor AI Layer (扩展)
Auto-Apply Extension
textEditor.edit · 自动应用修改
SCM API 集成
Diff Editor 展示
Codebase Indexer Extension
workspace.onDidChangeTextDocument
增量索引代码库
Embedding 存储
AI Chat Extension
注册 Chat Participant
vscode.chat API
调用 LLM Service

开发 Cursor 类工具的关键知识点:

  • 必须理解:扩展激活时机(Activation Events)、RPC 通信模型(主线程 ↔ 扩展宿主)、依赖注入系统、Worker 计算模型;
  • 常用 APIworkspace.fs / textEditor.edit(读写文件)、onDidChangeTextDocument(监听变更)、commands.registerCommandregisterCompletionItemProviderdebug.startDebuggingWebview / TreeView
  • 性能优化 :合理使用 Activation Events(避免 *)、计算密集任务放 Worker/子进程、用 onDidChange 事件而非轮询、批量更新 UI、高频事件用 debounce;
  • 安全注意 :Webview 必须用 CSP + nonce、扩展 API 权限分级(secrets vs workspaceState)、外部链接用 vscode.env.openExternal、避免执行未验证的代码。

17. 实战:开发一个插件

17.1 快速开始

bash 复制代码
npm install -g yo generator-code   # 安装脚手架
yo code                            # 选择 "New Extension (TypeScript)"
cd my-extension
# 按 F5 或运行 "Debug: Start Debugging" 编译并启动调试

17.2 完整示例:代码统计插件

typescript 复制代码
// src/extension.ts
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    const statsCmd = vscode.commands.registerCommand('codeStats.showStats', async () => {
        const editor = vscode.window.activeTextEditor;
        if (!editor) { vscode.window.showWarningMessage('No active editor!'); return; }
        const doc = editor.document;
        const text = doc.getText();
        const lines = doc.lineCount;
        const chars = text.length;
        const words = text.split(/\s+/).filter(w => w.length > 0).length;
        vscode.window.showInformationMessage(
            `📄 ${doc.fileName.split('/').pop()}\nLines: ${lines}\nWords: ${words}\nCharacters: ${chars}\nLanguage: ${doc.languageId}`,
            { modal: true }
        );
    });

    const statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100);
    statusItem.command = 'codeStats.showStats';
    const updateStatusBar = (editor?: vscode.TextEditor) => {
        if (editor) { statusItem.text = `$(file) ${editor.document.lineCount} lines`; statusItem.show(); }
        else statusItem.hide();
    };
    vscode.window.onDidChangeActiveTextEditor(updateStatusBar);
    updateStatusBar(vscode.window.activeTextEditor);

    const codeLensProvider = vscode.languages.registerCodeLensProvider({ scheme: 'file' }, {
        provideCodeLenses(document) {
            const firstLine = document.lineAt(0);
            return [new vscode.CodeLens(firstLine.range, {
                title: `📊 ${document.lineCount} lines`, command: 'codeStats.showStats'
            })];
        }
    });

    const completionProvider = vscode.languages.registerCompletionItemProvider('typescript', {
        provideCompletionItems(document, position) {
            const linePrefix = document.lineAt(position).text.substr(0, position.character);
            if (linePrefix.endsWith('log.')) {
                return ['info', 'warn', 'error'].map(m => new vscode.CompletionItem(m, vscode.CompletionItemKind.Method));
            }
            return undefined;
        }
    }, '.');

    vscode.window.registerTreeDataProvider('codeStats.explorer', new StatsTreeDataProvider());

    context.subscriptions.push(statsCmd, statusItem, codeLensProvider, completionProvider);
}

class StatsTreeDataProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
    getTreeItem(element: vscode.TreeItem) { return element; }
    getChildren(): vscode.TreeItem[] {
        const item = new vscode.TreeItem('Current File Stats');
        item.description = 'Click to view';
        item.command = { command: 'codeStats.showStats', title: 'Show Stats' };
        return [item];
    }
}

export function deactivate() {}

对应的 package.json

jsonc 复制代码
{
    "name": "code-stats",
    "displayName": "Code Statistics",
    "version": "1.0.0",
    "engines": { "vscode": "^1.80.0" },
    "main": "./out/extension.js",
    "contributes": {
        "commands": [ { "command": "codeStats.showStats", "title": "Show Code Statistics", "category": "Code Stats" } ],
        "views": { "explorer": [ { "id": "codeStats.explorer", "name": "Code Statistics" } ] }
    }
}

18. 关键源码文件索引

核心架构

文件路径 说明
src/main.ts Electron 主进程入口
src/bootstrap-esm.ts ESM 引导入口,ASAR 支持
src/vs/workbench/browser/workbench.ts Workbench UI 入口
src/vs/workbench/workbench.common.main.ts 公共模块注册
src/vs/workbench/workbench.desktop.main.ts 桌面版主入口
src/vs/editor/editor.main.ts Monaco Editor 入口

插件系统

文件路径 说明
src/vs/workbench/services/extensions/common/extensions.ts 插件描述和管理
src/vs/workbench/services/extensions/common/extensionHostProtocol.ts Extension Host 通信协议
src/vs/workbench/api/common/extHost.api.impl.ts vscode.* API 的实际实现
src/vs/workbench/api/common/extHost.protocol.ts ExtHost 侧协议定义(MainThread/ExtHost 接口)
src/vs/workbench/services/extensions/common/abstractExtensionService.ts 插件加载和激活
src/vs/workbench/services/extensions/electron-browser/extensionHostStarter.ts 扩展宿主启动
src/vs/platform/instantiation/common/instantiation.ts DI 容器核心

内置插件(学习插件开发的最佳参考)

目录 说明
extensions/typescript-language-features/ TypeScript/JavaScript 支持(LSP 客户端)
extensions/markdown-language-features/ Markdown 支持(含预览 Webview)
extensions/git/ Git 集成(SCM Provider 示例)
extensions/emmet/ Emmet 支持(CompletionProvider 示例)
extensions/configuration-editing/ 配置编辑增强

配置与编辑器核心

文件路径 说明
src/vs/platform/configuration/common/configuration.ts 配置核心接口
src/vs/editor/common/model/textModel.ts 文本模型(Document Model)
src/vs/editor/browser/editor.ts 编辑器主类
src/vs/editor/common/languages/language.ts 语言注册和管理

19. VSCode API 速查表

窗口和编辑器

typescript 复制代码
const editor = vscode.window.activeTextEditor;

vscode.window.showInformationMessage('Info');
vscode.window.showWarningMessage('Warning');
vscode.window.showErrorMessage('Error');

const result = await vscode.window.showQuickPick(['Option A', 'Option B'], { placeHolder: 'Select' });
const name = await vscode.window.showInputBox({
    prompt: 'Enter your name',
    validateInput: (value) => value.length < 2 ? 'Too short' : null
});

await vscode.window.withProgress(
    { location: vscode.ProgressLocation.Notification, title: 'Processing...' },
    async (progress) => { progress.report({ increment: 50 }); await doWork(); }
);

工作区和文件

typescript 复制代码
const doc = await vscode.workspace.openTextDocument('/path/to/file');
await vscode.window.showTextDocument(doc);

const content = await vscode.workspace.fs.readFile(uri);
await vscode.workspace.fs.writeFile(uri, Buffer.from('content'));

vscode.workspace.onDidChangeTextDocument(e => console.log('Changed:', e.document.uri));
vscode.workspace.onDidSaveTextDocument(doc => console.log('Saved:', doc.uri));

const files = await vscode.workspace.findFiles('**/*.ts', '**/node_modules/**');

诊断和语言

typescript 复制代码
const diagnostics = vscode.languages.createDiagnosticCollection('myExt');
const diagnostic = new vscode.Diagnostic(
    new vscode.Range(0, 0, 0, 10), 'Something is wrong', vscode.DiagnosticSeverity.Error
);
diagnostics.set(document.uri, [diagnostic]);

本综合文档基于 microsoft/vscode 源码、官方 API 文档(code.visualstudio.com/api)与两份原始解读材料合并整理。VSCode 是持续演进的项目,具体实现细节可能随版本更新而变化,建议以源码为准。

相关推荐
laboratory agent开发43 分钟前
企业智能体上线后效果难以衡量:评估体系怎么搭
大数据·人工智能
AI英德西牛仔1 小时前
千问导出 pdf 颜色不一样怎么办,选用 AI 导出鸭优化格式转换,多维度剖析千问内容 PDF 变色各类成因
人工智能·ai·chatgpt·pdf·deepseek·ai导出鸭
小玮看世界1 小时前
当AI学会“讨好”:政务智能化的“泛娱乐化”陷阱与防治
人工智能
Mr.朱鹏1 小时前
科技周报(第2026-08-17):开源与变现
人工智能·科技·开源
TechEdu2026061 小时前
[人工智能]Tianshou强化学习框架:概念、架构与工程实践
人工智能·ai·rl
苏苏susuus1 小时前
从像素到汉字:OCR 模型是如何依靠 CNN “学会“识字的?
人工智能·cnn·ocr
努力搬砖的咸鱼1 小时前
意图理解:让Agent从需求描述自动生成Pytest测试策略
人工智能·python·ai·单元测试·pytest·agent
ZJU_统一阿萨姆1 小时前
【推理优化进阶】性能实验科学:工作负载、统计显著性与尾延迟归因
开发语言·人工智能·语言模型·系统架构·vllm
weixin_509138341 小时前
【无标题】
人工智能·agi·智能体·认知动力学·智能体认知