美文网首页VScode插件开发
VScode插件之QuickFix

VScode插件之QuickFix

作者: 从今以后_19d7 | 来源:发表于2022-11-26 15:32 被阅读0次

    诊断项提供者逻辑

    • provideCodeActions方法返回一个CodeAction类型的列表
    • createFixcreateCommand方法提供两种不同的修复项,他们都是返回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;
    }
    

    相关文章

      网友评论

        本文标题:VScode插件之QuickFix

        本文链接:https://www.haomeiwen.com/subject/jikqfdtx.html