You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建VS Code扩展实现自定义脚本文本可见性的命令/视图切换?

自定义脚本内容显示切换的最优实现方案

核心思路

基于VS Code原生API,结合你正在开发的语言工具链,实现标识符的显示/隐藏切换,以下是三个不同复杂度的方案,按需选择:

方案一:文本装饰隐藏(快速上手)

这是最适合新手的快速实现方式,通过VS Code的文本装饰API把标识符“隐藏”,不会修改原始文档内容:

  • 先定义一个隐藏样式的装饰类型:
    // 扩展激活时创建装饰类型
    const hiddenIdDecoration = vscode.window.createTextEditorDecorationType({
        opacity: '0', // 完全透明
        letterSpacing: '-999px', // 消除占位宽度,避免布局偏移
        rangeBehavior: vscode.DecorationRangeBehavior.ClosedClosed
    });
    
  • 编写扫描标识符位置的函数:
    function getIdentifierRanges(doc: vscode.TextDocument): vscode.DecorationOptions[] {
        const ranges: vscode.DecorationOptions[] = [];
        const text = doc.getText();
        // 替换成你匹配标识符的正则,比如假设ID格式是 [XXX] 结尾
        const regex = /\s*\[\w+\]$/gm;
        let match;
        while ((match = regex.exec(text)) !== null) {
            const start = doc.positionAt(match.index);
            const end = doc.positionAt(match.index + match[0].length);
            ranges.push({ range: new vscode.Range(start, end) });
        }
        return ranges;
    }
    
  • 注册切换命令,控制装饰显示:
    let showIdentifiers = true;
    
    vscode.commands.registerCommand('yourExt.toggleStringIds', () => {
        showIdentifiers = !showIdentifiers;
        const activeEditor = vscode.window.activeTextEditor;
        if (activeEditor && activeEditor.document.languageId === '你的自定义语言ID') {
            const decorations = showIdentifiers ? [] : getIdentifierRanges(activeEditor.document);
            activeEditor.setDecorations(hiddenIdDecoration, decorations);
        }
    });
    
  • 监听文档变化,自动更新装饰:
    vscode.window.onDidChangeActiveTextEditor(updateDecorations);
    vscode.workspace.onDidChangeTextDocument(e => {
        if (vscode.window.activeTextEditor?.document === e.document) {
            updateDecorations();
        }
    });
    
    function updateDecorations() {
        const activeEditor = vscode.window.activeTextEditor;
        if (!activeEditor || activeEditor.document.languageId !== '你的自定义语言ID') return;
        const decorations = showIdentifiers ? [] : getIdentifierRanges(activeEditor.document);
        activeEditor.setDecorations(hiddenIdDecoration, decorations);
    }
    

方案二:虚拟文档双视图(完全分离)

如果需要同时打开“作者视图”和“开发者视图”,可以用虚拟文档实现两个视图内容独立:

  • 注册虚拟文档内容提供者:
    class AuthorViewProvider implements vscode.TextDocumentContentProvider {
        provideTextDocumentContent(uri: vscode.Uri): string {
            // 从查询参数获取原始文档URI
            const originalUri = vscode.Uri.parse(uri.query);
            const originalDoc = vscode.workspace.textDocuments.find(d => d.uri.toString() === originalUri.toString());
            if (!originalDoc) return '';
            
            // 过滤每行标识符,替换成你的实际逻辑
            return originalDoc.getText().split('\n')
                .map(line => line.replace(/\s*\[\w+\]$/, '')) // 移除结尾的[ID]
                .join('\n');
        }
    }
    
    // 注册提供者
    vscode.workspace.registerTextDocumentContentProvider('author-view', new AuthorViewProvider());
    
  • 注册打开作者视图的命令:
    vscode.commands.registerCommand('yourExt.openAuthorView', () => {
        const activeEditor = vscode.window.activeTextEditor;
        if (!activeEditor || activeEditor.document.languageId !== '你的自定义语言ID') return;
        
        // 构造虚拟文档URI
        const virtualUri = vscode.Uri.parse(`author-view:${activeEditor.document.uri.path}?${activeEditor.document.uri.toString()}`);
        // 在侧边打开虚拟文档
        vscode.window.showTextDocument(virtualUri, { viewColumn: vscode.ViewColumn.Beside, preserveFocus: true });
    });
    
  • 在package.json中给虚拟文档关联自定义语法:
    "contributes": {
        "languages": [
            {
                "id": "你的自定义语言ID",
                "filenames": ["*.yourExt"],
                "aliases": ["你的语言名"],
                "configuration": "./language-configuration.json"
            }
        ],
        "grammars": [
            {
                "language": "你的自定义语言ID",
                "scopeName": "source.yourLang",
                "path": "./syntaxes/yourLang.tmLanguage.json"
            }
        ],
        "commands": [
            {
                "command": "yourExt.openAuthorView",
                "title": "打开作者视图"
            },
            {
                "command": "yourExt.toggleStringIds",
                "title": "切换标识符显示"
            }
        ]
    }
    

方案三:语言服务器集成(长期最优)

结合你正在开发的语言服务器,利用语义分析精准控制标识符显示:

  • 在语言服务器中,对每个标识符做语义标记,通过semanticTokens或自定义通知把位置信息发给客户端
  • 客户端收到语义信息后,应用装饰逻辑实现显示/隐藏切换
  • 优势:能处理复杂脚本结构(比如嵌套、多行标识符),支持跨文档状态同步,后续扩展更灵活

推荐方案

  • 新手优先选方案一,代码量少,半天就能跑通,不影响现有开发流程
  • 需要双视图并行编辑/查看,选方案二
  • 长期维护扩展,选方案三,和语言服务器能力结合更紧密

内容的提问来源于stack exchange,提问作者Lex C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:01:09