Skip to content

Commit 9e05d4b

Browse files
committed
[folding] fold regions, initial, preconfigured support. For microsoft#12146
1 parent a678f60 commit 9e05d4b

9 files changed

Lines changed: 341 additions & 135 deletions

File tree

extensions/cpp/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,11 @@
3333
"scopeName": "source.c.platform",
3434
"path": "./syntaxes/Platform.tmLanguage"
3535
}]
36+
},
37+
"folding": {
38+
"markers": {
39+
"start": "^\\s*#pragma\\s+region",
40+
"end": "^\\s*#pragma\\s+endregion"
41+
}
3642
}
3743
}

extensions/csharp/language-configuration.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,11 @@
2323
["<", ">"],
2424
["'", "'"],
2525
["\"", "\""]
26-
]
26+
],
27+
"folding": {
28+
"markers": {
29+
"start": "^\\s*#region",
30+
"end": "^\\s*#endregion"
31+
}
32+
}
2733
}

extensions/javascript/javascript-language-configuration.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@
2424
["'", "'"],
2525
["\"", "\""],
2626
["`", "`"]
27-
]
27+
],
28+
"folding": {
29+
"markers": {
30+
"start": "^\\s*//\\s*#region",
31+
"end": "^\\s*//\\s*#endregion"
32+
}
33+
}
2834
}

extensions/powershell/language-configuration.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,11 @@
2222
["(", ")"],
2323
["\"", "\""],
2424
["'", "'"]
25-
]
25+
],
26+
"folding": {
27+
"markers": {
28+
"start": "^\\s*#region",
29+
"end": "^\\s*#endregion"
30+
}
31+
}
2632
}

extensions/typescript/language-configuration.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,11 @@
2424
["'", "'"],
2525
["\"", "\""],
2626
["`", "`"]
27-
]
27+
],
28+
"folding": {
29+
"markers": {
30+
"start": "^\\s*//\\s*#region",
31+
"end": "^\\s*//\\s*#endregion"
32+
}
33+
}
2834
}

extensions/vb/language-configuration.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,11 @@
2020
["(", ")"],
2121
["\"", "\""],
2222
["<", ">"]
23-
]
23+
],
24+
"folding": {
25+
"markers": {
26+
"start": "^\\s*#Region",
27+
"end": "^\\s*#End Region"
28+
}
29+
}
2430
}

src/vs/editor/common/model/indentRanges.ts

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ export class IndentRange {
1212
startLineNumber: number;
1313
endLineNumber: number;
1414
indent: number;
15+
marker: boolean;
1516

16-
constructor(startLineNumber: number, endLineNumber: number, indent: number) {
17+
constructor(startLineNumber: number, endLineNumber: number, indent: number, marker?: boolean) {
1718
this.startLineNumber = startLineNumber;
1819
this.endLineNumber = endLineNumber;
1920
this.indent = indent;
21+
this.marker = marker;
2022
}
2123

2224
public static deepCloneArr(indentRanges: IndentRange[]): IndentRange[] {
@@ -29,12 +31,27 @@ export class IndentRange {
2931
}
3032
}
3133

32-
export function computeRanges(model: ITextModel, offSide: boolean, minimumRangeSize: number = 1): IndentRange[] {
34+
export interface FoldMarkers {
35+
start: string;
36+
end: string;
37+
indent?: number;
38+
}
39+
40+
interface PreviousRegion { indent: number; line: number; marker: RegExp; };
41+
42+
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldMarkers, minimumRangeSize: number = 1): IndentRange[] {
3343

3444
let result: IndentRange[] = [];
3545

36-
let previousRegions: { indent: number, line: number }[] = [];
37-
previousRegions.push({ indent: -1, line: model.getLineCount() + 1 }); // sentinel, to make sure there's at least one entry
46+
let pattern = void 0;
47+
let patternIndent = -1;
48+
if (markers) {
49+
pattern = new RegExp(`(${markers.start})|(?:${markers.end})`);
50+
patternIndent = typeof markers.indent === 'number' ? markers.indent : -1;
51+
}
52+
53+
let previousRegions: PreviousRegion[] = [];
54+
previousRegions.push({ indent: -1, line: model.getLineCount() + 1, marker: null }); // sentinel, to make sure there's at least one entry
3855

3956
for (let line = model.getLineCount(); line > 0; line--) {
4057
let indent = model.getIndentLevel(line);
@@ -46,26 +63,48 @@ export function computeRanges(model: ITextModel, offSide: boolean, minimumRangeS
4663
}
4764
continue; // only whitespace
4865
}
66+
let m;
67+
if (pattern && (patternIndent === -1 || patternIndent === indent) && (m = model.getLineContent(line).match(pattern))) {
68+
// folding pattern match
69+
if (m[1]) { // start pattern match
70+
if (previous.indent >= 0 && !previous.marker) {
4971

72+
// discard all regions until the folding pattern
73+
do {
74+
previousRegions.pop();
75+
previous = previousRegions[previousRegions.length - 1];
76+
} while (previous.indent >= 0 && !previous.marker);
77+
}
78+
if (previous.marker) {
79+
// new folding range from pattern, includes the end line
80+
result.push(new IndentRange(line, previous.line, indent, true));
81+
previous.marker = null;
82+
previous.indent = indent;
83+
previous.line = line;
84+
}
85+
} else { // end pattern match
86+
previousRegions.push({ indent: -2, line, marker: pattern });
87+
}
88+
} else {
89+
if (previous.indent > indent) {
90+
// discard all regions with larger indent
91+
do {
92+
previousRegions.pop();
93+
previous = previousRegions[previousRegions.length - 1];
94+
} while (previous.indent > indent);
5095

51-
if (previous.indent > indent) {
52-
// discard all regions with larger indent
53-
do {
54-
previousRegions.pop();
55-
previous = previousRegions[previousRegions.length - 1];
56-
} while (previous.indent > indent);
57-
58-
// new folding range
59-
let endLineNumber = previous.line - 1;
60-
if (endLineNumber - line >= minimumRangeSize) {
61-
result.push(new IndentRange(line, endLineNumber, indent));
96+
// new folding range
97+
let endLineNumber = previous.line - 1;
98+
if (endLineNumber - line >= minimumRangeSize) {
99+
result.push(new IndentRange(line, endLineNumber, indent));
100+
}
101+
}
102+
if (previous.indent === indent) {
103+
previous.line = line;
104+
} else { // previous.indent < indent
105+
// new region with a bigger indent
106+
previousRegions.push({ indent, line, marker: null });
62107
}
63-
}
64-
if (previous.indent === indent) {
65-
previous.line = line;
66-
} else { // previous.indent < indent
67-
// new region with a bigger indent
68-
previousRegions.push({ indent, line });
69108
}
70109
}
71110

src/vs/editor/common/model/textModelWithTokens.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,8 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
845845
if (!this._indentRanges) {
846846
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id);
847847
let offSide = foldingRules && foldingRules.offSide;
848+
let markers = foldingRules && foldingRules['markers'];
849+
this._indentRanges = computeRanges(this, offSide, markers);
848850
}
849851
return this._indentRanges;
850852
}

0 commit comments

Comments
 (0)