Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(GH-811) Fix folding with spanning regions #805

Merged
merged 4 commits into from
Dec 12, 2018

Conversation

glennsarti
Copy link
Contributor

@glennsarti glennsarti commented Dec 6, 2018

From PowerShell/vscode-powershell#1631

Fixes #811


In the use case above the following code snippet is confusing the folder;

Bad folder

foreach ($1 in $2) {     <----- STARTS MATCH HERE (1)

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

Good folder

foreach ($1 in $2) {     <----- STARTS MATCH HERE (1)

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

The old grammar based folder knew the difference between a } terminating a hash vs a script block. The PowerShell Tokeniser does not.

Note I found this is also the case for @( ... ), ( ... ), and $( ... )

@glennsarti glennsarti requested a review from rjmholt as a code owner December 6, 2018 14:11
@glennsarti
Copy link
Contributor Author

@rjmholt @TylerLeonhardt @rkeithhill Although this is WIP, looking for a quick review. I need to cleanup the commit message.

Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thanks for jumping this!

@glennsarti glennsarti changed the title {WIP} (GH-1631) Fix folding with spanning regions (GH-1631) Fix folding with spanning regions Dec 8, 2018
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.
@glennsarti glennsarti changed the title (GH-1631) Fix folding with spanning regions (GH-811) Fix folding with spanning regions Dec 8, 2018
@glennsarti
Copy link
Contributor Author

@TylerLeonhardt This is no longer WIP. Ready for merge.

Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM!

Copy link
Collaborator

@SeeminglyScience SeeminglyScience left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM, just one small request.

Also, this definitely isn't a blocker for this PR, but looking over the implementation, would something like this make sense instead?

private readonly Stack<Token> _curlyEndStarts = new Stack<Token>();

private readonly Stack<Token> _parenEndStarts = new Stack<Token>();

internal FoldingReference[] FoldableRegions(Tokens[] tokens, bool showLastLine)
{
    var foldableRegions = new List<FoldableReference>();
    foreach (Token token in tokens)
    {
        Token start;
        switch (token.TokenKind)
        {
            case TokenKind.AtCurly:
            case TokenKind.LCurly:
                _curlyEndStarts.Push(token);
                break;
            case TokenKind.RCurly:
                start = _curlyEndStarts.Pop();
                foldableRegions.Add(CreateFoldingReference(start, token.Extent.EndLineNumber));
                break;
            case TokenKind.AtParen:
            case TokenKind.LParen:
                _parenEndStarts.Push(token);
                break;
            case TokenKind.RParen:
                start = _parenEndStarts.Pop();
                foldableRegions.Add(CreateFoldingReference(start, token.Extent.EndLineNumber));
                break;
        }
    }
}

That way you'd only need to enumerate once, it should already be sorted, and no nulls. Sorry if this was already brought up in the original PR

src/PowerShellEditorServices/Language/TokenOperations.cs Outdated Show resolved Hide resolved
src/PowerShellEditorServices/Language/TokenOperations.cs Outdated Show resolved Hide resolved
@glennsarti
Copy link
Contributor Author

glennsarti commented Dec 10, 2018

@SeeminglyScience Just a note that I can't reply easily to review comments.

That way you'd only need to enumerate once, it should already be sorted, and no nulls. Sorry if this was already brought up in the original PR

  • The sorting will not be solved due to the comments foldingreferences being appended later.
  • The way it's currently written nulls can still be written if the range doesn't span at least two lines
  • While slightly inefficient, multiple passes of the token array is very cheap (sub ms)

Note that PR #806 removes all those code paths anyway.

Copy link
Contributor

@rjmholt rjmholt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

src/PowerShellEditorServices/Language/TokenOperations.cs Outdated Show resolved Hide resolved
src/PowerShellEditorServices/Language/TokenOperations.cs Outdated Show resolved Hide resolved
#endregion Comment Block 3

# What about anonynous variable assignment
${this
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the edge case I like to see. Allowing these awful variable names is one of @JamesWTruher's proudest additions to PowerShell :)

Previously the code folder was not aware of unopinionated variable name
assignments.  This commit adds detection and an appropriate test.
This commit adds a splat command to the folding scenario to ensure that the
folder is not confused by the (at) character for splatting.
@rjmholt rjmholt merged commit e3179e4 into PowerShell:master Dec 12, 2018
@@ -16,10 +16,26 @@ namespace Microsoft.PowerShell.EditorServices
/// </summary>
internal static class TokenOperations
{
// Region kinds to align with VSCode's region kinds
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants