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

Reintroduce a color compatibility hack, but only for PowerShells #6810

Merged

Conversation

DHowett
Copy link
Member

@DHowett DHowett commented Jul 7, 2020

There is going to be a very long tail of applications that will
explicitly request VT SGR 40/37 when what they really want is to
SetConsoleTextAttribute() with a black background/white foreground.
Instead of making those applications look bad (and therefore making us
look bad, because we're releasing this as an update to something that
"looks good" already), we're introducing this compatibility quirk.
Before the color reckoning in #6698 + #6506, every color was subject
to being spontaneously and erroneously turned into the default color.
Now, only the 16-color palette value that matches the active console
background/foreground color will be destroyed, and only when received
from specific applications.

Removal will be tracked by #6807.

Michael and I discussed what layer this quirk really belonged in. I
originally believed it would be sufficient to detect a background color
that matched the legacy default background, but @j4james provided an
example of where that wouldn't work out (powershell setting the
foreground color to white/gray). In addition, it was too heavyhanded: it
re-broke black backgrounds for every application.

Michael thought that it should live in the server, as a small VT parser
that righted the wrongs coming directly out of the application. On
further investigation, however, I realized that we'd need to push more
information up into the server (so that it could make the decision about
which VT was wrong and which was right) than should be strictly
necessary.

The host knows which colors are right and wrong, and it gets final say
in what ends up in the buffer.

Because of that, I chose to push the quirk state down through
WriteConsole to DoWriteConsole and toggle state on the
SCREEN_INFORMATION that indicates whether the colors coming out of the
application are to be distrusted. This quirk only applies to pwsh.exe
and powershell.exe.

NOTE: This doesn't work for PowerShell the .NET Global tool,
because it is run as an assembly through dotnet.exe. I have no opinion
on how to fix this, or whether it is worth fixing.

PR Checklist

Validation

I've configured my terminals to have an incredibly garish color scheme
to show exactly what's going to happen as a result of this. The default
terminal background
is purple or red, and the foreground green. I've
printed out a heap of test colors to see how black interacts with them.

One the left, Terminal Preview without this fix. On the right, Terminal
Dev with this fix.

  • DEFAULT = 39 or 49
  • WHITE = 37 or 47
  • BLACK = 30 or 40
  • AIX WHT = 97 or 107
  • AIX BLK = 90 or 100
  • INT = 1

image

The only color lines that change are the ones where black as a
background or white as a foreground is selected out of the 16-color
palette explicitly. Reverse video still works fine (because black is in
the foreground!), and it's even possible to represent "black on default"
and reverse it into "default on black", despite the black in question
having been 40.

There is going to be a very long tail of applications that will
explicitly request VT SGR 40 when what they really want is to
SetConsoleTextAttribute() with a black background. Instead of making
those applications look bad (and therefore making us look bad, because
we're releasing this as an update to something that "looks good"
already), we're introducing this compatibility hack. Before the color
reckoning in #6698 + #6506, *every* color was subject to being
spontaneously and erroneously turned into the default color. Now, only
the 16-color palette value that matches the active console background
color will be destroyed.  This is not intended to be a long-term
solution. This comment will be discovered in forty years(*) time and
people will laugh at my hubris.

Removal, or final remediation, will be tracked by #6807.

*it doesn't matter when you're reading this, it will always be 40 years
from now.
@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

/cc @j4james, as I can't request a review from him right now.

With apologies.

@j4james
Copy link
Collaborator

j4james commented Jul 7, 2020

Obviously I hate this, but I understand the reasons for needing it. I'd have been happy to block #6506 for the same reasons. But definitely only as a temporary solution. The mention of "defer the hard work until later -- if ever" sounds scary to me. Because with this solution we're just trading one set of bug reports for another. And it's the apps that are doing the right thing that are going to get buggy results, while the buggy apps get what they want. That just doesn't seem right.

So +1 on doing whatever we have to do to keep PowerShell happy for now. But I'd definitely want us to make this a PowerShell-only mode ASAP. I don't think it really needs to be anything fancy - just exactly what you're doing now, but tied to a flag that is only set for PowerShell. Possibly a profile option that's default true for the PowerShell profiles, so that way users can still turn it off if PowerShell ever gets fixed.

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

So, my motivation behind saying “if ever” is less because we might keep it forever and more because I’m hoping to get PowerShell (Core) serviced with the fix. If we fail to identify any other applications that need a workaround like this, we can move it into a shim that only applies to PowerShell Inbox or simply throw up our hands and say “no, we aren’t going to make a concession for this one.” If we never have to do the shim work because all our reproducers disappear, that’s better than having to carry around a better version of the fix forever.

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

And with regards to blocking the original PR, I’m really glad we didn’t. I wanted this improvement, and its already paying dividends in how easily you could implement overline and fix DECSCNM. We would have had merge conflicts for months while we shook it all out.

