in src/services/htmlFolding.ts [83:171]
export function getFoldingRanges(document: TextDocument, context: { rangeLimit?: number }): FoldingRange[] {
const scanner = createScanner(document.getText());
let token = scanner.scan();
const ranges: FoldingRange[] = [];
const stack: { startLine: number, tagName: string }[] = [];
let lastTagName = null;
let prevStart = -1;
function addRange(range: FoldingRange) {
ranges.push(range);
prevStart = range.startLine;
}
while (token !== TokenType.EOS) {
switch (token) {
case TokenType.StartTag: {
const tagName = scanner.getTokenText();
const startLine = document.positionAt(scanner.getTokenOffset()).line;
stack.push({ startLine, tagName });
lastTagName = tagName;
break;
}
case TokenType.EndTag: {
lastTagName = scanner.getTokenText();
break;
}
case TokenType.StartTagClose:
if (!lastTagName || !isVoidElement(lastTagName)) {
break;
}
// fallthrough
case TokenType.EndTagClose:
case TokenType.StartTagSelfClose: {
let i = stack.length - 1;
while (i >= 0 && stack[i].tagName !== lastTagName) {
i--;
}
if (i >= 0) {
const stackElement = stack[i];
stack.length = i;
const line = document.positionAt(scanner.getTokenOffset()).line;
const startLine = stackElement.startLine;
const endLine = line - 1;
if (endLine > startLine && prevStart !== startLine) {
addRange({ startLine, endLine });
}
}
break;
}
case TokenType.Comment: {
let startLine = document.positionAt(scanner.getTokenOffset()).line;
const text = scanner.getTokenText();
const m = text.match(/^\s*#(region\b)|(endregion\b)/);
if (m) {
if (m[1]) { // start pattern match
stack.push({ startLine, tagName: '' }); // empty tagName marks region
} else {
let i = stack.length - 1;
while (i >= 0 && stack[i].tagName.length) {
i--;
}
if (i >= 0) {
const stackElement = stack[i];
stack.length = i;
const endLine = startLine;
startLine = stackElement.startLine;
if (endLine > startLine && prevStart !== startLine) {
addRange({ startLine, endLine, kind: FoldingRangeKind.Region });
}
}
}
} else {
const endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
if (startLine < endLine) {
addRange({ startLine, endLine, kind: FoldingRangeKind.Comment });
}
}
break;
}
}
token = scanner.scan();
}
const rangeLimit = context && context.rangeLimit || Number.MAX_VALUE;
if (ranges.length > rangeLimit) {
return limitRanges(ranges, rangeLimit);
}
return ranges;
}