mirror of
https://github.com/microsoft/terminal.git
synced 2025-12-10 00:48:23 -06:00
Add support for OSC 104, 110, 111, 112 and 117 (resets) (#18767)
This pull request adds support for resetting the various color table entries and xterm resource values back to their defaults. Building on the default color table James introduced in #17879, it was relatively straightforward to add support for resetting specific entries. This implementation cleaves tightly to observed behavior in xterm(379) rather than observed behavior in libvte(0.70.6). They differ in the following ways: - xterm rejects any OSC [110..119] with any number of parameters; libvte accepts it but only resets the first color. - When passed a list of color indices to reset in 104, xterm resets any colors up until the first one which fails to parse as an integer and does _not_ reset the rest; libvte resets all parseable color indices. I was unable to verify how these reset commands interact with colors set via `DECAC Assign Color` so I went with the implementation that made the most sense: - Resetting the background color with `110` also restores the background color alias entry to its pre-`DECAC` value; this results in the perceived background color returning to e.g. index 0 in conhost and the `background` color in Terminal. - _ibid._ for the foreground color Refs #18695 Refs #17879 Closes #3719
This commit is contained in:
parent
22c509f426
commit
5f311506dc
@ -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<size_t>(alias));
|
||||
}
|
||||
|
||||
void RenderSettings::RestoreDefaultColorAliasIndex(const ColorAlias alias) noexcept
|
||||
{
|
||||
gsl::at(_colorAliasIndices, static_cast<size_t>(alias)) = gsl::at(_defaultColorAliasIndices, static_cast<size_t>(alias));
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Calculates the RGB colors of a given text attribute, using the current
|
||||
// color table configuration and active render settings.
|
||||
|
||||
@ -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<COLORREF, COLORREF> GetAttributeColors(const TextAttribute& attr) const noexcept;
|
||||
std::pair<COLORREF, COLORREF> GetAttributeColorsWithAlpha(const TextAttribute& attr) const noexcept;
|
||||
COLORREF GetAttributeUnderlineColor(const TextAttribute& attr) const noexcept;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<ColorAlias>(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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<size_t>(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:
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -1163,7 +1163,8 @@ public:
|
||||
_hyperlinkMode{ false },
|
||||
_options{ s_cMaxOptions, static_cast<DispatchTypes::GraphicsOptions>(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<size_t> _xtermResourcesChanged;
|
||||
std::vector<DWORD> _xtermResourceValues;
|
||||
std::vector<size_t> _xtermResourcesRequested;
|
||||
std::vector<size_t> _xtermResourcesReset;
|
||||
bool _setColorTableEntry;
|
||||
std::vector<size_t> _colorTableEntriesRequested;
|
||||
bool _resetAllColors;
|
||||
std::vector<size_t> _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<StatefulDispatch>();
|
||||
auto pDispatch = dispatch.get();
|
||||
auto engine = std::make_unique<OutputStateMachineEngine>(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<StatefulDispatch>();
|
||||
auto pDispatch = dispatch.get();
|
||||
auto engine = std::make_unique<OutputStateMachineEngine>(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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user