blob: 50ac5d06210c879411d0c5ad31417e5e8171bd9f [file] [log] [blame]
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "vscode-languageserver-types", "../htmlLanguageTypes", "../parser/htmlScanner", "../languageFacts/fact"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var vscode_languageserver_types_1 = require("vscode-languageserver-types");
var htmlLanguageTypes_1 = require("../htmlLanguageTypes");
var htmlScanner_1 = require("../parser/htmlScanner");
var fact_1 = require("../languageFacts/fact");
function limitRanges(ranges, rangeLimit) {
ranges = ranges.sort(function (r1, r2) {
var diff = r1.startLine - r2.startLine;
if (diff === 0) {
diff = r1.endLine - r2.endLine;
}
return diff;
});
// compute each range's nesting level in 'nestingLevels'.
// count the number of ranges for each level in 'nestingLevelCounts'
var top = void 0;
var previous = [];
var nestingLevels = [];
var nestingLevelCounts = [];
var setNestingLevel = function (index, level) {
nestingLevels[index] = level;
if (level < 30) {
nestingLevelCounts[level] = (nestingLevelCounts[level] || 0) + 1;
}
};
// compute nesting levels and sanitize
for (var i = 0; i < ranges.length; i++) {
var entry = ranges[i];
if (!top) {
top = entry;
setNestingLevel(i, 0);
}
else {
if (entry.startLine > top.startLine) {
if (entry.endLine <= top.endLine) {
previous.push(top);
top = entry;
setNestingLevel(i, previous.length);
}
else if (entry.startLine > top.endLine) {
do {
top = previous.pop();
} while (top && entry.startLine > top.endLine);
if (top) {
previous.push(top);
}
top = entry;
setNestingLevel(i, previous.length);
}
}
}
}
var entries = 0;
var maxLevel = 0;
for (var i = 0; i < nestingLevelCounts.length; i++) {
var n = nestingLevelCounts[i];
if (n) {
if (n + entries > rangeLimit) {
maxLevel = i;
break;
}
entries += n;
}
}
var result = [];
for (var i = 0; i < ranges.length; i++) {
var level = nestingLevels[i];
if (typeof level === 'number') {
if (level < maxLevel || (level === maxLevel && entries++ < rangeLimit)) {
result.push(ranges[i]);
}
}
}
return result;
}
function getFoldingRanges(document, context) {
var scanner = htmlScanner_1.createScanner(document.getText());
var token = scanner.scan();
var ranges = [];
var stack = [];
var lastTagName = null;
var prevStart = -1;
function addRange(range) {
ranges.push(range);
prevStart = range.startLine;
}
while (token !== htmlLanguageTypes_1.TokenType.EOS) {
switch (token) {
case htmlLanguageTypes_1.TokenType.StartTag: {
var tagName = scanner.getTokenText();
var startLine = document.positionAt(scanner.getTokenOffset()).line;
stack.push({ startLine: startLine, tagName: tagName });
lastTagName = tagName;
break;
}
case htmlLanguageTypes_1.TokenType.EndTag: {
lastTagName = scanner.getTokenText();
break;
}
case htmlLanguageTypes_1.TokenType.StartTagClose:
if (!lastTagName || !fact_1.isVoidElement(lastTagName)) {
break;
}
// fallthrough
case htmlLanguageTypes_1.TokenType.EndTagClose:
case htmlLanguageTypes_1.TokenType.StartTagSelfClose: {
var i = stack.length - 1;
while (i >= 0 && stack[i].tagName !== lastTagName) {
i--;
}
if (i >= 0) {
var stackElement = stack[i];
stack.length = i;
var line = document.positionAt(scanner.getTokenOffset()).line;
var startLine = stackElement.startLine;
var endLine = line - 1;
if (endLine > startLine && prevStart !== startLine) {
addRange({ startLine: startLine, endLine: endLine });
}
}
break;
}
case htmlLanguageTypes_1.TokenType.Comment: {
var startLine = document.positionAt(scanner.getTokenOffset()).line;
var text = scanner.getTokenText();
var m = text.match(/^\s*#(region\b)|(endregion\b)/);
if (m) {
if (m[1]) { // start pattern match
stack.push({ startLine: startLine, tagName: '' }); // empty tagName marks region
}
else {
var i = stack.length - 1;
while (i >= 0 && stack[i].tagName.length) {
i--;
}
if (i >= 0) {
var stackElement = stack[i];
stack.length = i;
var endLine = startLine;
startLine = stackElement.startLine;
if (endLine > startLine && prevStart !== startLine) {
addRange({ startLine: startLine, endLine: endLine, kind: vscode_languageserver_types_1.FoldingRangeKind.Region });
}
}
}
}
else {
var endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
if (startLine < endLine) {
addRange({ startLine: startLine, endLine: endLine, kind: vscode_languageserver_types_1.FoldingRangeKind.Comment });
}
}
break;
}
}
token = scanner.scan();
}
var rangeLimit = context && context.rangeLimit || Number.MAX_VALUE;
if (ranges.length > rangeLimit) {
return limitRanges(ranges, rangeLimit);
}
return ranges;
}
exports.getFoldingRanges = getFoldingRanges;
});