Skip to content

Commit dfb5233

Browse files
authored
Remove VT color quirk for PowerShell (#17666)
Roughly 4 years ago we gave Windows Terminal the ability to differentiate between black/white and the default colors. One of the victims was PowerShell and most importantly PSReadLine, which emit SRG 37 & 40 when what they really want is 38 & 48. We fixed this on our side by adding a shim. Since the addition of VT passthrough in #17510 we now intentionally lost the ability to translate VT sequences from one thing to another. This meant we also lost the ability to do this shim and as such this PR removes it. Luckily Windows 11 now ships PSReadLine 2.0.0, which contains a proper fix for this. Unfortunately, this is not the case for Windows 10, which ships PSReadLine 2.0.0-beta2. Users affected by this will have to install a newer version of PSReadLine or use the default black/white theme. See 1bf4c08 Closes #13037
1 parent 5174c96 commit dfb5233

17 files changed

+23
-275
lines changed

src/buffer/out/TextAttribute.cpp

-41
Original file line numberDiff line numberDiff line change
@@ -65,47 +65,6 @@ void TextAttribute::SetLegacyDefaultAttributes(const WORD defaultAttributes) noe
6565
gsl::at(s_legacyBackgroundColorMap, s_legacyDefaultBackground) = TextColor{};
6666
}
6767

68-
// Routine Description:
69-
// Pursuant to GH#6807
70-
// This routine replaces VT colors from the 16-color set with the "default"
71-
// flag. It is intended to be used as part of the "VT Quirk" in
72-
// WriteConsole[AW].
73-
//
74-
// There is going to be a very long tail of applications that will
75-
// explicitly request VT SGR 40/37 when what they really want is to
76-
// SetConsoleTextAttribute() with a black background/white foreground.
77-
// Instead of making those applications look bad (and therefore making us
78-
// look bad, because we're releasing this as an update to something that
79-
// "looks good" already), we're introducing this compatibility hack. Before
80-
// the color reckoning in GH#6698 + GH#6506, *every* color was subject to
81-
// being spontaneously and erroneously turned into the default color. Now,
82-
// only the 16-color palette value that matches the active console
83-
// background color will be destroyed when the quirk is enabled.
84-
//
85-
// This is not intended to be a long-term solution. This comment will be
86-
// discovered in forty years(*) time and people will laugh at our hubris.
87-
//
88-
// *it doesn't matter when you're reading this, it will always be 40 years
89-
// from now.
90-
TextAttribute TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept
91-
{
92-
const auto fg{ attribute.GetForeground() };
93-
const auto bg{ attribute.GetBackground() };
94-
auto copy{ attribute };
95-
if (fg.IsIndex16() &&
96-
attribute.IsIntense() == WI_IsFlagSet(s_ansiDefaultForeground, FOREGROUND_INTENSITY) &&
97-
fg.GetIndex() == (s_ansiDefaultForeground & ~FOREGROUND_INTENSITY))
98-
{
99-
// We don't want to turn 1;37m into 39m (or even 1;39m), as this was meant to mimic a legacy color.
100-
copy.SetDefaultForeground();
101-
}
102-
if (bg.IsIndex16() && bg.GetIndex() == s_ansiDefaultBackground)
103-
{
104-
copy.SetDefaultBackground();
105-
}
106-
return copy;
107-
}
108-
10968
// Routine Description:
11069
// - Returns a WORD with legacy-style attributes for this textattribute.
11170
// Parameters:

src/buffer/out/TextAttribute.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ class TextAttribute final
9393
}
9494

9595
static void SetLegacyDefaultAttributes(const WORD defaultAttributes) noexcept;
96-
static TextAttribute StripErroneousVT16VersionsOfLegacyDefaults(const TextAttribute& attribute) noexcept;
9796
WORD GetLegacyAttributes() const noexcept;
9897

9998
bool IsTopHorizontalDisplayed() const noexcept;

src/host/ApiRoutines.h

