diff --git a/src/renderer/base/RenderSettings.cpp b/src/renderer/base/RenderSettings.cpp index 0410211143..371b591b32 100644 --- a/src/renderer/base/RenderSettings.cpp +++ b/src/renderer/base/RenderSettings.cpp @@ -112,6 +112,20 @@ COLORREF RenderSettings::GetColorTableEntry(const size_t tableIndex) const return _colorTable.at(tableIndex); } +// Routine Description: +// - Restores all of the xterm-addressable colors to the ones saved in SaveDefaultSettings. +void RenderSettings::RestoreDefaultIndexed256ColorTable() +{ + std::copy_n(_defaultColorTable.begin(), 256, _colorTable.begin()); +} + +// Routine Description: +// - Restores a color table entry to the value saved in SaveDefaultSettings. +void RenderSettings::RestoreDefaultColorTableEntry(const size_t tableIndex) +{ + _colorTable.at(tableIndex) = _defaultColorTable.at(tableIndex); +} + // Routine Description: // - Sets the position in the color table for the given color alias and updates the color. // Arguments: @@ -159,6 +173,11 @@ size_t RenderSettings::GetColorAliasIndex(const ColorAlias alias) const noexcept return gsl::at(_colorAliasIndices, static_cast(alias)); } +void RenderSettings::RestoreDefaultColorAliasIndex(const ColorAlias alias) noexcept +{ + gsl::at(_colorAliasIndices, static_cast(alias)) = gsl::at(_defaultColorAliasIndices, static_cast(alias)); +} + // Routine Description: // - Calculates the RGB colors of a given text attribute, using the current // color table configuration and active render settings. diff --git a/src/renderer/inc/RenderSettings.hpp b/src/renderer/inc/RenderSettings.hpp index a9c370133c..84443889bd 100644 --- a/src/renderer/inc/RenderSettings.hpp +++ b/src/renderer/inc/RenderSettings.hpp @@ -37,10 +37,13 @@ namespace Microsoft::Console::Render void ResetColorTable() noexcept; void SetColorTableEntry(const size_t tableIndex, const COLORREF color); COLORREF GetColorTableEntry(const size_t tableIndex) const; + void RestoreDefaultIndexed256ColorTable(); + void RestoreDefaultColorTableEntry(const size_t tableIndex); void SetColorAlias(const ColorAlias alias, const size_t tableIndex, const COLORREF color); COLORREF GetColorAlias(const ColorAlias alias) const; void SetColorAliasIndex(const ColorAlias alias, const size_t tableIndex) noexcept; size_t GetColorAliasIndex(const ColorAlias alias) const noexcept; + void RestoreDefaultColorAliasIndex(const ColorAlias alias) noexcept; std::pair GetAttributeColors(const TextAttribute& attr) const noexcept; std::pair GetAttributeColorsWithAlpha(const TextAttribute& attr) const noexcept; COLORREF GetAttributeUnderlineColor(const TextAttribute& attr) const noexcept; diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index 1576571aa9..da24f71b6f 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -78,8 +78,11 @@ public: virtual void TabSet(const VTParameter setType) = 0; // DECST8C virtual void SetColorTableEntry(const size_t tableIndex, const DWORD color) = 0; // OSCSetColorTable virtual void RequestColorTableEntry(const size_t tableIndex) = 0; // OSCGetColorTable - virtual void SetXtermColorResource(const size_t resource, const DWORD color) = 0; // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor, OSCResetCursorColor + virtual void ResetColorTable() = 0; // OSCResetColorTable + virtual void ResetColorTableEntry(const size_t tableIndex) = 0; // OSCResetColorTable + virtual void SetXtermColorResource(const size_t resource, const DWORD color) = 0; // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor virtual void RequestXtermColorResource(const size_t resource) = 0; // OSCGetDefaultForeground, OSCGetDefaultBackground, OSCGetCursorColor + virtual void ResetXtermColorResource(const size_t resource) = 0; // OSCResetForegroundColor, OSCResetBackgroundColor, OSCResetCursorColor, OSCResetHighlightColor virtual void AssignColor(const DispatchTypes::ColorItem item, const VTInt fgIndex, const VTInt bgIndex) = 0; // DECAC virtual void EraseInDisplay(const DispatchTypes::EraseType eraseType) = 0; // ED diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index fe1b3c9a8a..9158b962ab 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -3292,6 +3292,40 @@ void AdaptDispatch::RequestColorTableEntry(const size_t tableIndex) } } +void AdaptDispatch::ResetColorTable() +{ + _renderSettings.RestoreDefaultIndexed256ColorTable(); + if (_renderer) + { + // This is pessimistic because it's unlikely that the frame or background changed, + // but let's tell the renderer that both changed anyway. + _renderer->TriggerRedrawAll(true, true); + } +} + +// Method Description: +// - Restores a single color table entry to its default user-specified value +// Arguments: +// - tableIndex: The VT color table index +void AdaptDispatch::ResetColorTableEntry(const size_t tableIndex) +{ + _renderSettings.RestoreDefaultColorTableEntry(tableIndex); + + if (_renderer) + { + // If we're updating the background color, we need to let the renderer + // know, since it may want to repaint the window background to match. + const auto backgroundIndex = _renderSettings.GetColorAliasIndex(ColorAlias::DefaultBackground); + const auto backgroundChanged = (tableIndex == backgroundIndex); + + // Similarly for the frame color, the tab may need to be repainted. + const auto frameIndex = _renderSettings.GetColorAliasIndex(ColorAlias::FrameBackground); + const auto frameChanged = (tableIndex == frameIndex); + + _renderer->TriggerRedrawAll(backgroundChanged, frameChanged); + } +} + // Method Description: // - Sets one Xterm Color Resource such as Default Foreground, Background, Cursor void AdaptDispatch::SetXtermColorResource(const size_t resource, const DWORD color) @@ -3338,6 +3372,25 @@ void AdaptDispatch::RequestXtermColorResource(const size_t resource) } } +// Method Description: +// - Restores to the original user-provided value one Xterm Color Resource such as Default Foreground, Background, Cursor +void AdaptDispatch::ResetXtermColorResource(const size_t resource) +{ + assert(resource >= 10); + const auto mappingIndex = resource - 10; + const auto& oscMapping = XtermResourceColorTableMappings.at(mappingIndex); + if (oscMapping.ColorTableIndex > 0) + { + if (oscMapping.AliasIndex >= 0) + { + // If this color reset applies to an aliased color, point the alias back at the original color + _renderSettings.RestoreDefaultColorAliasIndex(static_cast(oscMapping.AliasIndex)); + } + + ResetColorTableEntry(oscMapping.ColorTableIndex); + } +} + // Method Description: // DECAC - Assigns the foreground and background color indexes that should be // used for a given aspect of the user interface. diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 2f63e782ca..313611a732 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -133,8 +133,11 @@ namespace Microsoft::Console::VirtualTerminal void SetColorTableEntry(const size_t tableIndex, const DWORD color) override; // OSCSetColorTable void RequestColorTableEntry(const size_t tableIndex) override; // OSCGetColorTable - void SetXtermColorResource(const size_t resource, const DWORD color) override; // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor, OSCResetCursorColor + void ResetColorTable() override; // OSCResetColorTable + void ResetColorTableEntry(const size_t tableIndex) override; // OSCResetColorTable + void SetXtermColorResource(const size_t resource, const DWORD color) override; // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor void RequestXtermColorResource(const size_t resource) override; // OSCGetDefaultForeground, OSCGetDefaultBackground, OSCGetCursorColor + void ResetXtermColorResource(const size_t resource) override; // OSCResetForegroundColor, OSCResetBackgroundColor, OSCResetCursorColor, OSCResetHighlightColor void AssignColor(const DispatchTypes::ColorItem item, const VTInt fgIndex, const VTInt bgIndex) override; // DECAC void WindowManipulation(const DispatchTypes::WindowManipulationType function, diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index f6dab368f8..0f3908331b 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -71,8 +71,11 @@ public: void TabSet(const VTParameter /*setType*/) override {} // DECST8C void SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) override {} // OSCSetColorTable void RequestColorTableEntry(const size_t /*tableIndex*/) override {} // OSCGetColorTable - void SetXtermColorResource(const size_t /*resource*/, const DWORD /*color*/) override {} // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor, OSCResetCursorColor + void ResetColorTable() override {} // OSCResetColorTable + void ResetColorTableEntry(const size_t /*tableIndex*/) override {} // OSCResetColorTable + void SetXtermColorResource(const size_t /*resource*/, const DWORD /*color*/) override {} // OSCSetDefaultForeground, OSCSetDefaultBackground, OSCSetCursorColor void RequestXtermColorResource(const size_t /*resource*/) override {} // OSCGetDefaultForeground, OSCGetDefaultBackground, OSCGetCursorColor + void ResetXtermColorResource(const size_t /*resource*/) override {} // OSCResetForegroundColor, OSCResetBackgroundColor, OSCResetCursorColor, OSCResetHighlightColor void AssignColor(const DispatchTypes::ColorItem /*item*/, const VTInt /*fgIndex*/, const VTInt /*bgIndex*/) override {} // DECAC void EraseInDisplay(const DispatchTypes::EraseType /* eraseType*/) override {} // ED diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index c8a1367a26..4febc78ee8 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -810,10 +810,40 @@ bool OutputStateMachineEngine::ActionOscDispatch(const size_t parameter, const s } break; } - case OscActionCodes::ResetCursorColor: + case OscActionCodes::ResetColor: { - // The reset codes for xterm dynamic resources are the set codes + 100 - _dispatch->SetXtermColorResource(parameter - 100u, INVALID_COLOR); + if (string.empty()) + { + _dispatch->ResetColorTable(); + } + else + { + for (auto&& c : til::split_iterator{ string, L';' }) + { + if (const auto index{ til::parse_unsigned(c, 10) }; index) + { + _dispatch->ResetColorTableEntry(*index); + } + else + { + // NOTE: xterm stops at the first unparseable index whereas VTE keeps going. + break; + } + } + } + break; + } + case OscActionCodes::ResetForegroundColor: + case OscActionCodes::ResetBackgroundColor: + case OscActionCodes::ResetCursorColor: + case OscActionCodes::ResetHighlightColor: + { + // NOTE: xterm ignores the request if there's any parameters whereas VTE resets the provided index and ignores the rest + if (string.empty()) + { + // The reset codes for xterm dynamic resources are the set codes + 100 + _dispatch->ResetXtermColorResource(parameter - 100u); + } break; } case OscActionCodes::Hyperlink: diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index ab41e066cf..d36789e108 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -214,9 +214,11 @@ namespace Microsoft::Console::VirtualTerminal SetHighlightColor = 17, DECSWT_SetWindowTitle = 21, SetClipboard = 52, - ResetForegroundColor = 110, // Not implemented - ResetBackgroundColor = 111, // Not implemented + ResetColor = 104, + ResetForegroundColor = 110, + ResetBackgroundColor = 111, ResetCursorColor = 112, + ResetHighlightColor = 117, FinalTermAction = 133, VsCodeAction = 633, ITerm2Action = 1337, diff --git a/src/terminal/parser/ut_parser/OutputEngineTest.cpp b/src/terminal/parser/ut_parser/OutputEngineTest.cpp index 416ed6681d..f12dac966c 100644 --- a/src/terminal/parser/ut_parser/OutputEngineTest.cpp +++ b/src/terminal/parser/ut_parser/OutputEngineTest.cpp @@ -1163,7 +1163,8 @@ public: _hyperlinkMode{ false }, _options{ s_cMaxOptions, static_cast(s_uiGraphicsCleared) }, // fill with cleared option _colorTable{}, - _setColorTableEntry{ false } + _setColorTableEntry{ false }, + _resetAllColors{ false } { } @@ -1390,6 +1391,16 @@ public: _colorTableEntriesRequested.push_back(tableIndex); } + void ResetColorTable() noexcept override + { + _resetAllColors = true; + } + + void ResetColorTableEntry(const size_t tableIndex) noexcept override + { + _colorTableEntriesReset.push_back(tableIndex); + } + void SetXtermColorResource(const size_t resource, const DWORD color) override { _xtermResourcesChanged.push_back(resource); @@ -1401,6 +1412,11 @@ public: _xtermResourcesRequested.push_back(resource); } + void ResetXtermColorResource(const size_t resource) override + { + _xtermResourcesReset.push_back(resource); + } + void SetClipboard(wil::zwstring_view content) noexcept override { _copyContent = content; @@ -1476,8 +1492,11 @@ public: std::vector _xtermResourcesChanged; std::vector _xtermResourceValues; std::vector _xtermResourcesRequested; + std::vector _xtermResourcesReset; bool _setColorTableEntry; std::vector _colorTableEntriesRequested; + bool _resetAllColors; + std::vector _colorTableEntriesReset; bool _hyperlinkMode; std::wstring _copyContent; std::wstring _uri; @@ -3221,6 +3240,79 @@ class StateMachineExternalTest final pDispatch->ClearState(); } + TEST_METHOD(TestOscXtermResourceReset) + { + auto dispatch = std::make_unique(); + auto pDispatch = dispatch.get(); + auto engine = std::make_unique(std::move(dispatch)); + StateMachine mach(std::move(engine)); + + mach.ProcessString(L"\033]110\033\\"); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesChanged.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesRequested.size()); + VERIFY_ARE_EQUAL(1u, pDispatch->_xtermResourcesReset.size()); + VERIFY_ARE_EQUAL(10u, pDispatch->_xtermResourcesReset[0]); + pDispatch->ClearState(); + + mach.ProcessString(L"\033]111;\033\\"); // dangling ; + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesChanged.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesRequested.size()); + VERIFY_ARE_EQUAL(1u, pDispatch->_xtermResourcesReset.size()); + VERIFY_ARE_EQUAL(11u, pDispatch->_xtermResourcesReset[0]); + pDispatch->ClearState(); + + mach.ProcessString(L"\033]111;110\033\\"); + // NOTE: this is xterm behavior - ignore the entire sequence if any params exist + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesChanged.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesRequested.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesReset.size()); + pDispatch->ClearState(); + } + + TEST_METHOD(TestOscColorTableReset) + { + auto dispatch = std::make_unique(); + auto pDispatch = dispatch.get(); + auto engine = std::make_unique(std::move(dispatch)); + StateMachine mach(std::move(engine)); + + mach.ProcessString(L"\033]104\033\\"); + VERIFY_IS_TRUE(pDispatch->_resetAllColors); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesReset.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesRequested.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesReset.size()); + pDispatch->ClearState(); + + mach.ProcessString(L"\033]104;1;3;5;7;9\033\\"); + VERIFY_IS_FALSE(pDispatch->_resetAllColors); + VERIFY_ARE_EQUAL(5u, pDispatch->_colorTableEntriesReset.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesRequested.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesReset.size()); + VERIFY_ARE_EQUAL(1u, pDispatch->_colorTableEntriesReset[0]); + VERIFY_ARE_EQUAL(3u, pDispatch->_colorTableEntriesReset[1]); + VERIFY_ARE_EQUAL(5u, pDispatch->_colorTableEntriesReset[2]); + VERIFY_ARE_EQUAL(7u, pDispatch->_colorTableEntriesReset[3]); + VERIFY_ARE_EQUAL(9u, pDispatch->_colorTableEntriesReset[4]); + pDispatch->ClearState(); + + // NOTE: xterm behavior - stop after first failed parse + mach.ProcessString(L"\033]104;1;a;3\033\\"); + VERIFY_IS_FALSE(pDispatch->_resetAllColors); + VERIFY_IS_FALSE(pDispatch->_setColorTableEntry); + VERIFY_ARE_EQUAL(1u, pDispatch->_colorTableEntriesReset.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesRequested.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesReset.size()); + VERIFY_ARE_EQUAL(1u, pDispatch->_colorTableEntriesReset[0]); + pDispatch->ClearState(); + + mach.ProcessString(L"\033]104;;;\033\\"); + VERIFY_IS_FALSE(pDispatch->_setColorTableEntry); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesReset.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_colorTableEntriesRequested.size()); + VERIFY_ARE_EQUAL(0u, pDispatch->_xtermResourcesReset.size()); + pDispatch->ClearState(); + } + TEST_METHOD(TestOscSetWindowTitle) { BEGIN_TEST_METHOD_PROPERTIES()