Skip to content

Commit 776419c

Browse files
committed
[folding] fix restoring collapse state (for #36555)
1 parent 464f1a7 commit 776419c

File tree

3 files changed

+74
-28
lines changed

3 files changed

+74
-28
lines changed

src/vs/editor/contrib/folding/browser/folding.ts

+12-24
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { ICommonCodeEditor, ScrollType } from 'vs/editor/common/editorCommon';
1717
import { editorAction, ServicesAccessor, EditorAction, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions';
1818
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
1919
import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions';
20-
import { FoldingModel, FoldingRegion, setCollapseStateAtLevel, setCollapseStateRecursivly, fold, unfold } from 'vs/editor/contrib/folding/common/foldingModel';
20+
import { FoldingModel, setCollapseStateAtLevel, setCollapseStateRecursivly, fold, unfold, CollapseState } from 'vs/editor/contrib/folding/common/foldingModel';
2121
import { computeRanges, limitByIndent } from 'vs/editor/contrib/folding/common/indentFoldStrategy';
2222
import { FoldingDecorationProvider } from './foldingDecorations';
2323
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
@@ -99,47 +99,35 @@ export class FoldingController {
9999
/**
100100
* Store view state.
101101
*/
102-
public saveViewState(): any {
102+
public saveViewState(): { collapsedRegions?: CollapseState, lineCount?: number } {
103103
let model = this.editor.getModel();
104104
if (!model) {
105105
return {};
106106
}
107-
let collapsedIndexes: number[] = [];
108-
for (let region of this.foldingModel.regions) {
109-
if (region.isCollapsed && region.editorDecorationId) {
110-
var range = model.getDecorationRange(region.editorDecorationId);
111-
if (range) {
112-
collapsedIndexes.push(range.startLineNumber);
113-
}
114-
}
115-
}
116-
return { collapsedIndexes, lineCount: model.getLineCount() };
107+
return { collapsedRegions: this.foldingModel.getCollapseState(), lineCount: model.getLineCount() };
117108
}
118109

119110
/**
120111
* Restore view state.
121112
*/
122-
public restoreViewState(state: any): void {
113+
public restoreViewState(state: { collapsedRegions?: CollapseState, lineCount?: number }): void {
123114
let model = this.editor.getModel();
124115
if (!model) {
125116
return;
126117
}
127118
if (!this._isEnabled) {
128119
return;
129120
}
130-
if (!state || !Array.isArray(state.collapsedIndexes) || state.collapsedIndexes.length === 0 || state.lineCount !== model.getLineCount()) {
121+
if (!state || !state.collapsedRegions || state.lineCount !== model.getLineCount()) {
131122
return;
132123
}
133-
this.getFoldingModel().then(foldingModel => {
134-
let toToogle: FoldingRegion[] = [];
135-
for (let index of state.collapsedIndexes) {
136-
let region = foldingModel.getRegionAtLine(index);
137-
if (region && !region.isCollapsed) {
138-
toToogle.push(region);
139-
}
140-
}
141-
foldingModel.toggleCollapseState(toToogle);
142-
});
124+
125+
// set the hidden ranges right way, before waiting for the folding model.
126+
if (this.hiddenRangeModel.applyCollapseState(state.collapsedRegions)) {
127+
this.getFoldingModel().then(foldingModel => {
128+
foldingModel.applyCollapseState(state.collapsedRegions);
129+
});
130+
}
143131
}
144132

145133
private onModelChanged(): void {

src/vs/editor/contrib/folding/common/foldingModel.ts

+40
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export interface FoldingModelChangeEvent {
3232
collapseStateChanged?: FoldingRegion[];
3333
}
3434

35+
export type CollapseState = ILineRange[];
36+
3537
export class FoldingModel {
3638
private _textModel: IModel;
3739
private _decorationProvider: IDecorationProvider;
@@ -134,6 +136,44 @@ export class FoldingModel {
134136
this._updateEventEmitter.fire({ model: this });
135137
}
136138

139+
/**
140+
* Collapse state, for persistence only
141+
*/
142+
public getCollapseState(): CollapseState {
143+
let collapsedRanges: ILineRange[] = [];
144+
for (let region of this._regions) {
145+
if (region.isCollapsed && region.editorDecorationId) {
146+
let range = this._textModel.getDecorationRange(region.editorDecorationId);
147+
if (range) {
148+
let startLineNumber = range.startLineNumber;
149+
let endLineNumber = range.endLineNumber + region.range.endLineNumber + region.range.startLineNumber;
150+
collapsedRanges.push({ startLineNumber, endLineNumber });
151+
}
152+
}
153+
}
154+
if (collapsedRanges.length > 0) {
155+
return collapsedRanges;
156+
}
157+
return null;
158+
}
159+
160+
/**
161+
* Apply persisted state, for persistence only
162+
*/
163+
public applyCollapseState(state: CollapseState) {
164+
if (!Array.isArray(state)) {
165+
return;
166+
}
167+
let toToogle: FoldingRegion[] = [];
168+
for (let range of state) {
169+
let region = this.getRegionAtLine(range.startLineNumber);
170+
if (region && !region.isCollapsed) {
171+
toToogle.push(region);
172+
}
173+
}
174+
this.toggleCollapseState(toToogle);
175+
}
176+
137177
public dispose() {
138178
let editorDecorationIds = [];
139179
for (let region of this._regions) {

src/vs/editor/contrib/folding/common/hiddenRangeModel.ts

+22-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55

66
import Event, { Emitter } from 'vs/base/common/event';
77
import { Range, IRange } from 'vs/editor/common/core/range';
8-
import { FoldingRegion, FoldingModel, IFoldingRange } from 'vs/editor/contrib/folding/common/foldingModel';
8+
import { FoldingRegion, FoldingModel, IFoldingRange, CollapseState } from 'vs/editor/contrib/folding/common/foldingModel';
99
import { IDisposable } from 'vs/base/common/lifecycle';
1010
import { Selection } from 'vs/editor/common/core/selection';
1111
import { findFirst } from 'vs/base/common/arrays';
1212

13-
1413
export class HiddenRangeModel {
1514
private _foldingModel: FoldingModel;
1615
private _hiddenRanges: IRange[] = [];
@@ -53,9 +52,28 @@ export class HiddenRangeModel {
5352
}
5453
};
5554
if (updateHiddenAreas || i < this._hiddenRanges.length) {
56-
this._hiddenRanges = newHiddenAreas;
57-
this._updateEventEmitter.fire(newHiddenAreas);
55+
this.applyHiddenRanges(newHiddenAreas);
56+
}
57+
}
58+
59+
public applyCollapseState(state: CollapseState): boolean {
60+
if (!Array.isArray(state) || state.length === 0) {
61+
return false;
5862
}
63+
let hiddenRanges = [];
64+
for (let r of state) {
65+
if (!r.startLineNumber || !r.endLineNumber) {
66+
return false;
67+
}
68+
hiddenRanges.push(new Range(r.startLineNumber, 1, r.endLineNumber, 1));
69+
}
70+
this.applyHiddenRanges(hiddenRanges);
71+
return true;
72+
}
73+
74+
private applyHiddenRanges(newHiddenAreas: IRange[]) {
75+
this._hiddenRanges = newHiddenAreas;
76+
this._updateEventEmitter.fire(newHiddenAreas);
5977
}
6078

6179
public hasRanges() {

0 commit comments

Comments
 (0)