诊断项提供者逻辑
-
provideCodeActions
方法返回一个CodeAction
类型的列表 -
createFix
和createCommand
方法提供两种不同的修复项,他们都是返回CodeAction
类型对象 - 注册多个修复项
isPreferred
可以设置首选项,Alt+Shift+.
执行快速修复,会命中该选项
/**
* 提供转换为笑脸符号的代码操作。
*/
export class Emojizer implements vscode.CodeActionProvider {
// 类型为快速修复
public static readonly
providedCodeActionKinds = [
vscode.CodeActionKind.QuickFix
];
public provideCodeActions(document: vscode.TextDocument, range: vscode.Range): vscode.CodeAction[] | undefined {
if (!this.isAtStartOfSmiley(document, range)) {
return;
}
// 添加三项修复项
const replaceWithSmileyCatFix = this.createFix(document, range, '😺');
const replaceWithSmileyFix = this.createFix(document, range, '😀');
// 将单个修复标记为`首选的`意味着用户可以使用`Auto Fix`命令使用单个键盘快捷键来应用它。
replaceWithSmileyFix.isPreferred = true;
const replaceWithSmileyHankyFix = this.createFix(document, range, '💩');
const commandAction = this.createCommand();
// 返回 CodeAction 类型的列表,表示该光标位置的修复项
return [
replaceWithSmileyCatFix,
replaceWithSmileyFix,
replaceWithSmileyHankyFix,
commandAction
];
}
// 检查该范围是否需要进行
private isAtStartOfSmiley(document: vscode.TextDocument, range: vscode.Range) {
// range代表光标位置, start和end是同一个值
const start = range.start;
// 获取该行文本
const line = document.lineAt(start.line);
// 检测光标后是否笑脸
return line.text[start.character] === ':' && line.text[start.character + 1] === ')';
}
// 创建一个修复项
private createFix(document: vscode.TextDocument, range: vscode.Range, emoji: string): vscode.CodeAction {
// 初始化一个快速修复,传入(标题,类型)
const fix = new vscode.CodeAction(`Convert to ${emoji}`, vscode.CodeActionKind.QuickFix);
fix.edit = new vscode.WorkspaceEdit();
// 修复操作, 命名空间替换(文档, 范围, 内容)
fix.edit.replace(document.uri, new vscode.Range(range.start, range.start.translate(0, 2)), emoji);
return fix;
}
// 创建一个命令
private createCommand(): vscode.CodeAction {
// 初始化一个快速修复,传入(标题,类型)
const action = new vscode.CodeAction('Learn more...', vscode.CodeActionKind.Empty);
// 触发一个命令
action.command = {
command: COMMAND,
title: 'Learn more about emojis',
tooltip: 'This will open the unicode emoji page.'
};
return action;
}
}
针对诊断项的快速修复
- 通过
diagnostic.code
属性来确定是否出示快速修复项
/**
* 提供与诊断问题对应的代码操作。
*/
export class Emojinfo implements vscode.CodeActionProvider {
// 类型为快速修复
public static readonly providedCodeActionKinds = [
vscode.CodeActionKind.QuickFix
];
provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): vscode.CodeAction[] {
// 对于每个具有匹配的`代码`的诊断条目,创建一个代码操作命令
return context.diagnostics
.filter(diagnostic => diagnostic.code === EMOJI_MENTION)
.map(diagnostic => this.createCommandCodeAction(diagnostic));
}
private createCommandCodeAction(diagnostic: vscode.Diagnostic): vscode.CodeAction {
const action = new vscode.CodeAction('Learn more...', vscode.CodeActionKind.QuickFix);
action.command = {
command: COMMAND,
title: 'Learn more about emojis',
tooltip: 'This will open the unicode emoji page.'
};
// 诊断项
action.diagnostics = [diagnostic];
// 首选项
action.isPreferred = true;
return action;
}
}
针对诊断项来做快速修复的话, 需要先收集所有的诊断项
// 诊断性容器
const emojiDiagnostics = vscode.languages.createDiagnosticCollection("emoji");
// 注册到销毁容器, 当插件卸载时不至于占用过多内存
context.subscriptions.push(emojiDiagnostics);
// 进行诊断项的收集
subscribeToDocumentChanges(context, emojiDiagnostics);
进行诊断的时机
export function subscribeToDocumentChanges(context: vscode.ExtensionContext, emojiDiagnostics: vscode.DiagnosticCollection): void {
// 入口处是当插件被激活时, 如果存在活动文档, 则对活动文档进行诊断
if (vscode.window.activeTextEditor) {
refreshDiagnostics(vscode.window.activeTextEditor.document, emojiDiagnostics);
}
// 当活动文档发生切换时
context.subscriptions.push(
vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor) {
refreshDiagnostics(editor.document, emojiDiagnostics);
}
})
);
// 当文档内容发生修改时
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument(e => refreshDiagnostics(e.document, emojiDiagnostics))
);
// 文档关闭时, 删除诊断容器
context.subscriptions.push(
vscode.workspace.onDidCloseTextDocument(doc => emojiDiagnostics.delete(doc.uri))
);
}
收集诊断项, 也是诊断这个功能的核心逻辑, 只是这里需要用户替换自己的逻辑,那些代码状态需要进行诊断?
/**
* 分析文本文档中出现的问题。这个演示诊断问题提供者会找到所有提到的“表情符号”。
* @param doc text document to analyze
* @param emojiDiagnostics diagnostic collection
*/
export function refreshDiagnostics(doc: vscode.TextDocument, emojiDiagnostics: vscode.DiagnosticCollection): void {
const diagnostics: vscode.Diagnostic[] = [];
// 循环每一行
for (let lineIndex = 0; lineIndex < doc.lineCount; lineIndex++) {
// 如果包含目标的文本则创建一个诊断项, 这里实际应该替换成自己的逻辑
const lineOfText = doc.lineAt(lineIndex);
if (lineOfText.text.includes(EMOJI)) {
// 创建一个诊断项放入容器中
diagnostics.push(createDiagnostic(doc, lineOfText, lineIndex));
}
}
// 向容器中添加诊断项列表
emojiDiagnostics.set(doc.uri, diagnostics);
}
创建诊断项的逻辑
- 创建诊断项(范围, 标题, 类型)
- 通过
diagnostic.code = EMOJI_MENTION
来区分本诊断项的类型, 在快速修复的地方会判断这个条件
function createDiagnostic(doc: vscode.TextDocument, lineOfText: vscode.TextLine, lineIndex: number): vscode.Diagnostic {
// 找到在“表情符号”这一行中提到的位置
const index = lineOfText.text.indexOf(EMOJI);
// 创建表示单词在文档中的位置的范围
const range = new vscode.Range(lineIndex, index, lineIndex, index + EMOJI.length);
const diagnostic = new vscode.Diagnostic(range, "When you say 'emoji', do you want to find out more?",
vscode.DiagnosticSeverity.Information);
diagnostic.code = EMOJI_MENTION;
return diagnostic;
}
网友评论