SCM 输入框与操作
源码管理视图的底部是提交输入框,顶部按钮执行拉取/推送等操作。本文深入输入框的配置与校验、提交按钮的行为绑定、状态栏命令与计数徽章。
inputBox 输入框
sourceControl.inputBox 是提交信息输入框,提供完整的交互配置:
typescript
import * as vscode from 'vscode';
const scm = vscode.scm.createSourceControl('myscm', 'MySCM');
// 基本配置
scm.inputBox.placeholder = '输入提交信息(Enter 提交)';
scm.inputBox.visible = true;
// 设置初始值
scm.inputBox.value = 'fix: 修复登录问题';inputBox 属性
| 属性 | 类型 | 说明 |
|---|---|---|
value | string | 当前输入内容(可读写) |
placeholder | string | 空输入时的提示文字 |
visible | boolean | 是否显示输入框 |
enabled | boolean | 是否可编辑 |
onDidChange | Event | 输入内容变化事件 |
validateInput | 函数 | 输入校验函数 |
输入校验
typescript
scm.inputBox.validateInput = (value: string): string | undefined => {
// 返回字符串表示校验失败,内容为错误提示
if (!value.trim()) {
return '提交信息不能为空';
}
// 校验格式(如要求前缀)
const allowed = ['feat', 'fix', 'docs', 'refactor'];
const match = value.match(/^([a-z]+):\s/);
if (match && !allowed.includes(match[1])) {
return `提交类型 ${match[1]} 不受支持`;
}
// 返回 undefined 表示通过
return undefined;
};输入框下方会实时显示校验错误信息,有错误时提交按钮自动禁用。
提交按钮行为
提交按钮("✓")按下时触发 acceptInputCommand:
typescript
// 注册提交命令
const commitCommand = 'myscm.commit';
context.subscriptions.push(
vscode.commands.registerCommand(commitCommand, async () => {
const message = scm.inputBox.value.trim();
if (!message) {
vscode.window.showWarningMessage('提交信息为空');
return;
}
try {
await performCommit(message);
// 提交成功后清空输入框
scm.inputBox.value = '';
// 刷新资源组
refreshGroups();
vscode.window.showInformationMessage(`已提交: ${message}`);
} catch (err) {
vscode.window.showErrorMessage(`提交失败: ${err.message}`);
}
})
);
// 绑定到输入框
scm.acceptInputCommand = {
command: commitCommand,
title: '提交',
arguments: []
};提交时序
text
用户输入提交信息
↓
输入校验通过(validateInput 返回 undefined)
↓
点击提交按钮
↓
触发 acceptInputCommand
↓
执行提交命令 → 成功清空输入框并刷新提交确认与快捷键
typescript
// 在输入框中按 Ctrl+Enter 直接提交(编辑绑定)
{
"contributes": {
"keybindings": [
{
"command": "myscm.commit",
"key": "ctrl+enter",
"when": "scmProvider == myscm && inputBoxFocus"
}
]
}
}statusBarCommands 状态栏命令
statusBarCommands 在源码管理实例行显示操作按钮:
typescript
scm.statusBarCommands = [
{
command: 'myscm.pull',
title: '$(cloud-download) 拉取',
tooltip: '从远程拉取更新',
arguments: []
},
{
command: 'myscm.push',
title: '$(cloud-upload) 推送',
tooltip: '推送本地提交',
arguments: []
}
];命令实现示例:
typescript
vscode.commands.registerCommand('myscm.pull', async () => {
await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
title: '正在拉取...'
},
async () => {
await runScmCommand('pull');
refreshGroups();
}
);
});按钮标题支持 $(icon) 语法与动态文本:
typescript
// 动态显示分支名
function updateStatusBar() {
scm.statusBarCommands = [
{
command: 'myscm.switchBranch',
title: `$(git-branch) ${currentBranch}`,
tooltip: '切换分支'
},
{
command: 'myscm.pull',
title: '$(cloud-download) 拉取',
tooltip: '拉取更新'
}
];
}count 未提交计数
scm.count 控制在源码管理图标上的徽章数字:
typescript
// 刷新时更新计数
function updateCount() {
scm.count = modifiedGroup.resourceStates.length +
untrackedGroup.resourceStates.length;
}| 值 | 表现 |
|---|---|
0 | 不显示徽章 |
| 正数 | 显示数字徽章 |
undefined | 不显示徽章(同 0) |
完整交互流程示例
组装输入框、提交、状态栏与计数:
typescript
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
const scm = vscode.scm.createSourceControl('myscm', 'MySCM');
const group = scm.createResourceGroup('changes', '更改');
// 输入框配置
scm.inputBox.placeholder = '提交信息(Enter 提交)';
scm.inputBox.validateInput = (value) =>
value.trim() ? undefined : '请输入提交信息';
// 提交命令
context.subscriptions.push(
vscode.commands.registerCommand('myscm.commit', async () => {
const message = scm.inputBox.value.trim();
await commit(message);
scm.inputBox.value = '';
await refresh();
vscode.window.showInformationMessage('提交成功');
})
);
// 绑定提交按钮
scm.acceptInputCommand = {
command: 'myscm.commit',
title: '提交'
};
// 状态栏命令
scm.statusBarCommands = [
{
command: 'myscm.pull',
title: '$(cloud-download) 拉取',
tooltip: '拉取更新'
}
];
context.subscriptions.push(
vscode.commands.registerCommand('myscm.pull', async () => {
await runCommand('pull');
await refresh();
})
);
// 刷新函数
async function refresh() {
const changes = await scanChanges();
group.resourceStates = changes.map((c) => ({
resourceUri: c.uri,
contextValue: 'myscm.changed',
decorations: {
letter: 'M',
tooltip: '已修改',
color: new vscode.ThemeColor('gitDecoration.modifiedResourceForeground')
}
}));
scm.count = changes.length;
}
context.subscriptions.push(scm);
refresh();
}输入框的高级用法
多仓库联动
typescript
// 一个扩展管理多个仓库
const repos = [/* ... */];
const scms = repos.map((repo) => {
const s = vscode.scm.createSourceControl(`myscm.${repo.id}`, repo.name);
return s;
});
// 切换工作区时聚焦对应实例
vscode.workspace.onDidChangeWorkspaceFolders(() => {
const active = vscode.workspace.workspaceFolders?.[0];
if (active) {
const target = scms.find((s) => s.id === `myscm.${active.name}`);
// 聚焦由用户切换,插件只需保持数据同步
}
});输入框内容同步
typescript
// 跨实例共享提交信息(如"全部提交")
scm.inputBox.onDidChange((value) => {
otherScms.forEach((s) => {
if (s.inputBox.value !== value) {
s.inputBox.value = value;
}
});
});输入框、提交按钮、状态栏命令与计数构成了 SCM 实例的完整操作面,下一篇把这些能力用于真实的 Git 集成。