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

Add minimal progress bar using ANSI rendering #14414

Merged
merged 21 commits into from Feb 5, 2021

Conversation

SteveL-MSFT
Copy link
Member

@SteveL-MSFT SteveL-MSFT commented Dec 14, 2020

PR Summary

The current progress bar is large and complex and provides a different experience on Windows vs Linux/macOS. Redo the progress bar to be a single line leveraging ANSI escape sequence to render progress. $PSStyle.Progress now controls configuration:

$PSStyle.Progress.Style is an ANSI string setting the rendering style
$PSStyle.Progress.MaxWidth sets the max width of the view, defaults to 120. Set to 0 for console width.
$PSStyle.Progress.View is an enum with values Minimal and Classic where Classic is existing rendering with no changes. Current default is Minimal.

Example:

Screen-Recording-2021-01-28-at-7

Since this visualization is built into the console host, the new settings would not apply to other hosts like EditorServices.

Fix #14426

PR Checklist

@ghost ghost assigned daxian-dbw Dec 14, 2020
@SteveL-MSFT
Copy link
Member Author

Noticed an initial rendering issue with the Expand-Archive example I need to fix

@jhoneill
Copy link

One of the attractions of the existing progress reporting is it can list things with a fair amount of detail and when they are done, the output goes away. This seems to end up with clutter left behind and the formatting makes it very "attention grabbing"
I would actually want to turn off progress indications if they did that, and would stop using write-progress in my code.

@doctordns
Copy link
Contributor

One of the attractions of the existing progress reporting is it can list things with a fair amount of detail and when they are done, the output goes away. This seems to end up with clutter left behind and the formatting makes it very "attention grabbing"
I would actually want to turn off progress indications if they did that, and would stop using write-progress in my code.

This progress bar and pop up stuff is also an issue for me in VS Code. Using VS Code and doing server management pops up all manner of stuff that obscures what is going on in the screen and does not go away. I'd like to see this addressed in general.

@Jaykul
Copy link
Contributor

Jaykul commented Dec 14, 2020

One of the attractions of the existing progress reporting is it can list things with a fair amount of detail and when they are done, the output goes away. This seems to end up with clutter left behind and the formatting makes it very "attention grabbing"

The current implementation is far bigger and more attention grabbing -- I wrote a script just last week using Invoke-RestMethod repeatedly which ended up completely obscuring the more important actual output of the script behind a wall of RestMethod progress reports that weren't cleaned up until the script ended.

Obviously one can always turn off progress output (we already do this on PS5.1 because of performance problems), but I think leaving behind a trace of the progress that was is better than the current situation where the progress is totally gone after the fact --regardless of outcome. Currently scripts cannot rely heavily on progress to report state because if they crash, the information is completely lost.

Having said that, I have two other questions:

  1. Have you tested this with long status strings? There's currently nothing preventing people from writing multiple lines worth of information into a Status or an Activity, right?
  2. Is there an option to still have multi-line output? I'm concerned that using the same space for the text and the progress is going to make this hard to deal with for some users...

@SteveL-MSFT
Copy link
Member Author

@Jaykul regarding long status messages, I did test that and the current PR explicitly truncates it adding an ellipsis to the end. This is similar to how content is truncated in other parts of PowerShell formatting. Anyone writing progress needs to be thoughtful on the information being presented (like long file paths). I'd rather than support multi-line output.

Do you have a scenario that requires multi-line progress output? Keep in mind that nested and multi-progress bars is supported, but each bar is limited to one line currently.

@jhoneill
Copy link

One of the attractions of the existing progress reporting is it can list things with a fair amount of detail and when they are done, the output goes away. This seems to end up with clutter left behind and the formatting makes it very "attention grabbing"

The current implementation is far bigger and more attention grabbing -- I wrote a script just last week using Invoke-RestMethod repeatedly which ended up completely obscuring the more important actual output of the script behind a wall of RestMethod progress reports that weren't cleaned up until the script ended.

