提交 40bd3533 编写于 作者: M Martin Aeschlimann

[folding] fix for max folding regions

上级 16c2b0ee
......@@ -19,16 +19,14 @@ export class IndentRanges {
private _startIndexes: Uint32Array;
private _endIndexes: Uint32Array;
private _model: ITextModel;
private _indentLimit: number;
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, model: ITextModel, indentLimit: number) {
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, model: ITextModel) {
if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {
throw new Error('invalid startIndexes or endIndexes size');
}
this._startIndexes = startIndexes;
this._endIndexes = endIndexes;
this._model = model;
this._indentLimit = indentLimit;
this._computeParentIndices();
}
......@@ -74,10 +72,6 @@ export class IndentRanges {
return parent;
}
public get indentLimit() {
return this._indentLimit;
}
public getIndent(index: number) {
const lineNumber = this.getStartLineNumber(index);
const tabSize = this._model.getOptions().tabSize;
......@@ -132,7 +126,7 @@ export class RangesCollector {
private _length: number;
private _foldingRegionsLimit: number;
constructor(foldingRegionsLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT) {
constructor(foldingRegionsLimit: number) {
this._startIndexes = [];
this._endIndexes = [];
this._indentOccurrences = [];
......@@ -153,41 +147,55 @@ export class RangesCollector {
}
}
private _computeMaxIndent() {
let maxEntries = this._foldingRegionsLimit;
let maxIndent = this._indentOccurrences.length;
for (let i = 0; i < this._indentOccurrences.length; i++) {
if (this._indentOccurrences[i]) {
maxEntries -= this._indentOccurrences[i];
if (maxEntries < 0) {
maxIndent = i;
break;
public toIndentRanges(model: ITextModel) {
if (this._length <= this._foldingRegionsLimit) {
// reverse and create arrays of the exact length
let startIndexes = new Uint32Array(this._length);
let endIndexes = new Uint32Array(this._length);
for (let i = this._length - 1, k = 0; i >= 0; i-- , k++) {
startIndexes[k] = this._startIndexes[i];
endIndexes[k] = this._endIndexes[i];
}
return new IndentRanges(startIndexes, endIndexes, model);
} else {
let entries = 0;
let maxIndent = this._indentOccurrences.length;
for (let i = 0; i < this._indentOccurrences.length; i++) {
let n = this._indentOccurrences[i];
if (n) {
if (n + entries > this._foldingRegionsLimit) {
maxIndent = i;
break;
}
entries += n;
}
}
const tabSize = model.getOptions().tabSize;
// reverse and create arrays of the exact length
let startIndexes = new Uint32Array(entries);
let endIndexes = new Uint32Array(entries);
for (let i = this._length - 1, k = 0; i >= 0; i--) {
let startIndex = this._startIndexes[i];
let lineContent = model.getLineContent(startIndex);
let indent = computeIndentLevel(lineContent, tabSize);
if (indent < maxIndent) {
startIndexes[k] = startIndex;
endIndexes[k] = this._endIndexes[i];
k++;
}
}
return new IndentRanges(startIndexes, endIndexes, model);
}
return maxIndent;
}
public toIndentRanges(model: ITextModel) {
// reverse and create arrays of the exact length
let startIndexes = new Uint32Array(this._length);
let endIndexes = new Uint32Array(this._length);
for (let i = this._length - 1, k = 0; i >= 0; i-- , k++) {
startIndexes[k] = this._startIndexes[i];
endIndexes[k] = this._endIndexes[i];
}
return new IndentRanges(startIndexes, endIndexes, model, this._computeMaxIndent());
}
}
interface PreviousRegion { indent: number; line: number; marker: boolean; };
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, minimumRangeSize: number = 1): IndentRanges {
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRegionsLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): IndentRanges {
const tabSize = model.getOptions().tabSize;
let result = new RangesCollector();
let result = new RangesCollector(foldingRegionsLimit);
let pattern = void 0;
if (markers) {
......@@ -244,7 +252,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol
// new folding range
let endLineNumber = previous.line - 1;
if (endLineNumber - line >= minimumRangeSize) {
if (endLineNumber - line >= 1) { // needs at east size 1
result.insertFirst(line, endLineNumber, indent);
}
}
......
......@@ -84,17 +84,15 @@ export class FoldingModel {
region.init(ranges, index, isCollapsed);
newRegions.push(region);
if (ranges.getIndent(index) < ranges.indentLimit) {
let startLineNumber = region.startLineNumber;
let maxColumn = this._textModel.getLineMaxColumn(startLineNumber);
let decorationRange = {
startLineNumber: startLineNumber,
startColumn: maxColumn,
endLineNumber: startLineNumber,
endColumn: maxColumn
};
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(region) });
}
let startLineNumber = region.startLineNumber;
let maxColumn = this._textModel.getLineMaxColumn(startLineNumber);
let decorationRange = {
startLineNumber: startLineNumber,
startColumn: maxColumn,
endLineNumber: startLineNumber,
endColumn: maxColumn
};
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(region) });
};
let k = 0, i = 0;
......
......@@ -5,42 +5,73 @@
'use strict';
import * as assert from 'assert';
import { RangesCollector } from 'vs/editor/common/model/indentRanges';
import { computeRanges } from 'vs/editor/common/model/indentRanges';
import { Model } from 'vs/editor/common/model/model';
interface IndentRange {
startLineNumber: number;
endLineNumber: number;
indent: number;
}
suite('Indentation Folding', () => {
function r(startLineNumber: number, endLineNumber: number, indent: number): IndentRange {
return { startLineNumber, endLineNumber, indent };
function r(startLineNumber: number, endLineNumber: number): IndentRange {
return { startLineNumber, endLineNumber };
}
test('Limit By indent', () => {
let input = [r(1, 4, 0), r(3, 4, 2), r(5, 8, 0), r(6, 7, 1), r(9, 15, 0), r(10, 15, 10), r(11, 12, 2000), r(14, 15, 2000)];
function assertLimit(maxEntries: number, expectedIndentLimit: number) {
let collector = new RangesCollector(maxEntries);
for (let i of input) {
collector.insertFirst(i.startLineNumber, i.endLineNumber, i.indent);
let lines = [
/* 1*/ 'A',
/* 2*/ ' A',
/* 3*/ ' A',
/* 4*/ ' A',
/* 5*/ ' A',
/* 6*/ ' A',
/* 7*/ ' A',
/* 8*/ ' A',
/* 9*/ ' A',
/* 10*/ ' A',
/* 11*/ ' A',
/* 12*/ ' A',
/* 13*/ ' A',
/* 14*/ ' A',
/* 15*/ 'A',
/* 16*/ ' A'
];
let r1 = r(1, 14);
let r2 = r(3, 11);
let r3 = r(4, 5);
let r4 = r(6, 11);
let r5 = r(8, 9);
let r6 = r(10, 11);
let r7 = r(12, 14);
let r8 = r(13, 14);
let r9 = r(15, 16);
let model = Model.createFromString(lines.join('\n'));
function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) {
let indentRanges = computeRanges(model, true, null, maxEntries);
assert.ok(indentRanges.length <= maxEntries, 'max ' + message);
assert.equal(indentRanges.length, expectedRanges.length, 'len ' + message);
for (let i = 0; i < expectedRanges.length; i++) {
assert.equal(indentRanges.getStartLineNumber(i), expectedRanges[i].startLineNumber, 'start ' + message);
assert.equal(indentRanges.getEndLineNumber(i), expectedRanges[i].endLineNumber, 'end ' + message);
}
let indentRanges = collector.toIndentRanges(null);
assert.equal(indentRanges.indentLimit, expectedIndentLimit);
assert.ok(input.filter(r => r.indent < expectedIndentLimit).length <= maxEntries);
}
assertLimit(8, 11);
assertLimit(7, 11);
assertLimit(6, 11);
assertLimit(5, 10);
assertLimit(4, 2);
assertLimit(3, 1);
assertLimit(2, 0);
assertLimit(1, 0);
assertLimit(0, 0);
assertLimit(1000, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '1');
assertLimit(9, [r1, r2, r3, r4, r5, r6, r7, r8, r9], '2');
assertLimit(8, [r1, r2, r3, r4, r5, r6, r7, r9], '3');
assertLimit(7, [r1, r2, r3, r4, r7, r9], '4');
assertLimit(6, [r1, r2, r3, r4, r7, r9], '5');
assertLimit(5, [r1, r2, r7, r9], '6');
assertLimit(4, [r1, r2, r7, r9], '7');
assertLimit(3, [r1, r9], '8');
assertLimit(2, [r1, r9], '9');
assertLimit(1, [], '10');
assertLimit(0, [], '11');
});
});
......@@ -330,7 +330,7 @@ suite('Folding with regions', () => {
lines.push('#endregion');
}
let model = Model.createFromString(lines.join('\n'));
let actual = computeRanges(model, false, markers);
let actual = computeRanges(model, false, markers, MAX_FOLDING_REGIONS);
assert.equal(actual.length, nRegions, 'len');
for (let i = 0; i < nRegions; i++) {
assert.equal(actual.getStartLineNumber(i), i + 1, 'start' + i);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册