-2
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,11 @@ class ApiRoutines : public IApiRoutines
7272
[[nodiscard]] HRESULT WriteConsoleAImpl(IConsoleOutputObject& context,
7373
const std::string_view buffer,
7474
size_t& read,
75-
bool requiresVtQuirk,
7675
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
7776

7877
[[nodiscard]] HRESULT WriteConsoleWImpl(IConsoleOutputObject& context,
7978
const std::wstring_view buffer,
8079
size_t& read,
81-
bool requiresVtQuirk,
8280
std::unique_ptr<IWaitRoutine>& waiter) noexcept override;
8381

8482
#pragma region ThreadCreationInfo

src/host/_stream.cpp

+4-20
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,6 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo)
406406
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(*pcbBuffer) PCWCHAR pwchBuffer,
407407
_Inout_ size_t* const pcbBuffer,
408408
SCREEN_INFORMATION& screenInfo,
409-
bool requiresVtQuirk,
410409
std::unique_ptr<WriteData>& waiter)
411410
try
412411
{
@@ -416,22 +415,10 @@ try
416415
waiter = std::make_unique<WriteData>(screenInfo,
417416
pwchBuffer,
418417
*pcbBuffer,
419-
gci.OutputCP,
420-
requiresVtQuirk);
418+
gci.OutputCP);
421419
return CONSOLE_STATUS_WAIT;
422420
}
423421

424-
const auto restoreVtQuirk = wil::scope_exit([&]() {
425-
if (requiresVtQuirk)
426-
{
427-
screenInfo.ResetIgnoreLegacyEquivalentVTAttributes();
428-
}
429-
});
430-
if (requiresVtQuirk)
431-
{
432-
screenInfo.SetIgnoreLegacyEquivalentVTAttributes();
433-
}
434-
435422
const std::wstring_view str{ pwchBuffer, *pcbBuffer / sizeof(WCHAR) };
436423

437424
if (WI_IsAnyFlagClear(screenInfo.OutputMode, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT))
@@ -464,7 +451,6 @@ NT_CATCH_RETURN()
464451
[[nodiscard]] HRESULT WriteConsoleWImplHelper(IConsoleOutputObject& context,
465452
const std::wstring_view buffer,
466453
size_t& read,
467-
bool requiresVtQuirk,
468454
std::unique_ptr<WriteData>& waiter) noexcept
469455
{
470456
try
@@ -477,7 +463,7 @@ NT_CATCH_RETURN()
477463
size_t cbTextBufferLength;
478464
RETURN_IF_FAILED(SizeTMult(buffer.size(), sizeof(wchar_t), &cbTextBufferLength));
479465

480-
auto Status = DoWriteConsole(const_cast<wchar_t*>(buffer.data()), &cbTextBufferLength, context, requiresVtQuirk, waiter);
466+
auto Status = DoWriteConsole(const_cast<wchar_t*>(buffer.data()), &cbTextBufferLength, context, waiter);
481467

482468
// Convert back from bytes to characters for the resulting string length written.
483469
read = cbTextBufferLength / sizeof(wchar_t);
@@ -510,7 +496,6 @@ NT_CATCH_RETURN()
510496
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleAImpl(IConsoleOutputObject& context,
511497
const std::string_view buffer,
512498
size_t& read,
513-
bool requiresVtQuirk,
514499
std::unique_ptr<IWaitRoutine>& waiter) noexcept
515500
{
516501
try
@@ -622,7 +607,7 @@ NT_CATCH_RETURN()
622607

623608
// Make the W version of the call
624609
size_t wcBufferWritten{};
625-
const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, requiresVtQuirk, writeDataWaiter) };
610+
const auto hr{ WriteConsoleWImplHelper(screenInfo, wstr, wcBufferWritten, writeDataWaiter) };
626611

627612
// If there is no waiter, process the byte count now.
628613
if (nullptr == writeDataWaiter.get())
@@ -700,7 +685,6 @@ NT_CATCH_RETURN()
700685
[[nodiscard]] HRESULT ApiRoutines::WriteConsoleWImpl(IConsoleOutputObject& context,
701686
const std::wstring_view buffer,
702687
size_t& read,
703-
bool requiresVtQuirk,
704688
std::unique_ptr<IWaitRoutine>& waiter) noexcept
705689
{
706690
try
@@ -709,7 +693,7 @@ NT_CATCH_RETURN()
709693
auto unlock = wil::scope_exit([&] { UnlockConsole(); });
710694

711695
std::unique_ptr<WriteData> writeDataWaiter;
712-
RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, requiresVtQuirk, writeDataWaiter));
696+
RETURN_IF_FAILED(WriteConsoleWImplHelper(context.GetActiveBuffer(), buffer, read, writeDataWaiter));
713697

714698
// Transfer specific waiter pointer into the generic interface wrapper.
715699
waiter.reset(writeDataWaiter.release());

src/host/_stream.h

