From ba6f1e905d74a4f968648709398fa46cbca92442 Mon Sep 17 00:00:00 2001 From: James Holderness Date: Wed, 24 Jan 2024 12:02:16 +0000 Subject: [PATCH] Add support for the DECST8C escape sequence (#16534) ## Summary of the Pull Request This PR adds support for the `DECST8C` escape sequence, which resets the tab stops to every 8 columns. ## Detailed Description of the Pull Request / Additional comments This is actually a private parameter variant of the ANSI `CTC` sequence (Cursor Tabulation Control), which accepts a selective parameter which specifies the type of tab operation to be performed. But the DEC variant only defines a single parameter value (5), which resets all tab stops. It also considers an omitted parameter to be the equivalent of 5, so we support that too. ## Validation Steps Performed I've extended the existing tab stop tests in `ScreenBufferTests` with some basic coverage of this sequence. I've also manually verified that the `DECTABSR` script in #14984 now passes the `DECST8C` portion of the test. ## PR Checklist - [x] Closes #16533 - [x] Tests added/passed (cherry picked from commit f5898886be71dea351cead9a7cf3957e5da4dd19) Service-Card-Id: 91631721 Service-Version: 1.19 --- .github/actions/spelling/expect/expect.txt | 1 + src/host/ut_host/ScreenBufferTests.cpp | 10 +++++++++ src/terminal/adapter/DispatchTypes.hpp | 5 +++++ src/terminal/adapter/ITermDispatch.hpp | 1 + src/terminal/adapter/adaptDispatch.cpp | 21 ++++++++++++------- src/terminal/adapter/adaptDispatch.hpp | 4 ++-- src/terminal/adapter/termDispatch.hpp | 1 + .../parser/OutputStateMachineEngine.cpp | 5 +++++ .../parser/OutputStateMachineEngine.hpp | 1 + 9 files changed, 40 insertions(+), 9 deletions(-) diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt index d31bc7800f4..c141433d7af 100644 --- a/.github/actions/spelling/expect/expect.txt +++ b/.github/actions/spelling/expect/expect.txt @@ -464,6 +464,7 @@ DECSLPP DECSLRM DECSMKR DECSR +DECST DECSTBM DECSTGLT DECSTR diff --git a/src/host/ut_host/ScreenBufferTests.cpp b/src/host/ut_host/ScreenBufferTests.cpp index 985fcadf343..d6687e19bd6 100644 --- a/src/host/ut_host/ScreenBufferTests.cpp +++ b/src/host/ut_host/ScreenBufferTests.cpp @@ -604,6 +604,16 @@ void ScreenBufferTests::TestResetClearTabStops() stateMachine.ProcessString(resetToInitialState); expectedStops = { 8, 16, 24, 32, 40, 48, 56, 64, 72 }; VERIFY_ARE_EQUAL(expectedStops, _GetTabStops(screenInfo)); + + Log::Comment(L"DECST8C with 5 parameter resets tabs to defaults."); + stateMachine.ProcessString(clearTabStops); + stateMachine.ProcessString(L"\033[?5W"); + VERIFY_ARE_EQUAL(expectedStops, _GetTabStops(screenInfo)); + + Log::Comment(L"DECST8C with omitted parameter resets tabs to defaults."); + stateMachine.ProcessString(clearTabStops); + stateMachine.ProcessString(L"\033[?W"); + VERIFY_ARE_EQUAL(expectedStops, _GetTabStops(screenInfo)); } void ScreenBufferTests::TestAddTabStop() diff --git a/src/terminal/adapter/DispatchTypes.hpp b/src/terminal/adapter/DispatchTypes.hpp index 539dfb8f277..a0cabb0fde8 100644 --- a/src/terminal/adapter/DispatchTypes.hpp +++ b/src/terminal/adapter/DispatchTypes.hpp @@ -565,6 +565,11 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes ClearAllColumns = 3 }; + enum TabSetType : VTInt + { + SetEvery8Columns = 5 + }; + enum WindowManipulationType : VTInt { Invalid = 0, diff --git a/src/terminal/adapter/ITermDispatch.hpp b/src/terminal/adapter/ITermDispatch.hpp index 9221ea3cb4f..1b847d32ba0 100644 --- a/src/terminal/adapter/ITermDispatch.hpp +++ b/src/terminal/adapter/ITermDispatch.hpp @@ -68,6 +68,7 @@ class Microsoft::Console::VirtualTerminal::ITermDispatch virtual bool ForwardTab(const VTInt numTabs) = 0; // CHT, HT virtual bool BackwardsTab(const VTInt numTabs) = 0; // CBT virtual bool TabClear(const DispatchTypes::TabClearType clearType) = 0; // TBC + virtual bool TabSet(const VTParameter setType) = 0; // DECST8C virtual bool SetColorTableEntry(const size_t tableIndex, const DWORD color) = 0; // OSCColorTable virtual bool SetDefaultForeground(const DWORD color) = 0; // OSCDefaultForeground virtual bool SetDefaultBackground(const DWORD color) = 0; // OSCDefaultBackground diff --git a/src/terminal/adapter/adaptDispatch.cpp b/src/terminal/adapter/adaptDispatch.cpp index 4bd60116c8e..b6e07b77ffb 100644 --- a/src/terminal/adapter/adaptDispatch.cpp +++ b/src/terminal/adapter/adaptDispatch.cpp @@ -2822,16 +2822,23 @@ void AdaptDispatch::_ClearAllTabStops() noexcept } // Routine Description: -// - Clears all tab stops and sets the _initDefaultTabStops flag to indicate +// - DECST8C - If the parameter is SetEvery8Columns or is omitted, then this +// clears all tab stops and sets the _initDefaultTabStops flag to indicate // that the default positions should be reinitialized when needed. // Arguments: -// - +// - setType - only SetEvery8Columns is supported // Return value: -// - -void AdaptDispatch::_ResetTabStops() noexcept +// - True if handled successfully. False otherwise. +bool AdaptDispatch::TabSet(const VTParameter setType) noexcept { - _tabStopColumns.clear(); - _initDefaultTabStops = true; + constexpr auto SetEvery8Columns = DispatchTypes::TabSetType::SetEvery8Columns; + if (setType.value_or(SetEvery8Columns) == SetEvery8Columns) + { + _tabStopColumns.clear(); + _initDefaultTabStops = true; + return true; + } + return false; } // Routine Description: @@ -3105,7 +3112,7 @@ bool AdaptDispatch::HardReset() _api.GetTextBuffer().GetCursor().SetBlinkingAllowed(true); // Delete all current tab stops and reapply - _ResetTabStops(); + TabSet(DispatchTypes::TabSetType::SetEvery8Columns); // Clear the soft font in the renderer and delete the font buffer. _renderer.UpdateSoftFont({}, {}, false); diff --git a/src/terminal/adapter/adaptDispatch.hpp b/src/terminal/adapter/adaptDispatch.hpp index 1f23f134c97..0a24d01577d 100644 --- a/src/terminal/adapter/adaptDispatch.hpp +++ b/src/terminal/adapter/adaptDispatch.hpp @@ -105,6 +105,7 @@ namespace Microsoft::Console::VirtualTerminal bool ForwardTab(const VTInt numTabs) override; // CHT, HT bool BackwardsTab(const VTInt numTabs) override; // CBT bool TabClear(const DispatchTypes::TabClearType clearType) override; // TBC + bool TabSet(const VTParameter setType) noexcept override; // DECST8C bool DesignateCodingSystem(const VTID codingSystem) override; // DOCS bool Designate94Charset(const VTInt gsetNumber, const VTID charset) override; // SCS bool Designate96Charset(const VTInt gsetNumber, const VTID charset) override; // SCS @@ -251,7 +252,6 @@ namespace Microsoft::Console::VirtualTerminal void _ClearSingleTabStop(); void _ClearAllTabStops() noexcept; - void _ResetTabStops() noexcept; void _InitTabStopsForWidth(const VTInt width); StringHandler _RestoreColorTable(); @@ -271,7 +271,7 @@ namespace Microsoft::Console::VirtualTerminal StringHandler _CreateDrcsPassthroughHandler(const DispatchTypes::DrcsCharsetSize charsetSize); StringHandler _CreatePassthroughHandler(); - std::vector _tabStopColumns; + std::vector _tabStopColumns; bool _initDefaultTabStops = true; ITerminalApi& _api; diff --git a/src/terminal/adapter/termDispatch.hpp b/src/terminal/adapter/termDispatch.hpp index 4f11ae8bb93..122b48820bb 100644 --- a/src/terminal/adapter/termDispatch.hpp +++ b/src/terminal/adapter/termDispatch.hpp @@ -61,6 +61,7 @@ class Microsoft::Console::VirtualTerminal::TermDispatch : public Microsoft::Cons bool ForwardTab(const VTInt /*numTabs*/) override { return false; } // CHT, HT bool BackwardsTab(const VTInt /*numTabs*/) override { return false; } // CBT bool TabClear(const DispatchTypes::TabClearType /*clearType*/) override { return false; } // TBC + bool TabSet(const VTParameter /*setType*/) override { return false; } // DECST8C bool SetColorTableEntry(const size_t /*tableIndex*/, const DWORD /*color*/) override { return false; } // OSCColorTable bool SetDefaultForeground(const DWORD /*color*/) override { return false; } // OSCDefaultForeground bool SetDefaultBackground(const DWORD /*color*/) override { return false; } // OSCDefaultBackground diff --git a/src/terminal/parser/OutputStateMachineEngine.cpp b/src/terminal/parser/OutputStateMachineEngine.cpp index 70352c4b764..9d247bfc4fe 100644 --- a/src/terminal/parser/OutputStateMachineEngine.cpp +++ b/src/terminal/parser/OutputStateMachineEngine.cpp @@ -566,6 +566,11 @@ bool OutputStateMachineEngine::ActionCsiDispatch(const VTID id, const VTParamete return _dispatch->TabClear(clearType); }); break; + case CsiActionCodes::DECST8C_SetTabEvery8Columns: + success = parameters.for_each([&](const auto setType) { + return _dispatch->TabSet(setType); + }); + break; case CsiActionCodes::ECH_EraseCharacters: success = _dispatch->EraseCharacters(parameters.at(0)); break; diff --git a/src/terminal/parser/OutputStateMachineEngine.hpp b/src/terminal/parser/OutputStateMachineEngine.hpp index 8f3f72b9cb6..32105133bf3 100644 --- a/src/terminal/parser/OutputStateMachineEngine.hpp +++ b/src/terminal/parser/OutputStateMachineEngine.hpp @@ -121,6 +121,7 @@ namespace Microsoft::Console::VirtualTerminal DCH_DeleteCharacter = VTID("P"), SU_ScrollUp = VTID("S"), SD_ScrollDown = VTID("T"), + DECST8C_SetTabEvery8Columns = VTID("?W"), ECH_EraseCharacters = VTID("X"), CBT_CursorBackTab = VTID("Z"), HPA_HorizontalPositionAbsolute = VTID("`"),