At least this way we have the architectural fix and a place to document our known failings and foibles. I much prefer that over a beautiful architecture that never lands. 😄

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

I'm mildly concerned that by adding this hack for apps that are buggy, we'll have a harder time of identifying the misbehaving apps. We've obviously already identified powershell, but with this hack, the bugged apps will remain bugged, without an easy way to identify them.

I don't have a solution now for this problem, but it's something to consider. Maybe more coffee will help.

@j4james
Copy link
Collaborator

j4james commented Jul 7, 2020

To throw another spanner in the works, I've just realised that this patch actually makes things worse with light color schemes. For example, here's the before and after of dir ohno.txt in PowerShell with the One Half Light scheme. It may have been ugly before, but now it's invisible. You can't win. 😞

image

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

Alright, wow, ouch. The hack pretty much has to move into host (it can’t live in server because server doesn’t know the state of the global “legacy defaults” and it can’t live in the renderer because I absolutely don’t want to break 37 for anyone but powershell).

@zadjii-msft the only real way we truly ferret out all the broken applications is to ship with the visual regression, but I have so far failed to convince @cinnamon-msft that it’s worth our reputation to do so.

@cinnamon-msft
Copy link
Contributor

I know this isn't an ideal situation. Considering majority of people use PowerShell in Terminal, I'd be okay with having the hack only for PowerShell and the other broken applications will surface eventually.

@j4james
Copy link
Collaborator

j4james commented Jul 7, 2020

Have you considered maybe hacking this on the Terminal side as just a simple color scheme patch? For example, if the command line is powershell.exe or pwsh.exe, then automatically patch the initial scheme so black is the same color as background, and white is the same color as foreground. Doesn't require any run-time overhead, and people could still override the palette with an escape sequence if they really wanted to.

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

I'm not sure that's feasible, for a couple reasons.

  • For backgrounds; we don't support individual transparency for paletted colors, so acrylic/background image wouldn't show through even if we set black to background
  • It would damage black foregrounds/white backgrounds
  • It wouldn't help workflows where the user launches powershell/pwsh from another shell, and might do more harm (compared to a server/host quick for powershell directly) to workflows where the user launches something from pwsh

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

image

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

And a money shot for acrylic:

image

@DHowett DHowett marked this pull request as draft July 7, 2020 19:38
@DHowett DHowett changed the title Reintroduce a color compatibility hack, but only for the BG color Reintroduce a color compatibility hack, but only for powershells Jul 7, 2020
@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

The tests will fail to compile. Don't be daft, Dustin, fix them!

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

I'll have you all know that i hate this so much. 😄

@DHowett DHowett marked this pull request as ready for review July 7, 2020 20:17
@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

Okay, this check needs to be smarter about INTENSITY and whether the things it's suppressing match in intensity. 😄

@j4james
Copy link
Collaborator

j4james commented Jul 7, 2020

I've just been trying out this branch, and my initial impression with powershell.exe looked promising, but then I found that it didn't work with pwsh.exe (my version is 6.2.3). If I erased something on the command line, it redrew the line with a black background rather than the default.

I don't know if this has got anything to do with it, but when starting a conhost session in the debugger with pwsh.exe, I noticed that ConsoleShimPolicy::s_CreateInstance was actually called twice - the first time with processName being pwsh.exe, and the second time with dotnet.exe. Obviously the latter process isn't detected as powershell, so the quirk isn't enabled.

I don't have time to dig more tonight, but just wanted to let you know that there may be a problem somewhere.

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

Huh, that's actually really interesting. Thanks for testing!
There should be one shim policy per connected process, and we should be checking the process that's actually emitting the output ... but if something in process handling is busted, that could explain this behavior.

@DHowett
Copy link
Member Author

DHowett commented Jul 7, 2020

So, wow, okay. When PowerShell's been installed as a dotnet global tool it's spawned via dotnet pwsh.dll. The connection packet doesn't include the full commandline and we can't necessarily determine the identity of this dotnet.exe instance by its parentage ...

@DHowett DHowett changed the title Reintroduce a color compatibility hack, but only for powershells Reintroduce a color compatibility hack, but only for powershells EXE Jul 8, 2020
Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

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

No automated tests in ApiRoutines/ScreenBuffer/TextBuffer for the true case?

src/host/ApiRoutines.h Show resolved Hide resolved
@j4james
Copy link
Collaborator

j4james commented Jul 10, 2020

For the record I'm "happy" with this. I just want to note that black-on-black and white-on-white are no longer invisible if your defaults aren't white-on-black, which might trigger some bug reports. But I still think it's an improvement on the current situation, and hopefully this quirk won't have to last forever.

Copy link
Member

@miniksa miniksa left a comment

Choose a reason for hiding this comment

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

Yep, those are indeed some tests. Looks good. Thanks. I only mostly hate it. In the best way.

