PowerShell / PSScriptAnalyzer

Download ScriptAnalyzer from PowerShellGallery
https://www.powershellgallery.com/packages/PSScriptAnalyzer/
MIT License
1.8k stars 366 forks source link

Indentation breaks using anything other than pipelineIndentationStyle: None using a second pipe within parenthesis #1976

Open C0smin opened 4 months ago

C0smin commented 4 months ago

Prerequisites

Summary

The formatting of code breaks, not closing the indentation where it is logical. The conditions are highlighted in the Steps to reproduce section but it seems to be related to using both the pipe | and parenthesis () in multiple lines.

PowerShell Version

Name                           Value
----                           -----
PSVersion                      7.4.1
PSEdition                      Core
GitCommitId                    7.4.1
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0.}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visual Studio Code Version

1.86.2
x64

Extension Version

ms-vscode.powershell@2024.3.0

Steps to Reproduce

  1. Open a new file and paste this code:
    1 | Select-Object (
    $_ |
        Write-Host
    )
    Write-Host 'Indentation is broken'
  2. Format the document
  3. Write-Host is now indented at the same level as the closed parenthesis:
    1 | Select-Object (
    $_ |
        Write-Host
    )
    Write-Host 'Indentation is broken'

Visuals

No response

Logs

No response

SydneyhSmith commented 4 months ago

@C0smin what are your formatting settings?

C0smin commented 4 months ago

Hi @SydneyhSmith, default VSCode and powershell extension, this is the only non default setting in my editor (this is global user-data settings.json):

{
    "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline"
}
bergmeister commented 2 months ago

I can confirm I can repro with this specific setting. The thing with using different non-default settings for pipelineIndentationStyle is that your mileage might vary, it can achieve it in most cases but there are lots of edge cases that is still doesn't get, hence why it's not the default. Still great to raise it so maybe I can later look at seeing whether we can fix that. I've been doing that for a few years now but due to PowerShell's generic nature it's hard to write generic code covering all cases...

deadlydog commented 1 month ago

I came here to report this issue as well; glad to see that someone already has 🙂 I too am using the VS Code setting powershell.codeFormatting.pipelineIndentationStyle = IncreaseIndentationForFirstPipeline and seeing the same issue.

I can confirm it also occurs when using the IncreaseIndentationAfterEveryPipeline value, and is much worse since there will be several levels of indentation and the next code statement will continue with the deeper indentation. e.g.

$results.ServersResults |
    Select-Object -Property PSComputerName -ExpandProperty Matches |
        Select-Object -Property PSComputerName,
        Match, FilePath, LineNumber, Line, Pattern |
            Sort-Object -Property Match, PSComputerName, FilePath, LineNumber

            # This next line should not be indented since it is not part of the above pipeline.
            [PSCustomObject[]] $connectionErrors = Convert-ServersConnectionErrorsIntoUserFriendlyMessage

I find it's not consistent though. Sometimes the following statement does end up with the proper indentation, but other times it doesn't. I haven't been able to determine what exactly causes it to mess up sometimes.

I see C0smin reported that it happens when using a pipe inside of parenthesis, and I can reproduce the issue using his code snippet. My snippet does not use a pipe inside of parenthesis though, and actually just pasting my code above in isolation does not reproduce the issue 😕.


Ok, after a bit more testing I'm able to reproduce it with this code:

Process {
    $results.ServersResults |
        Select-Object -Property PSComputerName -ExpandProperty Matches |
            Select-Object -Property PSComputerName,
            Match, FilePath, LineNumber, Line, Pattern |
                Sort-Object -Property Match, PSComputerName, FilePath, LineNumber

                [PSCustomObject[]] $connectionErrors = Convert-ServersConnectionErrorsIntoUserFriendlyMessage
            }

            Begin {
                function SomeFunction {
                    [string[]] $serverNames = Get-ADComputer -Property DnsHostName |
                        Sort-Object
    }
}

That's the messed up indentation formatting. Down in the SomeFunction, if you move the Sort-Object up onto the above line and run the Format-Document VS Code command, it fixes some of the indentation issues, but not all of them, and you get this:

Process {
    $results.ServersResults |
        Select-Object -Property PSComputerName -ExpandProperty Matches |
            Select-Object -Property PSComputerName,
            Match, FilePath, LineNumber, Line, Pattern |
                Sort-Object -Property Match, PSComputerName, FilePath, LineNumber

                [PSCustomObject[]] $connectionErrors = Convert-ServersConnectionErrorsIntoUserFriendlyMessage
            }

            Begin {
                function SomeFunction {
                    [string[]] $serverNames = Get-ADComputer -Property DnsHostName | Sort-Object
                }
            }

If I remove the | Sort-Object altogether, then it formats everything correctly:

Process {
    $results.ServersResults |
        Select-Object -Property PSComputerName -ExpandProperty Matches |
            Select-Object -Property PSComputerName,
            Match, FilePath, LineNumber, Line, Pattern |
                Sort-Object -Property Match, PSComputerName, FilePath, LineNumber

    [PSCustomObject[]] $connectionErrors = Convert-ServersConnectionErrorsIntoUserFriendlyMessage
}

Begin {
    function SomeFunction {
        [string[]] $serverNames = Get-ADComputer -Property DnsHostName
    }
}

It's odd that code defined further down in the file can mess up the indentation of code above it in completely different scopes. Very weird, but it shows the problem isn't limited just to when you use a pipe inside of parenthesis.