Markdown region folding (#55399)

* Add foldin g of regions to markdown

* Add test for region folding

* Tweak region identification regex
This commit is contained in:
Jackson Kearl
2018-08-07 13:47:29 -07:00
committed by Matt Bierner
parent 868140430d
commit 6a1515671f
2 changed files with 59 additions and 5 deletions

View File

@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
import { MarkdownEngine } from '../markdownEngine';
import { TableOfContentsProvider } from '../tableOfContentsProvider';
import { Token } from 'markdown-it';
const rangeLimit = 5000;
@@ -16,15 +17,44 @@ export default class MarkdownFoldingProvider implements vscode.FoldingRangeProvi
private readonly engine: MarkdownEngine
) { }
private async getRegions(document: vscode.TextDocument): Promise<vscode.FoldingRange[]> {
const isStartRegion = (t: string) => /^\s*<!--\s*#?region\b.*-->/.test(t);
const isEndRegion = (t: string) => /^\s*<!--\s*#?endregion\b.*-->/.test(t);
const isRegionMarker = (token: Token) => token.type === 'html_block' &&
(isStartRegion(token.content) || isEndRegion(token.content));
const tokens = await this.engine.parse(document.uri, document.getText());
const regionMarkers = tokens.filter(isRegionMarker)
.map(token => ({ line: token.map[0], isStart: isStartRegion(token.content) }));
const nestingStack: { line: number, isStart: boolean }[] = [];
return regionMarkers
.map(marker => {
if (marker.isStart) {
nestingStack.push(marker);
} else if (nestingStack.length && nestingStack[nestingStack.length - 1].isStart) {
return new vscode.FoldingRange(nestingStack.pop()!.line, marker.line, vscode.FoldingRangeKind.Region);
} else {
// noop: invalid nesting (i.e. [end, start] or [start, end, end])
}
return null;
})
.filter((region: vscode.FoldingRange | null): region is vscode.FoldingRange => !!region);
}
public async provideFoldingRanges(
document: vscode.TextDocument,
_: vscode.FoldingContext,
_token: vscode.CancellationToken
): Promise<vscode.FoldingRange[]> {
const tocProvider = new TableOfContentsProvider(this.engine, document);
let toc = await tocProvider.getToc();
if (toc.length > rangeLimit) {
toc = toc.slice(0, rangeLimit);
let [regions, toc] = await Promise.all([this.getRegions(document), tocProvider.getToc()]);
if (toc.length > rangeLimit - regions.length) {
toc = toc.slice(0, rangeLimit - regions.length);
}
const foldingRanges = toc.map((entry, startIndex) => {
@@ -44,7 +74,6 @@ export default class MarkdownFoldingProvider implements vscode.FoldingRangeProvi
typeof end === 'number' ? end : document.lineCount - 1);
});
return foldingRanges;
return [...regions, ...foldingRanges];
}
}