You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为VSCode扩展实现基于起始标记后首个空行的折叠策略?

我完全懂你想要的折叠效果——从##开头的章节标题开始,把后面的内容折叠到第一个空行结束,这种需求和VSCode原生Markdown的块折叠逻辑几乎一样,但直接用language-configuration.json里的折叠标记配置确实搞不定,原因我给你拆解下,再给你一个靠谱的解决方案:

为什么原生折叠标记配置不生效?

你试过的"end": "^\\s*$"没效果,核心原因有两个:

  1. VSCode的折叠标记机制会自动忽略纯空白行的标记匹配,它默认认为空白行不是有效的折叠边界;
  2. 折叠标记的startend是独立逐行匹配的,没法实现“找到一个start后,直到下一个空行才结束”这种上下文关联的逻辑——它只会找所有成对的start和end,而不是按顺序关联。

至于用下一个##作为end,会把下一个标题包含进折叠块,这是因为折叠范围是从start行到end行之间的所有内容,包括end行本身,显然不符合你的需求。

正确的解决方案:实现自定义FoldingRangeProvider

这也是VSCode原生Markdown折叠用的方法,通过代码自定义折叠逻辑,完全能满足你的需求。具体步骤如下:

1. 在扩展激活函数中注册折叠范围提供者

在你的扩展主文件(比如extension.ts)里添加以下代码:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    // 替换成你的目标语言ID,比如如果是自定义Markdown变种就用'markdown'或者你的自定义ID
    const targetLanguageId = 'your-language-id';

    const foldingProvider = vscode.languages.registerFoldingRangeProvider(targetLanguageId, {
        provideFoldingRanges(document: vscode.TextDocument): vscode.FoldingRange[] {
            const foldingRanges: vscode.FoldingRange[] = [];
            const allLines = document.getText().split('\n');
            let currentStartLine: number | undefined;

            allLines.forEach((line, lineIndex) => {
                // 匹配起始折叠标记:以##开头的行(允许行首有空格)
                if (/^##/.test(line.trimStart())) {
                    // 如果之前有未闭合的折叠块(比如两个标题之间没有空行)
                    if (currentStartLine !== undefined) {
                        // 折叠到当前标题的前一行
                        foldingRanges.push(new vscode.FoldingRange(currentStartLine, lineIndex - 1));
                    }
                    // 记录新的折叠起始行
                    currentStartLine = lineIndex;
                } 
                // 匹配结束折叠标记:空行(包括只含空格/tab的行)
                else if (/^\s*$/.test(line) && currentStartLine !== undefined) {
                    // 折叠到空行的前一行
                    foldingRanges.push(new vscode.FoldingRange(currentStartLine, lineIndex - 1));
                    currentStartLine = undefined;
                }
            });

            // 处理文档末尾未闭合的折叠块(最后一个标题到文件结尾)
            if (currentStartLine !== undefined) {
                foldingRanges.push(new vscode.FoldingRange(currentStartLine, allLines.length - 1));
            }

            return foldingRanges;
        }
    });

    context.subscriptions.push(foldingProvider);
}

2. 代码逻辑说明

  • 遍历文档的每一行,先找到所有##开头的行作为折叠起始点;
  • 当遇到空行时,把从起始行到空行的前一行设为折叠范围;
  • 如果两个标题之间没有空行,自动把前一个标题到下一个标题的前一行折叠起来;
  • 处理文档末尾的情况,确保最后一个章节即使没有结尾空行也能正常折叠。

3. 测试与调整

把代码里的your-language-id替换成你扩展对应的语言ID,然后重新加载扩展,就能看到你想要的折叠效果了——和原生Markdown的块折叠逻辑完全一致。

额外提示

如果你需要更精细的控制(比如排除某些特殊行、支持嵌套折叠等),可以在遍历行的时候添加额外的判断逻辑,这个Provider的灵活性很高,完全能适配各种自定义折叠需求。

内容的提问来源于stack exchange,提问作者aamarks

火山引擎 最新活动