-1
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,4 @@ void WriteClearScreen(SCREEN_INFORMATION& screenInfo);
2828
[[nodiscard]] NTSTATUS DoWriteConsole(_In_reads_bytes_(pcbBuffer) const wchar_t* pwchBuffer,
2929
_Inout_ size_t* const pcbBuffer,
3030
SCREEN_INFORMATION& screenInfo,
31-
bool requiresVtQuirk,
3231
std::unique_ptr<WriteData>& waiter);

src/host/screenInfo.cpp

+1-23
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ SCREEN_INFORMATION::SCREEN_INFORMATION(
4141
_PopupAttributes{ popupAttributes },
4242
_virtualBottom{ 0 },
4343
_currentFont{ fontInfo },
44-
_desiredFont{ fontInfo },
45-
_ignoreLegacyEquivalentVTAttributes{ false }
44+
_desiredFont{ fontInfo }
4645
{
4746
// Check if VT mode should be enabled by default. This can be true if
4847
// VirtualTerminalLevel is set to !=0 in the registry, or when conhost
@@ -2014,13 +2013,6 @@ const TextAttribute& SCREEN_INFORMATION::GetPopupAttributes() const noexcept
20142013
// <none>
20152014
void SCREEN_INFORMATION::SetAttributes(const TextAttribute& attributes)
20162015
{
2017-
if (_ignoreLegacyEquivalentVTAttributes)
2018-
{
2019-
// See the comment on StripErroneousVT16VersionsOfLegacyDefaults for more info.
2020-
_textBuffer->SetCurrentAttributes(TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults(attributes));
2021-
return;
2022-
}
2023-
20242016
_textBuffer->SetCurrentAttributes(attributes);
20252017

20262018
// If we're an alt buffer, DON'T propagate this setting up to the main buffer.
@@ -2466,17 +2458,3 @@ const FontInfoDesired& SCREEN_INFORMATION::GetDesiredFont() const noexcept
24662458
{
24672459
return _desiredFont;
24682460
}
2469-
2470-
// Routine Description:
2471-
// - Engages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults
2472-
void SCREEN_INFORMATION::SetIgnoreLegacyEquivalentVTAttributes() noexcept
2473-
{
2474-
_ignoreLegacyEquivalentVTAttributes = true;
2475-
}
2476-
2477-
// Routine Description:
2478-
// - Disengages the legacy VT handling quirk; see TextAttribute::StripErroneousVT16VersionsOfLegacyDefaults
2479-
void SCREEN_INFORMATION::ResetIgnoreLegacyEquivalentVTAttributes() noexcept
2480-
{
2481-
_ignoreLegacyEquivalentVTAttributes = false;
2482-
}

src/host/screenInfo.hpp

-5
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,6 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
213213
FontInfoDesired& GetDesiredFont() noexcept;
214214
const FontInfoDesired& GetDesiredFont() const noexcept;
215215

216-
void SetIgnoreLegacyEquivalentVTAttributes() noexcept;
217-
void ResetIgnoreLegacyEquivalentVTAttributes() noexcept;
218-
219216
[[nodiscard]] NTSTATUS ResizeWithReflow(const til::size coordnewScreenSize);
220217
[[nodiscard]] NTSTATUS ResizeTraditional(const til::size coordNewScreenSize);
221218

@@ -277,8 +274,6 @@ class SCREEN_INFORMATION : public ConsoleObjectHeader, public Microsoft::Console
277274
// the viewport to move (SetBufferInfo, WriteConsole, etc)
278275
til::CoordType _virtualBottom;
279276

280-
bool _ignoreLegacyEquivalentVTAttributes;
281-
282277
std::optional<til::size> _deferredPtyResize{ std::nullopt };
283278

284279
static void _handleDeferredResize(SCREEN_INFORMATION& siMain);

src/host/ut_host/ApiRoutinesTests.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ class ApiRoutinesTests
385385
const auto cchWriteLength = std::min(cchIncrement, cchTestText - i);
386386

387387
// Run the test method
388-
const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, false, waiter);
388+
const auto hr = _pApiRoutines->WriteConsoleAImpl(si, { pszTestText + i, cchWriteLength }, cchRead, waiter);
389389

390390
VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing.");
391391
if (!fInduceWait)
@@ -441,7 +441,7 @@ class ApiRoutinesTests
441441

442442
size_t cchRead = 0;
443443
std::unique_ptr<IWaitRoutine> waiter;
444-
const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, false, waiter);
444+
const auto hr = _pApiRoutines->WriteConsoleWImpl(si, testText, cchRead, waiter);
445445

446446
VERIFY_ARE_EQUAL(S_OK, hr, L"Successful result code from writing.");
447447
if (!fInduceWait)

0 commit comments

Comments
 (0)