123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { onUnexpectedExternalError } from '../../../base/common/errors.js';
- import { DisposableStore } from '../../../base/common/lifecycle.js';
- import { FoldingRegions, MAX_LINE_NUMBER } from './foldingRanges.js';
- const MAX_FOLDING_REGIONS = 5000;
- const foldingContext = {};
- export const ID_SYNTAX_PROVIDER = 'syntax';
- export class SyntaxRangeProvider {
- constructor(editorModel, providers, handleFoldingRangesChange, limit = MAX_FOLDING_REGIONS) {
- this.editorModel = editorModel;
- this.providers = providers;
- this.limit = limit;
- this.id = ID_SYNTAX_PROVIDER;
- for (const provider of providers) {
- if (typeof provider.onDidChange === 'function') {
- if (!this.disposables) {
- this.disposables = new DisposableStore();
- }
- this.disposables.add(provider.onDidChange(handleFoldingRangesChange));
- }
- }
- }
- compute(cancellationToken) {
- return collectSyntaxRanges(this.providers, this.editorModel, cancellationToken).then(ranges => {
- if (ranges) {
- let res = sanitizeRanges(ranges, this.limit);
- return res;
- }
- return null;
- });
- }
- dispose() {
- var _a;
- (_a = this.disposables) === null || _a === void 0 ? void 0 : _a.dispose();
- }
- }
- function collectSyntaxRanges(providers, model, cancellationToken) {
- let rangeData = null;
- let promises = providers.map((provider, i) => {
- return Promise.resolve(provider.provideFoldingRanges(model, foldingContext, cancellationToken)).then(ranges => {
- if (cancellationToken.isCancellationRequested) {
- return;
- }
- if (Array.isArray(ranges)) {
- if (!Array.isArray(rangeData)) {
- rangeData = [];
- }
- let nLines = model.getLineCount();
- for (let r of ranges) {
- if (r.start > 0 && r.end > r.start && r.end <= nLines) {
- rangeData.push({ start: r.start, end: r.end, rank: i, kind: r.kind });
- }
- }
- }
- }, onUnexpectedExternalError);
- });
- return Promise.all(promises).then(_ => {
- return rangeData;
- });
- }
- export class RangesCollector {
- constructor(foldingRangesLimit) {
- this._startIndexes = [];
- this._endIndexes = [];
- this._nestingLevels = [];
- this._nestingLevelCounts = [];
- this._types = [];
- this._length = 0;
- this._foldingRangesLimit = foldingRangesLimit;
- }
- add(startLineNumber, endLineNumber, type, nestingLevel) {
- if (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {
- return;
- }
- let index = this._length;
- this._startIndexes[index] = startLineNumber;
- this._endIndexes[index] = endLineNumber;
- this._nestingLevels[index] = nestingLevel;
- this._types[index] = type;
- this._length++;
- if (nestingLevel < 30) {
- this._nestingLevelCounts[nestingLevel] = (this._nestingLevelCounts[nestingLevel] || 0) + 1;
- }
- }
- toIndentRanges() {
- if (this._length <= this._foldingRangesLimit) {
- let startIndexes = new Uint32Array(this._length);
- let endIndexes = new Uint32Array(this._length);
- for (let i = 0; i < this._length; i++) {
- startIndexes[i] = this._startIndexes[i];
- endIndexes[i] = this._endIndexes[i];
- }
- return new FoldingRegions(startIndexes, endIndexes, this._types);
- }
- else {
- let entries = 0;
- let maxLevel = this._nestingLevelCounts.length;
- for (let i = 0; i < this._nestingLevelCounts.length; i++) {
- let n = this._nestingLevelCounts[i];
- if (n) {
- if (n + entries > this._foldingRangesLimit) {
- maxLevel = i;
- break;
- }
- entries += n;
- }
- }
- let startIndexes = new Uint32Array(this._foldingRangesLimit);
- let endIndexes = new Uint32Array(this._foldingRangesLimit);
- let types = [];
- for (let i = 0, k = 0; i < this._length; i++) {
- let level = this._nestingLevels[i];
- if (level < maxLevel || (level === maxLevel && entries++ < this._foldingRangesLimit)) {
- startIndexes[k] = this._startIndexes[i];
- endIndexes[k] = this._endIndexes[i];
- types[k] = this._types[i];
- k++;
- }
- }
- return new FoldingRegions(startIndexes, endIndexes, types);
- }
- }
- }
- export function sanitizeRanges(rangeData, limit) {
- let sorted = rangeData.sort((d1, d2) => {
- let diff = d1.start - d2.start;
- if (diff === 0) {
- diff = d1.rank - d2.rank;
- }
- return diff;
- });
- let collector = new RangesCollector(limit);
- let top = undefined;
- let previous = [];
- for (let entry of sorted) {
- if (!top) {
- top = entry;
- collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);
- }
- else {
- if (entry.start > top.start) {
- if (entry.end <= top.end) {
- previous.push(top);
- top = entry;
- collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);
- }
- else {
- if (entry.start > top.end) {
- do {
- top = previous.pop();
- } while (top && entry.start > top.end);
- if (top) {
- previous.push(top);
- }
- top = entry;
- }
- collector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);
- }
- }
- }
- }
- return collector.toIndentRanges();
- }
|