TextDocument 内容操作
上一节掌握了文档与编辑器的关系,本节聚焦内容本身:如何读取、修改、保存文档文本,以及文档的语言、行尾、编码等元信息。
读取内容 getText
document.getText() 读取文档文本:
typescript
import * as vscode from 'vscode';
// 读取整个文档
const fullText = document.getText();
// 读取指定范围
const selection = editor.selection;
const selectedText = document.getText(selection);
// 读取某一行
const line = document.lineAt(5);
console.log(line.text); // 行内容
console.log(line.lineNumber); // 行号
console.log(line.range); // 行范围
// 读取范围(从行 2 到行 4)
const range = new vscode.Range(2, 0, 4, 0);
const part = document.getText(range);getText 参数
| 参数 | 说明 |
|---|---|
| 无参 | 返回整个文档 |
Range | 返回指定范围的文本 |
undefined | 与无参相同 |
编辑操作 insert / delete / replace
editBuilder 提供三种基本编辑操作:
typescript
await editor.edit((editBuilder) => {
// 插入:在指定位置插入文本
editBuilder.insert(
new vscode.Position(0, 0),
'import * as vscode from "vscode";\n\n'
);
// 删除:删除指定范围
const rangeToDelete = new vscode.Range(1, 0, 2, 0);
editBuilder.delete(rangeToDelete);
// 替换:用新文本替换范围
editBuilder.replace(
editor.selection,
'const result = calculate();'
);
});编辑操作的顺序与冲突
typescript
// 多次编辑会合并到一次事务
await editor.edit((editBuilder) => {
editBuilder.insert(new vscode.Position(0, 0), 'A');
editBuilder.insert(new vscode.Position(0, 0), 'B');
// 最终行首变为 "BA"(逆序应用)
});重叠的编辑操作会冲突,避免在同一回调中处理重叠范围。
保存文档 document.save
typescript
// 保存当前文档
await document.save();
// 另存为
const uri = await vscode.window.showSaveDialog({
defaultUri: document.uri
});
if (uri) {
await document.saveAs(uri);
}自动保存配置
| 方式 | 说明 |
|---|---|
document.save() | 显式保存 |
editor.document.isDirty | 是否未保存 |
| 用户配置自动保存 | 编辑器自动触发 |
TextEdit 批量文本编辑
TextEdit 可以在不绑定编辑器的情况下构建编辑操作:
typescript
import * as vscode from 'vscode';
// 构建 TextEdit 数组
const edits: vscode.TextEdit[] = [
vscode.TextEdit.insert(
new vscode.Position(0, 0),
'// header\n'
),
vscode.TextEdit.delete(
new vscode.Range(1, 0, 2, 0)
),
vscode.TextEdit.replace(
new vscode.Range(3, 0, 3, 10),
'new content'
)
];
// 应用到编辑器(等价于 editBuilder 多条)
const editor = vscode.window.activeTextEditor;
if (editor) {
await editor.edit((builder) => {
for (const edit of edits) {
// 判断编辑类型并应用
applyEdit(builder, edit);
}
});
}TextEdit 静态方法
| 方法 | 作用 |
|---|---|
TextEdit.insert(position, text) | 插入 |
TextEdit.delete(range) | 删除 |
TextEdit.replace(range, text) | 替换 |
new TextEdit(range, newText) | 构造函数 |
应用场景
- 文档格式化提供器返回 TextEdit 数组
- 代码操作(CodeAction)返回编辑
- 批量重构
文档元信息
TextDocument 提供语言、行尾、编码等信息:
typescript
const document = editor.document;
// 语言
console.log(document.languageId); // typescript
console.log(document.languageId === 'typescript');
// 行尾
console.log(document.eol); // EndOfLine.LF / CRLF
// 编码
console.log(document.encoding); // utf8
// 其他
console.log(document.fileName); // 完整路径
console.log(document.isUntitled); // 是否未保存
console.log(document.isDirty); // 是否有未保存修改
console.log(document.lineCount); // 总行数
console.log(document.version); // 版本号行尾处理
typescript
// 判断行尾类型
if (document.eol === vscode.EndOfLine.CRLF) {
// Windows 风格
} else {
// Unix 风格
}
// 需要时统一行尾
await editor.edit((builder) => {
// 将整个文档按 LF 规范化
builder.replace(
new vscode.Range(0, 0, document.lineCount, 0),
document.getText().replace(/\r\n/g, '\n')
);
});监听文档变更
typescript
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument((event) => {
if (event.document.uri.toString() !== document.uri.toString()) {
return;
}
// 变更内容
event.contentChanges.forEach((change) => {
console.log(`变更位置: ${change.range.start.line}`);
console.log(`新文本: ${change.text}`);
});
// 文档当前内容已更新
const current = event.document.getText();
})
);完整示例:内容操作工具
typescript
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand('contentTools.addHeader', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const document = editor.document;
const header = `// ${document.fileName.split('\\').pop()}\n` +
`// Created: ${new Date().toISOString()}\n\n`;
// 判断是否已存在头部
const firstLine = document.lineAt(0).text;
if (firstLine.startsWith('// ')) {
vscode.window.showWarningMessage('文档已有头部注释');
return;
}
await editor.edit((builder) => {
builder.insert(new vscode.Position(0, 0), header);
});
await document.save();
vscode.window.showInformationMessage('已添加文件头');
})
);
}常见问题
| 问题 | 处理 |
|---|---|
| getText 返回空 | 确认文档已加载、range 有效 |
| 编辑无效果 | edit() 需 await,且文档未关闭 |
| 行尾混乱 | 统一用 replace 规范化 |
| 中文乱码 | 确认读取时编码正确 |
内容操作是文本处理的核心,结合读取、编辑、保存与元信息,可以构建格式化、模板生成、批量替换等强大功能。