SCM 扩展概述
源码管理视图(Source Control View)是 VS Code 侧边栏的经典区域:未提交的修改、暂存的文件、提交输入框。Git 扩展就是基于 SCM API 实现的,任何自定义版本控制工具都可以接入。
SCM API 是什么
SCM API 提供了一组类型,让插件把"版本控制状态"呈现在源码管理视图中:
| 类型 | 作用 |
|---|---|
SourceControl | 一个源码管理实例(如 Git 仓库) |
SourceControlResourceGroup | 一组资源(如"更改""暂存的更改") |
SourceControlResourceState | 单个文件/资源的状态(修改、新增、删除) |
SourceControlInputBox | 提交信息输入框 |
SourceControlResourceDecorations | 资源在资源管理器中的装饰(颜色、图标) |
创建 SCM 实例
通过 vscode.scm.createSourceControl 创建:
typescript
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// 创建一个源码管理实例
const scm = vscode.scm.createSourceControl(
'myscm', // id:全局唯一
'MySCM', // label:源码管理视图中显示的名称
vscode.Uri.file('/path/to/repo') // 可选:关联的根目录
);
// 输入框
scm.inputBox.placeholder = '输入提交信息';
context.subscriptions.push(scm);
}创建后,侧边栏会出现一个新的源码管理图标与入口。
contributes.scmProvider 注册
SCM 实例可以编程式创建,也可以声明式注册。package.json 中:
json
{
"contributes": {
"scmProviders": [
{
"scmId": "myscm",
"label": "MySCM",
"rootUri": true
}
]
}
}| 字段 | 说明 |
|---|---|
scmId | 与 createSourceControl 的 id 对应 |
label | 显示名称 |
rootUri | 为 true 时,当工作区根目录打开时自动创建实例 |
关联命令
SCM 视图工具栏按钮通过命令贡献:
json
{
"contributes": {
"commands": [
{
"command": "myscm.pull",
"title": "拉取",
"icon": "$(cloud-download)",
"category": "MySCM"
},
{
"command": "myscm.push",
"title": "推送",
"icon": "$(cloud-upload)",
"category": "MySCM"
}
],
"menus": {
"scm/sourceControl/title": [
{
"command": "myscm.pull",
"when": "scmProvider == myscm",
"group": "navigation"
},
{
"command": "myscm.push",
"when": "scmProvider == myscm",
"group": "navigation"
}
]
}
}
}scmProvider 上下文变量用于在 when 条件中筛选当前激活的 SCM 提供者。
SourceControl 属性详解
创建后的实例有一系列可配置属性:
标签与计数
typescript
const scm = vscode.scm.createSourceControl('myscm', 'MySCM');
// 修改计数徽章(源码管理图标上显示)
scm.count = 12;
// 描述文字(视图标题下方)
scm.description = '分支: main';
// 自定义状态栏命令(如"切换分支""拉取")
scm.statusBarCommands = [
{
command: 'myscm.pull',
title: '$(cloud-download) 拉取',
tooltip: '从远程拉取更新',
arguments: []
}
];| 属性 | 说明 |
|---|---|
count | 未提交更改数,显示为徽章 |
description | 实例描述,可动态更新 |
inputBox | 提交信息输入框 |
acceptInputCommand | 提交按钮被按下时的命令 |
statusBarCommands | 状态栏显示的命令按钮 |
quickDiffProvider | 快速差异对比提供者 |
onDidChange | 实例属性变化事件 |
资源组
资源组是源码管理视图的分组单元:
typescript
// 创建两个资源组
const changes = scm.createResourceGroup(
'changes', // id
'更改' // label
);
const staged = scm.createResourceGroup(
'staged',
'暂存的更改'
);
// 更新资源组内容
changes.resourceStates = [
{
resourceUri: vscode.Uri.file('/repo/src/main.js'),
decorations: { strikeThrough: false }
}
];| 属性 | 说明 |
|---|---|
id | 资源组唯一 ID |
label | 分组标题 |
resourceStates | 该组下的资源状态数组 |
hideWhenEmpty | 为空时自动隐藏 |
onDidChange | 组内容变化事件 |
资源状态
单个文件的状态由 SourceControlResourceState 描述:
typescript
interface SourceControlResourceState {
// 文件 URI(必填)
resourceUri: vscode.Uri;
// 命令:点击资源时执行
command?: vscode.Command;
// 装饰:资源管理器中的表现
decorations?: vscode.SourceControlResourceDecorations;
// 上下文值:菜单 when 条件
contextValue?: string;
// 提示文本
tooltip?: string;
// 资源行的具体更改(用于打开 diff)
resourceStates?: SourceControlResourceState[];
}typescript
const fileState: vscode.SourceControlResourceState = {
resourceUri: vscode.Uri.file('/repo/src/main.js'),
command: {
command: 'vscode.diff',
title: '查看差异',
arguments: [
vscode.Uri.file('/repo/.snapshots/main.js'),
vscode.Uri.file('/repo/src/main.js'),
'main.js (工作区 vs 快照)'
]
},
contextValue: 'myscm.changed',
tooltip: '此文件已被修改'
};SCM 视图工作原理
源码管理视图的数据流:
text
插件
├─ scm.count ──────────────► 图标徽章
├─ resourceGroup ──────────► 分组标题
├─ resourceStates ─────────► 文件列表(点击触发 command)
├─ inputBox ───────────────► 提交信息输入
└─ acceptInputCommand ─────► 提交按钮点击视图的更新由 onDidChange 事件驱动。数据变化后应触发通知让视图刷新:
typescript
// 方式一:直接重新赋值触发刷新
changes.resourceStates = newStates;
// 方式二:发出变更事件(自动刷新)
scm.onDidChange.fire();实际上 resourceStates 赋值时视图会自动刷新,无需手动 fire。只有修改其他属性(count/description 等)时才需要手动触发。
菜单集成
SCM 视图支持丰富的右键菜单:
json
{
"contributes": {
"menus": {
"scm/resourceState/context": [
{
"command": "myscm.revert",
"when": "scmProvider == myscm && resourceState.contextValue == myscm.changed",
"group": "1_modification"
}
],
"scm/resourceGroup/context": [
{
"command": "myscm.stageAll",
"when": "scmProvider == myscm",
"group": "1_actions"
}
],
"scm/title": [
{
"command": "myscm.refresh",
"when": "scmProvider == myscm",
"group": "navigation"
}
]
}
}
}| 菜单位置 | 触发场景 |
|---|---|
scm/sourceControl/title | 源码管理实例标题工具栏 |
scm/title | 源码管理视图标题工具栏 |
scm/resourceGroup/context | 资源组右键菜单 |
scm/resourceState/context | 单个资源右键菜单 |
resourceState.contextValue 可在 when 条件中使用,实现对不同状态文件的差异化菜单。
快速差异(Quick Diff)
编辑器左侧的差异指示条由 quickDiffProvider 提供:
typescript
import * as vscode from 'vscode';
class MyQuickDiffProvider implements vscode.QuickDiffProvider {
// 提供原始版本内容
provideOriginalResource(
uri: vscode.Uri,
token: vscode.CancellationToken
): vscode.ProviderResult<vscode.Uri> {
// 返回快照文件 URI
const snapshot = uri.fsPath.replace('/repo/', '/repo/.snapshots/');
return vscode.Uri.file(snapshot);
}
}
scm.quickDiffProvider = new MyQuickDiffProvider();SCM 基础框架搭建完成后,下一步深入资源组的精细管理。