VScode插件开发

VScode插件之QuickFix

2022-11-26  本文已影响0人  从今以后_19d7

诊断项提供者逻辑

/**
 * 提供转换为笑脸符号的代码操作。
 */
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;
    }
}

针对诊断项的快速修复

/**
 * 提供与诊断问题对应的代码操作。
 */
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);
}

创建诊断项的逻辑

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;
}
上一篇下一篇

猜你喜欢

热点阅读