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 f5898886be)
Service-Card-Id: 91631721
Service-Version: 1.19
This commit is contained in:
James Holderness 2024-01-24 12:02:16 +00:00 committed by Dustin L. Howett
parent bc452c61dc
commit ba6f1e905d
9 changed files with 40 additions and 9 deletions

View File

@ -464,6 +464,7 @@ DECSLPP
DECSLRM
DECSMKR
DECSR
DECST
DECSTBM
DECSTGLT
DECSTR

View File

@ -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()

View File

@ -565,6 +565,11 @@ namespace Microsoft::Console::VirtualTerminal::DispatchTypes
ClearAllColumns = 3
};
enum TabSetType : VTInt
{
SetEvery8Columns = 5
};
enum WindowManipulationType : VTInt
{
Invalid = 0,

View File

@ -68,6 +68,7 @@ public:
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

View File

@ -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:
// - <none>
// - setType - only SetEvery8Columns is supported
// Return value:
// - <none>
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);

View File

@ -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<bool> _tabStopColumns;
std::vector<uint8_t> _tabStopColumns;
bool _initDefaultTabStops = true;
ITerminalApi& _api;

View File

@ -61,6 +61,7 @@ public:
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

View File

@ -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;

View File

@ -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("`"),