Skip to content

Commit 5b3e355

Browse files
committed
(GH-1523) Remove duplicate/overlapping folding regions
Previously the syntax folder returned an ordered list of folding ranges which VS Code would "ignore" overlapping or duplicate ranges. However on manual testing, it showed that duplicate region did exist and could be folded/unfolded using the "Fold All" and "Unfold All" commands, but could NOT be manipulated manually in the editor using the +/- indicator. This commit adds a filter which removes any duplicate or overlapping regions which is easily detected via similar region start lines. This commit also adds a test for this scenario.
1 parent aa243d5 commit 5b3e355

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

src/features/Folding.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ export class FoldingProvider implements vscode.FoldingRangeProvider {
238238
// Sort the list of matched tokens, starting at the top of the document,
239239
// and ensure that, in the case of multiple ranges starting the same line,
240240
// that the largest range (i.e. most number of lines spanned) is sorted
241-
// first. This is needed as vscode will just ignore any duplicate folding
242-
// ranges.
241+
// first. This is needed to detect duplicate regions. The first in the list
242+
// will be used and subsequent duplicates ignored.
243243
foldableRegions.sort((a: LineNumberRange, b: LineNumberRange) => {
244244
// Initially look at the start line
245245
if (a.startline > b.startline) { return 1; }
@@ -252,9 +252,18 @@ export class FoldingProvider implements vscode.FoldingRangeProvider {
252252
return 0;
253253
});
254254

255-
// Convert the matched token list into a FoldingRange[]
256255
const foldingRanges = [];
257-
foldableRegions.forEach((item) => { foldingRanges.push(item.toFoldingRange()); });
256+
foldableRegions
257+
// Use an array to remove regions which have the same starting line number as the previous
258+
// region. This removes duplicate or overlapping ranges. The sort function above determines
259+
// which region will be used in the event of duplicates
260+
.filter((item, index, src) => {
261+
// The first element in the array can never be a duplicate
262+
if (index === 0) { return true; }
263+
return (item.startline !== src[index - 1].startline);
264+
})
265+
// Convert the matched token list into a FoldingRange[]
266+
.forEach((item) => { foldingRanges.push(item.toFoldingRange()); });
258267

259268
return foldingRanges;
260269
}

test/features/folding.test.ts

+15
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ suite("Features", () => {
9696

9797
assertFoldingRegions(result, expectedMismatchedFoldingRegions);
9898
});
99+
100+
test("Does not return duplicate or overlapping regions", async () => {
101+
const expectedMismatchedFoldingRegions = [
102+
{ start: 1, end: 2, kind: null },
103+
{ start: 2, end: 4, kind: null },
104+
];
105+
106+
// Integration test against the test fixture 'folding-mismatch.ps1' that contains
107+
// duplicate/overlapping ranges due to the `(` and `{` characters
108+
const uri = vscode.Uri.file(path.join(fixturePath, "folding-duplicate.ps1"));
109+
const document = await vscode.workspace.openTextDocument(uri);
110+
const result = await provider.provideFoldingRanges(document, null, null);
111+
112+
assertFoldingRegions(result, expectedMismatchedFoldingRegions);
113+
});
99114
});
100115
});
101116
});

test/fixtures/folding-duplicate.ps1

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This script causes duplicate/overlapping ranges due to the `(` and `{` characters
2+
$AnArray = @(Get-ChildItem -Path C:\ -Include *.ps1 -File).Where({
3+
$_.FullName -ne 'foo'}).ForEach({
4+
# Do Something
5+
})

0 commit comments

Comments
 (0)