Skip to content

Commit 92a5324

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 uses 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 92a5324

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

src/features/Folding.ts

+9-7
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,11 +252,13 @@ export class FoldingProvider implements vscode.FoldingRangeProvider {
252252
return 0;
253253
});
254254

255-
// Convert the matched token list into a FoldingRange[]
256-
const foldingRanges = [];
257-
foldableRegions.forEach((item) => { foldingRanges.push(item.toFoldingRange()); });
258-
259-
return foldingRanges;
255+
return foldableRegions
256+
// It's possible to have duplicate or overlapping ranges, that is, regions which have the same starting
257+
// line number as the previous region. Therefore only emit ranges which have a different starting line
258+
// than the previous range.
259+
.filter((item, index, src) => index === 0 || item.startline !== src[index - 1].startline)
260+
// Convert the internal representation into the VSCode expected type
261+
.map((item) => item.toFoldingRange());
260262
}
261263

262264
/**

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)