The important thing is they are cleaned up when the script ends. The job of Write-Progress is to give the user some indication that the script hasn't hung. That's it. If you want information about what happened that's for Write-Debug, or Write-Verbose, or in the case of people who feel the strong urge to generate lots of display on the console Write-hostwith-foreground`

Obviously one can always turn off progress output (we already do this on PS5.1 because of performance problems), but I think leaving behind a trace of the progress that was is better than the current situation where the progress is totally gone after the fact --regardless of outcome.

There are two different requirements, printing "chatty" output which a programmer expects a user to read, and providing something which says "still working, haven't crashed".

Currently scripts cannot rely heavily on progress to report state because if they crash, the information is completely lost.

Nor should they . Imagine if (say) the copy dialog in explorer remained open to tell you how many bytes / files had been copied at what speed afterwards. You don't care, the tasks was completed without errors, you can get on with the next task without stopping to read about what happened which is past your ability to change.

@SteveL-MSFT
Copy link
Member Author

Note that leaving the progress on screen is modeled after various Linux utilities. I can certainly see arguments for both sides.

@jhoneill
Copy link

Note that leaving the progress on screen is modeled after various Linux utilities. I can certainly see arguments for both sides.

Well yes, the unix world doesn't have verbose, debug, information and progress to write to, so all manner of garbage goes to standard output (and of course there isn't the distinction between "For human eyeballs" and "Output" that PowerShell has)

Being cleaner and tidier is one of the attractions of PowerShell. Getting the error output to be shorter was held to be a Good Thing, yes?
Developers have figured out what should be transient (something for eyeballs while work is happening) generally don't force users to read stuff they don't need to, and make most of the "hey this is what the program has done" stuff verbose / debug. It works well , but nothing is stopping developers writing commands in the style of Linux, just replace write-verbose with write-host . So this proposal doesn't allow anything extra but would take away something good and distinctive.

Anything which has a loop of display progress message, output a row, and remove the progress message will - I suspect - get the messages interleaved with the output.

@SteveL-MSFT
Copy link
Member Author

Native commands actually use stderr for the purpose of progress/verbose/warning/error messages and stdout is only for output. In this case, it's no different in that pipelining/redirection (unless stream(s) other than output is specified) only happens for output/stdout. I'm thinking of making whether it stays or clears user settable at least during the experimental phase to get real world usage feedback.

@iSazonov
Copy link
Collaborator

I'd prefer to keep current (release version) behavior in the PR. I wonder we discuss this in the PR. I think we should discuss this in an issue for all kinds of progress bar. There are some issues with feedback for progress bar. Current design/implementation has fundamental difficulties and we could improve this.

@SteveL-MSFT
Copy link
Member Author

Created #14426, let's have the design discussion there and keep discussion here for code review

@ghost ghost added the Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept label Dec 18, 2020
@ghost ghost added the Stale label Jan 2, 2021
@ghost
Copy link

ghost commented Jan 2, 2021

This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 15 days. It will be closed if no further activity occurs within 10 days of this comment.

@ghost ghost removed Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept Stale labels Jan 8, 2021
@ghost ghost added Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept and removed Waiting on Author The PR was reviewed and requires changes or comments from the author before being accept labels Jan 12, 2021
@SteveL-MSFT
Copy link
Member Author

Found an issue with how progress is rendered when objects are emitted to pipeline. Looks like I'll have to support clearing in all cases to make this work.

@SteveL-MSFT
Copy link
Member Author

Remaining codefactor are existing style or by-design

@iSazonov iSazonov added the CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log label Feb 4, 2021
@@ -336,6 +356,88 @@ private static void RenderFullDescription(string description, string indent, int
maxWidth));
}

