diff --git a/src/features/Folding.ts b/src/features/Folding.ts index 1a68b8c741..1e68f3b33b 100644 --- a/src/features/Folding.ts +++ b/src/features/Folding.ts @@ -238,8 +238,8 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { // Sort the list of matched tokens, starting at the top of the document, // and ensure that, in the case of multiple ranges starting the same line, // that the largest range (i.e. most number of lines spanned) is sorted - // first. This is needed as vscode will just ignore any duplicate folding - // ranges. + // first. This is needed to detect duplicate regions. The first in the list + // will be used and subsequent duplicates ignored. foldableRegions.sort((a: LineNumberRange, b: LineNumberRange) => { // Initially look at the start line if (a.startline > b.startline) { return 1; } @@ -252,11 +252,13 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { return 0; }); - // Convert the matched token list into a FoldingRange[] - const foldingRanges = []; - foldableRegions.forEach((item) => { foldingRanges.push(item.toFoldingRange()); }); - - return foldingRanges; + return foldableRegions + // It's possible to have duplicate or overlapping ranges, that is, regions which have the same starting + // line number as the previous region. Therefore only emit ranges which have a different starting line + // than the previous range. + .filter((item, index, src) => index === 0 || item.startline !== src[index - 1].startline) + // Convert the internal representation into the VSCode expected type + .map((item) => item.toFoldingRange()); } /** diff --git a/test/features/folding.test.ts b/test/features/folding.test.ts index 583abfb85d..8f94f96c65 100644 --- a/test/features/folding.test.ts +++ b/test/features/folding.test.ts @@ -96,6 +96,21 @@ suite("Features", () => { assertFoldingRegions(result, expectedMismatchedFoldingRegions); }); + + test("Does not return duplicate or overlapping regions", async () => { + const expectedMismatchedFoldingRegions = [ + { start: 1, end: 2, kind: null }, + { start: 2, end: 4, kind: null }, + ]; + + // Integration test against the test fixture 'folding-mismatch.ps1' that contains + // duplicate/overlapping ranges due to the `(` and `{` characters + const uri = vscode.Uri.file(path.join(fixturePath, "folding-duplicate.ps1")); + const document = await vscode.workspace.openTextDocument(uri); + const result = await provider.provideFoldingRanges(document, null, null); + + assertFoldingRegions(result, expectedMismatchedFoldingRegions); + }); }); }); }); diff --git a/test/fixtures/folding-duplicate.ps1 b/test/fixtures/folding-duplicate.ps1 new file mode 100644 index 0000000000..0d2a62797a --- /dev/null +++ b/test/fixtures/folding-duplicate.ps1 @@ -0,0 +1,5 @@ +# This script causes duplicate/overlapping ranges due to the `(` and `{` characters +$AnArray = @(Get-ChildItem -Path C:\ -Include *.ps1 -File).Where({ + $_.FullName -ne 'foo'}).ForEach({ + # Do Something +})