4

How can I make a VSCode extension folding strategy based on the first blank line following a starting folding marker?

## Some section   --|
Any text...         |  (this should fold)
...more text.     --|
                       (blank line)
## Another section     (next fold...)

I've tried lots of regex in the language-configuration.json.

    "folding": {
        "markers": {
            "start": "^##",
            "end": "^\\s*$"
    } },

If I change things to test with something other than a blank (or whitespace) line as the end delimiter it works. Can't use the next start marker to mark the end of the last or it includes it in the fold (I tried look ahead regex, but I think the regex are applied line by line and the matches can't span lines?)

It's similar to the folding needed for Markdown which VSCode handles well (don't know if that's using a more complex method like https://code.visualstudio.com/api/references/vscode-api#FoldingRangeProvider).

Maybe something in the fixes for [folding] should not fold white space after function has something to do with it.

aamarks
  • 942
  • 10
  • 17

1 Answers1

3

What I learned: 1. the begin and end regex are applied line by line. 2. tmLanguage start/end regex will work on blank lines, but currently language-configuration folding doesn't seem to work on blank lines.

And since blank lines are in this case a hack for ending at the next begin section:

To solve the problem of folding a section to the next similar section I used the FoldingRangeProvider.

    disposable = vscode.languages.registerFoldingRangeProvider('myExt', {
        provideFoldingRanges(document, context, token) {
            //console.log('folding range invoked'); // comes here on every character edit
            let sectionStart = 0, FR = [], re = /^## /;  // regex to detect start of region

            for (let i = 0; i < document.lineCount; i++) {

                if (re.test(document.lineAt(i).text)) {
                    if (sectionStart > 0) {
                        FR.push(new vscode.FoldingRange(sectionStart, i - 1, vscode.FoldingRangeKind.Region));
                    }
                    sectionStart = i;
                }
            }
            if (sectionStart > 0) { FR.push(new vscode.FoldingRange(sectionStart, document.lineCount - 1, vscode.FoldingRangeKind.Region)); }

            return FR;
        }
    });

Set "editor.foldingStrategy": "auto". You can make it more sophisticated to preserve white space between sections.

aamarks
  • 942
  • 10
  • 17
  • 1
    where does that FoldingRangeProvider go? i want to make my own extension for vscode, and the help/tutorials i can find online are not exactly helpful in any way, if you have to start from scratch. – Sabito stands with Ukraine Oct 16 '20 at 13:55
  • Sorry, just noticed this... It goes in your extension.ts file within the Activate function. Pull the vscode samples to learn, https://github.com/microsoft/vscode-extension-samples. – aamarks Aug 09 '21 at 19:00
  • Is there any way to compute the folding ranges based on the tokenization? So that we can avoid picking up keywords in strings and the like – Ted Brownlow Jan 28 '23 at 21:39
  • @Ted Brownlow I'm not sure what you're asking and it's been a long time since I messed with this. Pretty sure any VSC tokenization done through json in a tmLanguage file to color keywords is not accessible from your code in .ts files. If you can accomplish your folding through language-configuration.json, that is the easier way--I assume VSC creates a FoldingRangeProvider based on that json. – aamarks Feb 18 '23 at 19:50