Skip to content

Commit

Permalink
(PowerShellGH-811) Fix folding for regions with same end token
Browse files Browse the repository at this point in the history
Previously the token matching was broken;
```
foreach ($1 in $2) {     <----- STARTS MATCH HERE (1)

    $x = @{  <-----   STARTS MATCH HERE (2)
        'abc' = 'def'
    }        <----- ENDS   MATCH HERE (1) (2)
}
```

This was caused by two or more different token pairs sharing the same end token.
This commit modifies the token pair matching to take an array of Start Tokens
instead of a single.  This has the added benefit of performance increase too.

This commit also adds tests for this scenario.
  • Loading branch information
glennsarti committed Dec 8, 2018
1 parent bb65b2a commit 02273eb
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
28 changes: 11 additions & 17 deletions src/PowerShellEditorServices/Language/TokenOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System;
using System.Collections.Generic;
using System.Management.Automation.Language;
using System.Text.RegularExpressions;
Expand All @@ -28,24 +29,17 @@ internal static FoldingReference[] FoldableRegions(
{
List<FoldingReference> foldableRegions = new List<FoldingReference>();

// Find matching braces { -> }
foldableRegions.AddRange(
MatchTokenElements(tokens, TokenKind.LCurly, TokenKind.RCurly, RegionKindNone)
);

// Find matching braces ( -> )
foldableRegions.AddRange(
MatchTokenElements(tokens, TokenKind.LParen, TokenKind.RParen, RegionKindNone)
);

// Find matching arrays @( -> )
// Find matching braces { -> }
// Find matching hashes @{ -> }
foldableRegions.AddRange(
MatchTokenElements(tokens, TokenKind.AtParen, TokenKind.RParen, RegionKindNone)
MatchTokenElements(tokens, new TokenKind[] { TokenKind.LCurly, TokenKind.AtCurly }, TokenKind.RCurly, RegionKindNone)
);

// Find matching hashes @{ -> }
// Find matching parentheses ( -> )
// Find matching array literals @( -> )
// Find matching subexpressions $( -> )
foldableRegions.AddRange(
MatchTokenElements(tokens, TokenKind.AtCurly, TokenKind.RParen, RegionKindNone)
MatchTokenElements(tokens, new TokenKind[] { TokenKind.LParen, TokenKind.AtParen, TokenKind.DollarParen }, TokenKind.RParen, RegionKindNone)
);

// Find contiguous here strings @' -> '@
Expand Down Expand Up @@ -146,19 +140,19 @@ static private FoldingReference CreateFoldingReference(
}

/// <summary>
/// Given an array of tokens, find matching regions which start and end with a different TokenKind
/// Given an array of tokens, find matching regions which start (array of tokens) and end with a different TokenKind
/// </summary>
static private List<FoldingReference> MatchTokenElements(
Token[] tokens,
TokenKind startTokenKind,
TokenKind[] startTokenKind,
TokenKind endTokenKind,
string matchKind)
{
List<FoldingReference> result = new List<FoldingReference>();
Stack<Token> tokenStack = new Stack<Token>();
foreach (Token token in tokens)
{
if (token.Kind == startTokenKind) {
if (Array.IndexOf(startTokenKind, token.Kind) != -1) {
tokenStack.Push(token);
}
if ((tokenStack.Count > 0) && (token.Kind == endTokenKind)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,5 +217,33 @@ public void LaguageServiceFindsFoldablRegionsWithDuplicateRegions() {
FoldingReference[] result = GetRegions(testString);
AssertFoldingReferenceArrays(expectedFolds, result);
}

// This tests that token matching { -> }, @{ -> } and
// ( -> ), @( -> ) and $( -> ) does not confuse the folder
[Fact]
public void LaguageServiceFindsFoldablRegionsWithSameEndToken() {
string testString =
@"foreach ($1 in $2) {
$x = @{
'abc' = 'def'
}
}
$y = $(
$arr = @('1', '2'); Write-Host ($arr)
)
";
FoldingReference[] expectedFolds = {
CreateFoldingReference(0, 19, 4, 1, null),
CreateFoldingReference(2, 9, 3, 5, null),
CreateFoldingReference(7, 5, 8, 1, null)
};

FoldingReference[] result = GetRegions(testString);

AssertFoldingReferenceArrays(expectedFolds, result);
}

}
}

0 comments on commit 02273eb

Please sign in to comment.