internal static bool IsMinimalProgressRenderingEnabled()
{
return ExperimentalFeature.IsEnabled("PSAnsiProgress") && PSStyle.Instance.Progress.View == ProgressView.Minimal;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why don't we use constants for feature names? "PSAnsiProgress" looks like a puzzle.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question, we haven't been doing this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll update it for this feature in this PR, but won't update the other ones. We can follow this pattern going forward.

Comment on lines +279 to +282
/// <summary>
/// Gets or sets the style for progress bar.
/// </summary>
public string Style { get; set; } = "\x1b[33;1m";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add in the description that is the default.

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean describe in text what the ANSI escape sequence represents?

/// <summary>
/// Gets or sets the style for progress bar.
/// </summary>
public ProgressView View { get; set; } = ProgressView.Minimal;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe ViewStyle if it is a style.

Copy link
Member Author

Choose a reason for hiding this comment

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

Trying not to overload the style term and use it to mean ANSI decoration. Will change the description to view.

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

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

LGTM with a few comments.

@daxian-dbw
Copy link
Member

The CI tests are being flaky recently. I retried the failed CIs twice but both got test failures related to WinCompat:

Additional tests for Import-Module with WinCompat.Tests that ErrorAction/WarningAction have effect when Import-Module with WinCompat is used. Verify that Warning is generated with default WarningAction

Given that the second to last commit had successful CI runs (only CodeFactor failed which can be ignored) and the last commit only made trivial changes to code that is unrelated to the failed WinCompat tests, I will merge this PR.

@daxian-dbw daxian-dbw merged commit 887467e into PowerShell:master Feb 5, 2021
@SteveL-MSFT SteveL-MSFT deleted the progress-bar branch February 5, 2021 18:52
@daxian-dbw
Copy link
Member

@SteveL-MSFT Just noticed a small issue with the new progress bar:

image

When the MaxWidth is not big enough and the message cannot be fully displayed, I expect the message will be truncated with ellipsis ..., but it displays only 1 dot.

@daxian-dbw
Copy link
Member

Ah, another issue, when MaxWidth is too small to have enough space for the [...] part, progress rendering will fail with exceptions:

PS:12> $PSStyle.Progress.MaxWidth = 10
PS:13> Expand-Archive -Path .\source.zip -DestinationPath C:\arena\tmp\deleteme
Write-Progress: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:1179
Line |
1179 |          Write-Progress -Activity $cmdletName -Status $status -Percent …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Length cannot be less than zero. (Parameter 'length')

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\' because it
     | does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\Dockerfile'
     | because it does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path
     | 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\devcontainer.json' because it
     | does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\fedora30\'
     | because it does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path
     | 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\fedora30\Dockerfile' because it
     | does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path
     | 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.devcontainer\fedora30\devcontainer.json'
     | because it does not exist.

Remove-Item: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:418
Line |
 418 |  …               $expandedItems | % { Remove-Item "$_" -Force -Recurse }
     |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Cannot find path 'C:\arena\tmp\deleteme\PowerShell-7.2.0-preview.1\.editorconfig' because it does
     | not exist.

Write-Progress: C:\arena\repos\powershell\src\powershell-win-core\bin\debug\net5.0\win7-x64\publish\Modules\Microsoft.PowerShell.Archive\Microsoft.PowerShell.Archive.psm1:1179
Line |
1179 |          Write-Progress -Activity $cmdletName -Status $status -Percent …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Length cannot be less than zero. (Parameter 'length')

@SeeminglyScience
Copy link
Collaborator

Since this visualization is built into the console host, the new settings would not apply to other hosts like EditorServices.

PSES holds onto a copy of ConsoleHost and uses it's implementation of WriteProgress. I don't think it's likely to cause issues, but it will apply there as well.

@ghost
Copy link

ghost commented Feb 12, 2021

🎉v7.2.0-preview.3 has been released which incorporates this pull request.:tada:

Handy links:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CL-General Indicates that a PR should be marked as a general cmdlet change in the Change Log
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve rendering of Progress
9 participants