提交 33a92766 编写于 作者: M Martin Aeschlimann

[folding] avoid regions array

上级 352db6cc
......@@ -24,7 +24,7 @@ import { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mou
import { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel';
import { IRange } from 'vs/editor/common/core/range';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { computeRanges as computeIndentRanges } from 'vs/editor/contrib/folding/common/indentRangeProvider';
import { computeRanges as computeIndentRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
export const ID = 'editor.contrib.folding';
......
......@@ -5,7 +5,7 @@
import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { FoldingRegion, IDecorationProvider } from 'vs/editor/contrib/folding/foldingModel';
import { IDecorationProvider } from 'vs/editor/contrib/folding/foldingModel';
export class FoldingDecorationProvider implements IDecorationProvider {
......@@ -27,8 +27,8 @@ export class FoldingDecorationProvider implements IDecorationProvider {
public autoHideFoldingControls: boolean = true;
getDecorationOption(region: FoldingRegion): ModelDecorationOptions {
if (region.isCollapsed) {
getDecorationOption(isCollapsed: boolean): ModelDecorationOptions {
if (isCollapsed) {
return this.COLLAPSED_VISUAL_DECORATION;
} else if (this.autoHideFoldingControls) {
return this.EXPANDED_AUTO_HIDE_VISUAL_DECORATION;
......
......@@ -8,7 +8,7 @@ import Event, { Emitter } from 'vs/base/common/event';
import { FoldingRanges, ILineRange } from './foldingRanges';
export interface IDecorationProvider {
getDecorationOption(region: FoldingRegion): IModelDecorationOptions;
getDecorationOption(isCollapsed: boolean): IModelDecorationOptions;
}
export interface FoldingModelChangeEvent {
......@@ -22,18 +22,19 @@ export class FoldingModel {
private _textModel: IModel;
private _decorationProvider: IDecorationProvider;
private _regions: FoldingRegion[] = [];
private _ranges: FoldingRanges;
private _editorDecorationIds: string[];
private _updateEventEmitter = new Emitter<FoldingModelChangeEvent>();
public get regions(): FoldingRegion[] { return this._regions; }
public get ranges(): FoldingRanges { return this._ranges; }
public get onDidChange(): Event<FoldingModelChangeEvent> { return this._updateEventEmitter.event; }
public get textModel() { return this._textModel; }
constructor(textModel: IModel, decorationProvider: IDecorationProvider) {
this._textModel = textModel;
this._decorationProvider = decorationProvider;
this._ranges = new FoldingRanges(new Uint32Array(0), new Uint32Array(0));
}
public toggleCollapseState(regions: FoldingRegion[]) {
......@@ -43,10 +44,13 @@ export class FoldingModel {
let processed = {};
this._textModel.changeDecorations(accessor => {
for (let region of regions) {
if (region.editorDecorationId && !processed[region.editorDecorationId]) {
processed[region.editorDecorationId] = true;
region.isCollapsed = !region.isCollapsed;
accessor.changeDecorationOptions(region.editorDecorationId, this._decorationProvider.getDecorationOption(region));
let index = region.regionIndex;
let editorDecorationId = this._editorDecorationIds[index];
if (editorDecorationId && !processed[editorDecorationId]) {
processed[editorDecorationId] = true;
let newCollapseState = !this._ranges.isCollapsed(index);
this._ranges.setCollapsed(index, newCollapseState);
accessor.changeDecorationOptions(editorDecorationId, this._decorationProvider.getDecorationOption(newCollapseState));
}
}
});
......@@ -54,32 +58,11 @@ export class FoldingModel {
}
public update(newRanges: FoldingRanges): void {
let editorDecorationIds = [];
let newEditorDecorations = [];
// remember the latest start line numbers of the collapsed regions
let collapsedStartLineNumbers: number[] = [];
for (let region of this._regions) {
if (region.editorDecorationId) {
if (region.isCollapsed) {
let decRange = this._textModel.getDecorationRange(region.editorDecorationId);
if (decRange) {
collapsedStartLineNumbers.push(decRange.startLineNumber);
}
}
editorDecorationIds.push(region.editorDecorationId);
}
}
let recycleBin = this._regions;
let newRegions = [];
let newRegion = (ranges: FoldingRanges, index: number, isCollapsed: boolean) => {
let region = recycleBin.length ? recycleBin.pop() : new FoldingRegion();
region.init(ranges, index, isCollapsed);
newRegions.push(region);
let startLineNumber = region.startLineNumber;
let initRange = (index: number, isCollapsed: boolean) => {
newRanges.setCollapsed(index, isCollapsed);
let startLineNumber = newRanges.getStartLineNumber(index);
let maxColumn = this._textModel.getLineMaxColumn(startLineNumber);
let decorationRange = {
startLineNumber: startLineNumber,
......@@ -87,38 +70,46 @@ export class FoldingModel {
endLineNumber: startLineNumber,
endColumn: maxColumn
};
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(region) });
newEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed) });
};
let k = 0, i = 0;
while (i < collapsedStartLineNumbers.length && k < newRanges.length) {
let collapsedStartLineNumber = collapsedStartLineNumbers[i];
while (k < newRanges.length && collapsedStartLineNumber > newRanges.getStartLineNumber(k)) {
newRegion(newRanges, k, false);
k++;
let i = 0;
let nextCollapsed = () => {
while (i < this._ranges.length) {
let isCollapsed = this._ranges.isCollapsed(i);
i++;
if (isCollapsed) {
return i - 1;
}
}
if (k < newRanges.length) {
let currStartLineNumber = newRanges.getStartLineNumber(k);
if (collapsedStartLineNumber < currStartLineNumber) {
i++;
} else if (collapsedStartLineNumber === currStartLineNumber) {
newRegion(newRanges, k, true);
i++;
k++;
return -1;
};
let k = 0;
let collapsedIndex = nextCollapsed();
while (collapsedIndex !== -1 && k < newRanges.length) {
// get the latest range
let decRange = this._textModel.getDecorationRange(this._editorDecorationIds[collapsedIndex]);
if (decRange) {
let collapsedStartLineNumber = decRange.startLineNumber;
while (k < newRanges.length) {
let startLineNumber = newRanges.getStartLineNumber(k);
if (collapsedStartLineNumber >= startLineNumber) {
initRange(k, collapsedStartLineNumber === startLineNumber);
k++;
} else {
break;
}
}
}
collapsedIndex = nextCollapsed();
}
while (k < newRanges.length) {
newRegion(newRanges, k, false);
initRange(k, false);
k++;
}
let newEditorDecorationIds = this._textModel.deltaDecorations(editorDecorationIds, newEditorDecorations);
for (let i = 0; i < newEditorDecorations.length; i++) {
newRegions[i].editorDecorationId = newEditorDecorationIds[i];
}
this._regions = newRegions;
this._editorDecorationIds = this._textModel.deltaDecorations(this._editorDecorationIds, newEditorDecorations);
this._ranges = newRanges;
this._updateEventEmitter.fire({ model: this });
}
......@@ -128,12 +119,12 @@ export class FoldingModel {
*/
public getMemento(): CollapseMemento {
let collapsedRanges: ILineRange[] = [];
for (let region of this._regions) {
if (region.isCollapsed && region.editorDecorationId) {
let range = this._textModel.getDecorationRange(region.editorDecorationId);
for (let i = 0; i < this._ranges.length; i++) {
if (this._ranges.isCollapsed(i)) {
let range = this._textModel.getDecorationRange(this._editorDecorationIds[i]);
if (range) {
let startLineNumber = range.startLineNumber;
let endLineNumber = range.endLineNumber + region.endLineNumber - region.startLineNumber;
let endLineNumber = range.endLineNumber + this._ranges.getEndLineNumber(i) - this._ranges.getStartLineNumber(i);
collapsedRanges.push({ startLineNumber, endLineNumber });
}
}
......@@ -162,13 +153,7 @@ export class FoldingModel {
}
public dispose() {
let editorDecorationIds = [];
for (let region of this._regions) {
if (region.editorDecorationId) {
editorDecorationIds.push(region.editorDecorationId);
}
}
this._textModel.deltaDecorations(editorDecorationIds, []);
this._textModel.deltaDecorations(this._editorDecorationIds, []);
}
getAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] {
......@@ -177,7 +162,7 @@ export class FoldingModel {
let index = this._ranges.findRange(lineNumber);
let level = 1;
while (index >= 0) {
let current = this._regions[index];
let current = new FoldingRegion(this._ranges, index);
if (!filter || filter(current, level)) {
result.push(current);
}
......@@ -192,7 +177,7 @@ export class FoldingModel {
if (this._ranges) {
let index = this._ranges.findRange(lineNumber);
if (index >= 0) {
return this._regions[index];
return new FoldingRegion(this._ranges, index);
}
}
return null;
......@@ -205,7 +190,7 @@ export class FoldingModel {
let index = region ? region.regionIndex + 1 : 0;
let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;
for (let i = index, len = this._ranges.length; i < len; i++) {
let current = this.regions[i];
let current = new FoldingRegion(this._ranges, i);
if (this._ranges.getStartLineNumber(i) < endLineNumber) {
if (trackLevel) {
while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {
......@@ -229,27 +214,15 @@ export class FoldingModel {
export class FoldingRegion {
public editorDecorationId: string;
public isCollapsed: boolean;
private index: number;
private indentRanges: FoldingRanges;
constructor() {
}
public init(indentRanges: FoldingRanges, index: number, isCollapsed: boolean): void {
this.indentRanges = indentRanges;
this.index = index;
this.isCollapsed = isCollapsed;
this.editorDecorationId = void 0;
constructor(private ranges: FoldingRanges, private index: number) {
}
public get startLineNumber() {
return this.indentRanges.getStartLineNumber(this.index);
return this.ranges.getStartLineNumber(this.index);
}
public get endLineNumber() {
return this.indentRanges.getEndLineNumber(this.index);
return this.ranges.getEndLineNumber(this.index);
}
public get regionIndex() {
......@@ -257,18 +230,13 @@ export class FoldingRegion {
}
public get parentIndex() {
return this.indentRanges.getParentIndex(this.index);
return this.ranges.getParentIndex(this.index);
}
isAfterLine(lineNumber: number): boolean {
return lineNumber < this.startLineNumber;
}
isBeforeLine(lineNumber: number): boolean {
return lineNumber > this.endLineNumber;
}
contains(range: ILineRange): boolean {
return this.startLineNumber <= range.startLineNumber && this.endLineNumber >= range.endLineNumber;
public get isCollapsed() {
return this.ranges.isCollapsed(this.index);
}
containedBy(range: ILineRange): boolean {
return range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber;
}
......@@ -330,7 +298,7 @@ export function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse:
* @param blockedLineNumbers
*/
export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: number, doCollapse: boolean, blockedLineNumbers: number[]): void {
let filter = (region, level) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line));
let filter = (region: FoldingRegion, level: number) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line));
let toToggle = foldingModel.getRegionsInside(null, filter);
foldingModel.toggleCollapseState(toToggle);
}
\ No newline at end of file
......@@ -18,6 +18,7 @@ const MASK_INDENT = 0xFF000000;
export class FoldingRanges {
private _startIndexes: Uint32Array;
private _endIndexes: Uint32Array;
private _collapseStates: Uint32Array;
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array) {
if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {
......@@ -25,6 +26,7 @@ export class FoldingRanges {
}
this._startIndexes = startIndexes;
this._endIndexes = endIndexes;
this._collapseStates = new Uint32Array(Math.ceil(startIndexes.length / 32));
this._computeParentIndices();
}
......@@ -62,6 +64,23 @@ export class FoldingRanges {
return this._endIndexes[index] & MAX_LINE_NUMBER;
}
public isCollapsed(index: number): boolean {
let arrayIndex = (index / 32) | 0;
let bit = index % 32;
return (this._collapseStates[arrayIndex] & (1 << bit)) !== 0;
}
public setCollapsed(index: number, newState: boolean) {
let arrayIndex = (index / 32) | 0;
let bit = index % 32;
let value = this._collapseStates[arrayIndex];
if (newState) {
this._collapseStates[arrayIndex] = value | (1 << bit);
} else {
this._collapseStates[arrayIndex] = value & ~(1 << bit);
}
}
public getParentIndex(index: number) {
let parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16);
if (parent === MAX_FOLDING_REGIONS) {
......@@ -74,25 +93,6 @@ export class FoldingRanges {
return this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line;
}
isAfterLine(index: number, lineNumber: number): boolean {
return lineNumber < this.getStartLineNumber(index);
}
isBeforeLine(index: number, lineNumber: number): boolean {
return lineNumber > this.getEndLineNumber(index);
}
containsRange(index: number, range: ILineRange): boolean {
return this.getStartLineNumber(index) <= range.startLineNumber && this.getEndLineNumber(index) >= range.endLineNumber;
}
containedBy(index: number, range: ILineRange): boolean {
return range.startLineNumber <= this.getStartLineNumber(index) && range.endLineNumber >= this.getEndLineNumber(index);
}
containsLine(index: number, lineNumber: number) {
return this.getStartLineNumber(index) <= lineNumber && lineNumber <= this.getEndLineNumber(index);
}
hidesLine(index: number, lineNumber: number) {
return this.getStartLineNumber(index) < lineNumber && lineNumber <= this.getEndLineNumber(index);
}
private findIndex(line: number) {
let low = 0, high = this._startIndexes.length;
if (high === 0) {
......
......@@ -5,7 +5,7 @@
import Event, { Emitter } from 'vs/base/common/event';
import { Range, IRange } from 'vs/editor/common/core/range';
import { FoldingRegion, FoldingModel, CollapseMemento } from 'vs/editor/contrib/folding/foldingModel';
import { FoldingModel, CollapseMemento } from 'vs/editor/contrib/folding/foldingModel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Selection } from 'vs/editor/common/core/selection';
import { findFirst } from 'vs/base/common/arrays';
......@@ -22,7 +22,7 @@ export class HiddenRangeModel {
public constructor(model: FoldingModel) {
this._foldingModel = model;
this._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges());
if (model.regions.length) {
if (model.ranges.length) {
this.updateHiddenRanges();
}
}
......@@ -31,27 +31,36 @@ export class HiddenRangeModel {
let updateHiddenAreas = false;
let newHiddenAreas: IRange[] = [];
let i = 0; // index into hidden
let k = 0;
let lastCollapsed: FoldingRegion = null;
let lastCollapsedStart = Number.MAX_VALUE;
let lastCollapsedEnd = -1;
let regions = this._foldingModel.regions;
for (let region of regions) {
if (!region.isCollapsed || lastCollapsed && lastCollapsed.contains(region)) {
let ranges = this._foldingModel.ranges;
for (; i < ranges.length; i++) {
if (!ranges.isCollapsed(i)) {
continue;
}
let startLineNumber = ranges.getStartLineNumber(i) + 1; // the first line is not hidden
let endLineNumber = ranges.getEndLineNumber(i);
if (lastCollapsedStart <= startLineNumber && endLineNumber <= lastCollapsedEnd) {
// ignore ranges contained in collapsed regions
continue;
}
lastCollapsed = region;
let range = region;
if (!updateHiddenAreas && i < this._hiddenRanges.length && matchesHiddenRange(this._hiddenRanges[i], range)) {
newHiddenAreas.push(this._hiddenRanges[i]);
i++;
if (!updateHiddenAreas && k < this._hiddenRanges.length && this._hiddenRanges[k].startLineNumber === startLineNumber && this._hiddenRanges[k].endLineNumber === endLineNumber) {
// reuse the old ranges
newHiddenAreas.push(this._hiddenRanges[k]);
k++;
} else {
updateHiddenAreas = true;
newHiddenAreas.push(new Range(range.startLineNumber + 1, 1, range.endLineNumber, 1));
newHiddenAreas.push(new Range(startLineNumber, 1, endLineNumber, 1));
}
lastCollapsedStart = startLineNumber;
lastCollapsedEnd = endLineNumber;
}
if (updateHiddenAreas || i < this._hiddenRanges.length) {
if (updateHiddenAreas || k < this._hiddenRanges.length) {
this.applyHiddenRanges(newHiddenAreas);
}
}
......@@ -128,9 +137,6 @@ export class HiddenRangeModel {
}
}
function matchesHiddenRange(hr: IRange, range: FoldingRegion) {
return hr.startLineNumber === range.startLineNumber + 1 && hr.endLineNumber === range.endLineNumber;
}
function isInside(line: number, range: IRange) {
return line >= range.startLineNumber && line <= range.endLineNumber;
}
......
......@@ -8,7 +8,7 @@
import { ITextModel } from 'vs/editor/common/editorCommon';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
import { computeIndentLevel } from 'vs/editor/common/model/modelLine';
import { FoldingRanges, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/common/foldingRanges';
import { FoldingRanges, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/foldingRanges';
const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000;
......
......@@ -7,7 +7,7 @@
import * as assert from 'assert';
import { FoldingModel, FoldingRegion, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/foldingModel';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges } from 'vs/editor/contrib/folding/common/indentRangeProvider';
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
import { TrackedRangeStickiness } from 'vs/editor/common/editorCommon';
import { EditOperation } from 'vs/editor/common/core/editOperation';
......@@ -27,7 +27,7 @@ export class TestDecorationProvider {
linesDecorationsClassName: 'folding'
});
getDecorationOption(region: FoldingRegion): ModelDecorationOptions {
getDecorationOption(isCollapsed: boolean): ModelDecorationOptions {
return this.testDecorator;
}
}
......@@ -46,8 +46,24 @@ suite('Folding Model', () => {
}
}
function assertFoldedRegions(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
assert.deepEqual(foldingModel.regions.filter(r => r.isCollapsed).map(r => ({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, isCollapsed: false })), expectedRegions, message);
function assertFoldedRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
let actualRanges = [];
let actual = foldingModel.ranges;
for (let i = 0; i < actual.length; i++) {
if (actual.isCollapsed(i)) {
actualRanges.push(r(actual.getStartLineNumber(i), actual.getEndLineNumber(i)));
}
}
assert.deepEqual(actualRanges, expectedRegions, message);
}
function assertRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
let actualRanges = [];
let actual = foldingModel.ranges;
for (let i = 0; i < actual.length; i++) {
actualRanges.push(r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.isCollapsed(i)));
}
assert.deepEqual(actualRanges, expectedRegions, message);
}
function assertRegions(actual: FoldingRegion[], expectedRegions: ExpectedRegion[], message?: string) {
......@@ -76,7 +92,7 @@ suite('Folding Model', () => {
let r2 = r(4, 7, false);
let r3 = r(5, 6, false);
assertRegions(foldingModel.regions, [r1, r2, r3]);
assertRanges(foldingModel, [r1, r2, r3]);
assertRegion(foldingModel.getRegionAtLine(1), r1, '1');
assertRegion(foldingModel.getRegionAtLine(2), r1, '2');
......@@ -115,22 +131,22 @@ suite('Folding Model', () => {
let r2 = r(4, 7, false);
let r3 = r(5, 6, false);
assertRegions(foldingModel.regions, [r1, r2, r3]);
assertRanges(foldingModel, [r1, r2, r3]);
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)]);
foldingModel.update(ranges);
assertRegions(foldingModel.regions, [r(1, 3, true), r2, r3]);
assertRanges(foldingModel, [r(1, 3, true), r2, r3]);
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)]);
foldingModel.update(ranges);
assertRegions(foldingModel.regions, [r(1, 3, true), r2, r(5, 6, true)]);
assertRanges(foldingModel, [r(1, 3, true), r2, r(5, 6, true)]);
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)]);
foldingModel.update(ranges);
assertRegions(foldingModel.regions, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]);
assertRanges(foldingModel, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]);
textModel.dispose();
} finally {
......@@ -161,14 +177,14 @@ suite('Folding Model', () => {
let r2 = r(4, 7, false);
let r3 = r(5, 6, false);
assertRegions(foldingModel.regions, [r1, r2, r3]);
assertRanges(foldingModel, [r1, r2, r3]);
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2), foldingModel.getRegionAtLine(5)]);
textModel.applyEdits([EditOperation.insert(new Position(4, 1), '//hello\n')]);
foldingModel.update(computeRanges(textModel, false, null));
assertRegions(foldingModel.regions, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]);
assertRanges(foldingModel, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]);
} finally {
textModel.dispose();
}
......@@ -196,7 +212,7 @@ suite('Folding Model', () => {
let r2 = r(4, 7, false);
let r3 = r(5, 6, false);
assertRegions(foldingModel.regions, [r1, r2, r3]);
assertRanges(foldingModel, [r1, r2, r3]);
let region1 = foldingModel.getRegionAtLine(r1.startLineNumber);
let region2 = foldingModel.getRegionAtLine(r2.startLineNumber);
let region3 = foldingModel.getRegionAtLine(r3.startLineNumber);
......@@ -244,7 +260,7 @@ suite('Folding Model', () => {
let region2 = foldingModel.getRegionAtLine(r2.startLineNumber);
let region3 = foldingModel.getRegionAtLine(r3.startLineNumber);
assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]);
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 1), [r1, r2], '1');
assertRegions(foldingModel.getRegionsInside(null, (r, level) => level === 2), [r3], '2');
......@@ -289,7 +305,7 @@ suite('Folding Model', () => {
let r3 = r(3, 7, false);
let r4 = r(4, 5, false);
assertRegions(foldingModel.regions, [r1, r2, r3, r4]);
assertRanges(foldingModel, [r1, r2, r3, r4]);
assertRegions(foldingModel.getAllRegionsAtLine(1), [r1], '1');
assertRegions(foldingModel.getAllRegionsAtLine(2), [r1, r2].reverse(), '2');
......@@ -335,25 +351,25 @@ suite('Folding Model', () => {
let r3 = r(4, 11, false);
let r4 = r(5, 6, false);
let r5 = r(9, 10, false);
assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]);
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [4]);
assertFoldedRegions(foldingModel, [r3, r4, r5], '1');
assertFoldedRanges(foldingModel, [r3, r4, r5], '1');
setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [8]);
assertFoldedRegions(foldingModel, [], '2');
assertFoldedRanges(foldingModel, [], '2');
setCollapseStateLevelsDown(foldingModel, true, Number.MAX_VALUE, [12]);
assertFoldedRegions(foldingModel, [r2, r3, r4, r5], '1');
assertFoldedRanges(foldingModel, [r2, r3, r4, r5], '1');
setCollapseStateLevelsDown(foldingModel, false, Number.MAX_VALUE, [7]);
assertFoldedRegions(foldingModel, [r2], '1');
assertFoldedRanges(foldingModel, [r2], '1');
setCollapseStateLevelsDown(foldingModel, false);
assertFoldedRegions(foldingModel, [], '1');
assertFoldedRanges(foldingModel, [], '1');
setCollapseStateLevelsDown(foldingModel, true);
assertFoldedRegions(foldingModel, [r1, r2, r3, r4, r5], '1');
assertFoldedRanges(foldingModel, [r1, r2, r3, r4, r5], '1');
} finally {
textModel.dispose();
}
......@@ -388,25 +404,25 @@ suite('Folding Model', () => {
let r3 = r(4, 11, false);
let r4 = r(5, 6, false);
let r5 = r(9, 10, false);
assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]);
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
setCollapseStateAtLevel(foldingModel, 1, true, []);
assertFoldedRegions(foldingModel, [r1, r2], '1');
assertFoldedRanges(foldingModel, [r1, r2], '1');
setCollapseStateAtLevel(foldingModel, 1, false, [5]);
assertFoldedRegions(foldingModel, [r2], '1');
assertFoldedRanges(foldingModel, [r2], '1');
setCollapseStateAtLevel(foldingModel, 1, false, [1]);
assertFoldedRegions(foldingModel, [], '1');
assertFoldedRanges(foldingModel, [], '1');
setCollapseStateAtLevel(foldingModel, 2, true, []);
assertFoldedRegions(foldingModel, [r3], '1');
assertFoldedRanges(foldingModel, [r3], '1');
setCollapseStateAtLevel(foldingModel, 3, true, [4, 9]);
assertFoldedRegions(foldingModel, [r3, r4], '1');
assertFoldedRanges(foldingModel, [r3, r4], '1');
setCollapseStateAtLevel(foldingModel, 3, false, [4, 9]);
assertFoldedRegions(foldingModel, [r3], '1');
assertFoldedRanges(foldingModel, [r3], '1');
} finally {
textModel.dispose();
}
......@@ -440,25 +456,25 @@ suite('Folding Model', () => {
let r3 = r(4, 11, false);
let r4 = r(5, 6, false);
let r5 = r(9, 10, false);
assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]);
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
setCollapseStateLevelsDown(foldingModel, true, 1, [4]);
assertFoldedRegions(foldingModel, [r3], '1');
assertFoldedRanges(foldingModel, [r3], '1');
setCollapseStateLevelsDown(foldingModel, true, 2, [4]);
assertFoldedRegions(foldingModel, [r3, r4, r5], '2');
assertFoldedRanges(foldingModel, [r3, r4, r5], '2');
setCollapseStateLevelsDown(foldingModel, false, 2, [3]);
assertFoldedRegions(foldingModel, [r4, r5], '3');
assertFoldedRanges(foldingModel, [r4, r5], '3');
setCollapseStateLevelsDown(foldingModel, false, 2, [2]);
assertFoldedRegions(foldingModel, [r4, r5], '4');
assertFoldedRanges(foldingModel, [r4, r5], '4');
setCollapseStateLevelsDown(foldingModel, true, 4, [2]);
assertFoldedRegions(foldingModel, [r1, r4, r5], '5');
assertFoldedRanges(foldingModel, [r1, r4, r5], '5');
setCollapseStateLevelsDown(foldingModel, false, 4, [2, 3]);
assertFoldedRegions(foldingModel, [], '6');
assertFoldedRanges(foldingModel, [], '6');
} finally {
textModel.dispose();
}
......@@ -492,19 +508,19 @@ suite('Folding Model', () => {
let r3 = r(4, 11, false);
let r4 = r(5, 6, false);
let r5 = r(9, 10, false);
assertRegions(foldingModel.regions, [r1, r2, r3, r4, r5]);
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
setCollapseStateLevelsUp(foldingModel, true, 1, [4]);
assertFoldedRegions(foldingModel, [r3], '1');
assertFoldedRanges(foldingModel, [r3], '1');
setCollapseStateLevelsUp(foldingModel, true, 2, [4]);
assertFoldedRegions(foldingModel, [r2, r3], '2');
assertFoldedRanges(foldingModel, [r2, r3], '2');
setCollapseStateLevelsUp(foldingModel, false, 4, [1, 3, 4]);
assertFoldedRegions(foldingModel, [], '3');
assertFoldedRanges(foldingModel, [], '3');
setCollapseStateLevelsUp(foldingModel, true, 2, [10]);
assertFoldedRegions(foldingModel, [r3, r5], '4');
assertFoldedRanges(foldingModel, [r3, r5], '4');
} finally {
textModel.dispose();
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
import { MAX_FOLDING_REGIONS } from 'vs/editor/contrib/folding/foldingRanges';
let markers: FoldingMarkers = {
start: /^\s*#region\b/,
end: /^\s*#endregion\b/
};
suite('FoldingRanges', () => {
test('test max folding regions', () => {
let lines = [];
let nRegions = MAX_FOLDING_REGIONS;
for (let i = 0; i < nRegions; i++) {
lines.push('#region');
}
for (let i = 0; i < nRegions; i++) {
lines.push('#endregion');
}
let model = Model.createFromString(lines.join('\n'));
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);
assert.equal(actual.getEndLineNumber(i), nRegions * 2 - i, 'end' + i);
assert.equal(actual.getParentIndex(i), i - 1, 'parent' + i);
}
});
test('findRange', () => {
let lines = [
/* 1*/ '#region',
/* 2*/ '#endregion',
/* 3*/ 'class A {',
/* 4*/ ' void foo() {',
/* 5*/ ' if (true) {',
/* 6*/ ' return;',
/* 7*/ ' }',
/* 8*/ '',
/* 9*/ ' if (true) {',
/* 10*/ ' return;',
/* 11*/ ' }',
/* 12*/ ' }',
/* 13*/ '}'];
let textModel = Model.createFromString(lines.join('\n'));
try {
let actual = computeRanges(textModel, false, markers);
// let r0 = r(1, 2);
// let r1 = r(3, 12);
// let r2 = r(4, 11);
// let r3 = r(5, 6);
// let r4 = r(9, 10);
assert.equal(actual.findRange(1), 0, '1');
assert.equal(actual.findRange(2), 0, '2');
assert.equal(actual.findRange(3), 1, '3');
assert.equal(actual.findRange(4), 2, '4');
assert.equal(actual.findRange(5), 3, '5');
assert.equal(actual.findRange(6), 3, '6');
assert.equal(actual.findRange(7), 2, '7');
assert.equal(actual.findRange(8), 2, '8');
assert.equal(actual.findRange(9), 4, '9');
assert.equal(actual.findRange(10), 4, '10');
assert.equal(actual.findRange(11), 2, '11');
assert.equal(actual.findRange(12), 1, '12');
assert.equal(actual.findRange(13), -1, '13');
} finally {
textModel.dispose();
}
});
test('setCollapsed', () => {
let lines = [];
let nRegions = 500;
for (let i = 0; i < nRegions; i++) {
lines.push('#region');
}
for (let i = 0; i < nRegions; i++) {
lines.push('#endregion');
}
let model = Model.createFromString(lines.join('\n'));
let actual = computeRanges(model, false, markers, MAX_FOLDING_REGIONS);
assert.equal(actual.length, nRegions, 'len');
for (let i = 0; i < nRegions; i++) {
actual.setCollapsed(i, i % 3 === 0);
}
for (let i = 0; i < nRegions; i++) {
assert.equal(actual.isCollapsed(i), i % 3 === 0, 'line' + i);
}
});
});
\ No newline at end of file
......@@ -7,7 +7,7 @@
import * as assert from 'assert';
import { FoldingModel } from 'vs/editor/contrib/folding/foldingModel';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges } from 'vs/editor/contrib/folding/common/indentRangeProvider';
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
import { TestDecorationProvider } from './foldingModel.test';
import { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel';
import { IRange } from 'vs/editor/common/core/range';
......
......@@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import { computeRanges } from 'vs/editor/contrib/folding/common/indentRangeProvider';
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
import { Model } from 'vs/editor/common/model/model';
interface IndentRange {
......
......@@ -7,11 +7,10 @@
import * as assert from 'assert';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges } from 'vs/editor/contrib/folding/common/indentRangeProvider';
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
import { MAX_FOLDING_REGIONS } from 'vs/editor/contrib/folding/common/foldingRanges';
export interface ExpectedIndentRange {
interface ExpectedIndentRange {
startLineNumber: number;
endLineNumber: number;
parentIndex: number;
......@@ -320,69 +319,4 @@ suite('Folding with regions', () => {
], [], true, markers);
});
test('test max folding regions', () => {
let lines = [];
let nRegions = MAX_FOLDING_REGIONS;
for (let i = 0; i < nRegions; i++) {
lines.push('#region');
}
for (let i = 0; i < nRegions; i++) {
lines.push('#endregion');
}
let model = Model.createFromString(lines.join('\n'));
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);
assert.equal(actual.getEndLineNumber(i), nRegions * 2 - i, 'end' + i);
assert.equal(actual.getParentIndex(i), i - 1, 'parent' + i);
}
});
test('findRange', () => {
let lines = [
/* 1*/ '#region',
/* 2*/ '#endregion',
/* 3*/ 'class A {',
/* 4*/ ' void foo() {',
/* 5*/ ' if (true) {',
/* 6*/ ' return;',
/* 7*/ ' }',
/* 8*/ '',
/* 9*/ ' if (true) {',
/* 10*/ ' return;',
/* 11*/ ' }',
/* 12*/ ' }',
/* 13*/ '}'];
let textModel = Model.createFromString(lines.join('\n'));
try {
let actual = computeRanges(textModel, false, markers);
// let r0 = r(1, 2);
// let r1 = r(3, 12);
// let r2 = r(4, 11);
// let r3 = r(5, 6);
// let r4 = r(9, 10);
assert.equal(actual.findRange(1), 0, '1');
assert.equal(actual.findRange(2), 0, '2');
assert.equal(actual.findRange(3), 1, '3');
assert.equal(actual.findRange(4), 2, '4');
assert.equal(actual.findRange(5), 3, '5');
assert.equal(actual.findRange(6), 3, '6');
assert.equal(actual.findRange(7), 2, '7');
assert.equal(actual.findRange(8), 2, '8');
assert.equal(actual.findRange(9), 4, '9');
assert.equal(actual.findRange(10), 4, '10');
assert.equal(actual.findRange(11), 2, '11');
assert.equal(actual.findRange(12), 1, '12');
assert.equal(actual.findRange(13), -1, '13');
} finally {
textModel.dispose();
}
});
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册