@DHowett DHowett changed the title Reintroduce a color compatibility hack, but only for powershells EXE Reintroduce a color compatibility hack, but only for PowerShells Jul 10, 2020
@DHowett DHowett merged commit 1bf4c08 into master Jul 10, 2020
@DHowett DHowett deleted the dev/duhowett/i_am_sad_about_this_but_we_are_at_an_impasse branch July 10, 2020 22:25
@ghost
Copy link

ghost commented Jul 22, 2020

🎉Windows Terminal Preview v1.2.2022.0 has been released which incorporates this pull request.:tada:

Handy links:

@jantari
Copy link
Contributor

jantari commented Jul 22, 2020

Thanks for all the work on this issue. Am I correct in my understanding that:

  • This compatibility hack fixes the vast vast majority of PowerShell/PSReadline background color troubles
  • Is mostly being introduced because the inbox Windows PowerShell 5.1 and its PSReadLine version aren't going to get updated soon if ever ( mrw: 🙄)
  • The underlying issue is fixed by PSReadLine#1626
  • Once I update my PSReadLine manually to a version that includes PR 1626, everything will be perfect and this lingering compatibility fix, although still active for all my powershell tabs, won't re-break anything with the new PSReadLine version?
  • This compatibility hack also covers me if I run powershell.exe from within a cmd tab because it taps into the commandlines of the whole child process tree of a tab and not just the initial program the tabs profile started?

@DHowett
Copy link
Member Author

DHowett commented Jul 22, 2020

@jantari very close.

Since the workaround is happening in conhost, which receives a "console connection packet" for every commandline application that starts up, it's not doing any process tree inspection. But, yes, on all your other points:

  1. This compatibility hack fixes the majority of PowerShell/PSReadline-related background color issues revealed by the changes in Improve the propagation of color attributes over ConPTY #6506 or seen when using the "experimental terminal features" conhost option we added in Windows 1903.
    • It disables the use of two colors from the ANSI 16-color palette
  2. The update for PSReadline shipped with Windows PowerShell will come out in an insider's build of Windows eventually.
  3. Yes, Teach PSReadline to not force the background color during render PowerShell/PSReadLine#1626 fixed this
  4. The fixed version of PSRL will not introduce further issues (it moves the decision we made in conhost down into PSRL), but it will NOT bring back the two colors removed from the 16-color palette.
  5. Right, or any other means of spawning something named powershell.exe or pwsh.exe 😄

@DHowett
Copy link
Member Author

DHowett commented Jul 22, 2020

(@jantari: why do you ask? I love talking about this stuff, so am happy to dig through a bunch of questions about it :))

@jantari
Copy link
Contributor

jantari commented Aug 22, 2020

@DHowett sorry for not getting back to you, the reason is I've had to read up on and utilize the console APIs in some of my own projects (like this or here) and am generally interested in applications and platform architecture and the odd ins and outs of how something really works and comes together, it's what I enjoy most at my job when I get to do it 😊

Good to know I'm not the only one!

@Johbii
Copy link

Johbii commented Mar 7, 2021

@DHowett so the issue stands that in order to fix we would need to push a fix to the included Windows PowerShell 5.1 or PSReadLine included in Windows 10?

@DHowett
Copy link
Member Author

DHowett commented Mar 7, 2021

@DHowett so the issue stands that in order to fix we would need to push a fix to the included Windows PowerShell 5.1 or PSReadLine included in Windows 10?

This is fixed in PSReadline in Insider builds of Windows. Problem is, though, that this is a bug with a very limited impact and an easy workaround... so there’s no reason to service it to earlier versions. 🤷🏻

ghost pushed a commit that referenced this pull request Jun 23, 2022
In #6810, we introduced a "quirk" for all known versions of PowerShell
that suppressed their requests for black background/gray foreground.
This was done to avoid an [issue in PSReadline] where it would paint
black bars all over the screen if the default background color wasn't
the same as the ANSI black color.

Years have passed since that quirk was introduced. The underlying bug
was fixed, and the fix was released broadly long ago. It's time for us
to remove the quirk... almost.

Terminal still runs on versions of Windows that ship a broken version of
PSReadline. We must maintain the quirk there -- the user can't do
anything about it, and we would make their experience worse if we
removed the quirk entirely.

PowerShell 7.0 also ships a broken version of PSReadline. It is still in
support for another 6 months, but updates have been available for some
time. We can encourage users to update.

Therefore, we only need the quirk for Windows PowerShell, and then only
for specific versions of Windows.

_Inside Windows_, we don't even need that: we're guaranteed to be built
alongside a fixed version of PowerShell!

Closes #6807

[issue in PSReadline]: PowerShell/PSReadLine#830 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-VT Virtual Terminal sequence support Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Conhost For issues in the Console codebase
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Black background in PowerShell commands
7 participants