Initial Implementation for tab stops in TerminalDispatch (#9597)
* [x] Supports #1883 * [X] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed
This commit is contained in:
parent
05e7ea1423
commit
b68ee23bf8
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "../../terminal/adapter/DispatchTypes.hpp"
|
||||
#include "../../buffer/out/TextAttribute.hpp"
|
||||
#include "../../types/inc/Viewport.hpp"
|
||||
|
||||
namespace Microsoft::Terminal::Core
|
||||
{
|
||||
|
@ -22,6 +23,7 @@ namespace Microsoft::Terminal::Core
|
|||
virtual TextAttribute GetTextAttributes() const noexcept = 0;
|
||||
virtual void SetTextAttributes(const TextAttribute& attrs) noexcept = 0;
|
||||
|
||||
virtual Microsoft::Console::Types::Viewport GetBufferSize() noexcept = 0;
|
||||
virtual bool SetCursorPosition(short x, short y) noexcept = 0;
|
||||
virtual COORD GetCursorPosition() noexcept = 0;
|
||||
virtual bool SetCursorVisibility(const bool visible) noexcept = 0;
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
bool ExecuteChar(wchar_t wch) noexcept override;
|
||||
TextAttribute GetTextAttributes() const noexcept override;
|
||||
void SetTextAttributes(const TextAttribute& attrs) noexcept override;
|
||||
Microsoft::Console::Types::Viewport GetBufferSize() noexcept override;
|
||||
bool SetCursorPosition(short x, short y) noexcept override;
|
||||
COORD GetCursorPosition() noexcept override;
|
||||
bool SetCursorVisibility(const bool visible) noexcept override;
|
||||
|
|
|
@ -36,6 +36,11 @@ void Terminal::SetTextAttributes(const TextAttribute& attrs) noexcept
|
|||
_buffer->SetCurrentAttributes(attrs);
|
||||
}
|
||||
|
||||
Viewport Terminal::GetBufferSize() noexcept
|
||||
{
|
||||
return _buffer->GetSize();
|
||||
}
|
||||
|
||||
bool Terminal::SetCursorPosition(short x, short y) noexcept
|
||||
try
|
||||
{
|
||||
|
|
|
@ -134,6 +134,74 @@ try
|
|||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
|
||||
bool TerminalDispatch::HorizontalTabSet() noexcept
|
||||
{
|
||||
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
|
||||
const auto column = _terminalApi.GetCursorPosition().X;
|
||||
|
||||
_InitTabStopsForWidth(width);
|
||||
_tabStopColumns.at(column) = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminalDispatch::ForwardTab(const size_t numTabs) noexcept
|
||||
{
|
||||
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
|
||||
const auto cursorPosition = _terminalApi.GetCursorPosition();
|
||||
auto column = cursorPosition.X;
|
||||
const auto row = cursorPosition.Y;
|
||||
auto tabsPerformed = 0u;
|
||||
_InitTabStopsForWidth(width);
|
||||
while (column + 1 < width && tabsPerformed < numTabs)
|
||||
{
|
||||
column++;
|
||||
if (til::at(_tabStopColumns, column))
|
||||
{
|
||||
tabsPerformed++;
|
||||
}
|
||||
}
|
||||
|
||||
return _terminalApi.SetCursorPosition(column, row);
|
||||
}
|
||||
|
||||
bool TerminalDispatch::BackwardsTab(const size_t numTabs) noexcept
|
||||
{
|
||||
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
|
||||
const auto cursorPosition = _terminalApi.GetCursorPosition();
|
||||
auto column = cursorPosition.X;
|
||||
const auto row = cursorPosition.Y;
|
||||
auto tabsPerformed = 0u;
|
||||
_InitTabStopsForWidth(width);
|
||||
while (column > 0 && tabsPerformed < numTabs)
|
||||
{
|
||||
column--;
|
||||
if (til::at(_tabStopColumns, column))
|
||||
{
|
||||
tabsPerformed++;
|
||||
}
|
||||
}
|
||||
|
||||
return _terminalApi.SetCursorPosition(column, row);
|
||||
}
|
||||
|
||||
bool TerminalDispatch::TabClear(const DispatchTypes::TabClearType clearType) noexcept
|
||||
{
|
||||
bool success = false;
|
||||
switch (clearType)
|
||||
{
|
||||
case DispatchTypes::TabClearType::ClearCurrentColumn:
|
||||
success = _ClearSingleTabStop();
|
||||
break;
|
||||
case DispatchTypes::TabClearType::ClearAllColumns:
|
||||
success = _ClearAllTabStops();
|
||||
break;
|
||||
default:
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Sets a single entry of the colortable to a new value
|
||||
// Arguments:
|
||||
|
@ -550,6 +618,48 @@ bool TerminalDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param,
|
|||
return success;
|
||||
}
|
||||
|
||||
bool TerminalDispatch::_ClearSingleTabStop() noexcept
|
||||
{
|
||||
const auto width = _terminalApi.GetBufferSize().Dimensions().X;
|
||||
const auto column = _terminalApi.GetCursorPosition().X;
|
||||
|
||||
_InitTabStopsForWidth(width);
|
||||
_tabStopColumns.at(column) = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminalDispatch::_ClearAllTabStops() noexcept
|
||||
{
|
||||
_tabStopColumns.clear();
|
||||
_initDefaultTabStops = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TerminalDispatch::_ResetTabStops() noexcept
|
||||
{
|
||||
_tabStopColumns.clear();
|
||||
_initDefaultTabStops = true;
|
||||
}
|
||||
|
||||
void TerminalDispatch::_InitTabStopsForWidth(const size_t width)
|
||||
{
|
||||
const auto initialWidth = _tabStopColumns.size();
|
||||
if (width > initialWidth)
|
||||
{
|
||||
_tabStopColumns.resize(width);
|
||||
if (_initDefaultTabStops)
|
||||
{
|
||||
for (auto column = 8u; column < _tabStopColumns.size(); column += 8)
|
||||
{
|
||||
if (column >= initialWidth)
|
||||
{
|
||||
til::at(_tabStopColumns, column) = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TerminalDispatch::SoftReset() noexcept
|
||||
{
|
||||
// TODO:GH#1883 much of this method is not yet implemented in the Terminal,
|
||||
|
@ -623,8 +733,8 @@ bool TerminalDispatch::HardReset() noexcept
|
|||
// Cursor to 1,1 - the Soft Reset guarantees this is absolute
|
||||
success = CursorPosition(1, 1) && success;
|
||||
|
||||
// // Delete all current tab stops and reapply
|
||||
// _ResetTabStops();
|
||||
// Delete all current tab stops and reapply
|
||||
_ResetTabStops();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ public:
|
|||
bool CarriageReturn() noexcept override;
|
||||
bool SetWindowTitle(std::wstring_view title) noexcept override;
|
||||
|
||||
bool HorizontalTabSet() noexcept override; // HTS
|
||||
bool ForwardTab(const size_t numTabs) noexcept override; // CHT, HT
|
||||
bool BackwardsTab(const size_t numTabs) noexcept override; // CBT
|
||||
bool TabClear(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::TabClearType clearType) noexcept override; // TBC
|
||||
|
||||
bool SetColorTableEntry(const size_t tableIndex, const DWORD color) noexcept override;
|
||||
bool SetCursorStyle(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::CursorStyle cursorStyle) noexcept override;
|
||||
bool SetCursorColor(const DWORD color) noexcept override;
|
||||
|
@ -79,9 +84,17 @@ public:
|
|||
private:
|
||||
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;
|
||||
|
||||
std::vector<bool> _tabStopColumns;
|
||||
bool _initDefaultTabStops = true;
|
||||
|
||||
size_t _SetRgbColorsHelper(const ::Microsoft::Console::VirtualTerminal::VTParameters options,
|
||||
TextAttribute& attr,
|
||||
const bool isForeground) noexcept;
|
||||
|
||||
bool _ModeParamsHelper(const ::Microsoft::Console::VirtualTerminal::DispatchTypes::ModeParams param, const bool enable) noexcept;
|
||||
|
||||
bool _ClearSingleTabStop() noexcept;
|
||||
bool _ClearAllTabStops() noexcept;
|
||||
void _ResetTabStops() noexcept;
|
||||
void _InitTabStopsForWidth(const size_t width);
|
||||
};
|
||||
|
|
|
@ -41,6 +41,16 @@ class TerminalCoreUnitTests::TerminalBufferTests final
|
|||
|
||||
TEST_METHOD(DontSnapToOutputTest);
|
||||
|
||||
TEST_METHOD(TestResetClearTabStops);
|
||||
|
||||
TEST_METHOD(TestAddTabStop);
|
||||
|
||||
TEST_METHOD(TestClearTabStop);
|
||||
|
||||
TEST_METHOD(TestGetForwardTab);
|
||||
|
||||
TEST_METHOD(TestGetReverseTab);
|
||||
|
||||
TEST_METHOD_SETUP(MethodSetup)
|
||||
{
|
||||
// STEP 1: Set up the Terminal
|
||||
|
@ -56,6 +66,9 @@ class TerminalCoreUnitTests::TerminalBufferTests final
|
|||
}
|
||||
|
||||
private:
|
||||
void _SetTabStops(std::list<short> columns, bool replace);
|
||||
std::list<short> _GetTabStops();
|
||||
|
||||
DummyRenderTarget emptyRT;
|
||||
std::unique_ptr<Terminal> term;
|
||||
};
|
||||
|
@ -233,3 +246,349 @@ void TerminalBufferTests::DontSnapToOutputTest()
|
|||
VERIFY_ARE_EQUAL(TerminalViewHeight, seventhView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(TerminalHistoryLength, term->_scrollOffset);
|
||||
}
|
||||
|
||||
void TerminalBufferTests::_SetTabStops(std::list<short> columns, bool replace)
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
const auto clearTabStops = L"\033[3g";
|
||||
const auto addTabStop = L"\033H";
|
||||
|
||||
if (replace)
|
||||
{
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
|
||||
for (auto column : columns)
|
||||
{
|
||||
cursor.SetXPosition(column);
|
||||
termSm.ProcessString(addTabStop);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<short> TerminalBufferTests::_GetTabStops()
|
||||
{
|
||||
std::list<short> columns;
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
const auto initialView = term->GetViewport();
|
||||
const auto lastColumn = initialView.RightInclusive();
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
cursor.SetPosition({ 0, 0 });
|
||||
for (;;)
|
||||
{
|
||||
termSm.ProcessCharacter(L'\t');
|
||||
auto column = cursor.GetPosition().X;
|
||||
if (column >= lastColumn)
|
||||
{
|
||||
break;
|
||||
}
|
||||
columns.push_back(column);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
void TerminalBufferTests::TestResetClearTabStops()
|
||||
{
|
||||
auto& termSm = *term->_stateMachine;
|
||||
const auto initialView = term->GetViewport();
|
||||
|
||||
const auto clearTabStops = L"\033[3g";
|
||||
const auto resetToInitialState = L"\033c";
|
||||
|
||||
Log::Comment(L"Default tabs every 8 columns.");
|
||||
std::list<short> expectedStops{ 8, 16, 24, 32, 40, 48, 56, 64, 72 };
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Clear all tabs.");
|
||||
termSm.ProcessString(clearTabStops);
|
||||
expectedStops = {};
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"RIS resets tabs to defaults.");
|
||||
termSm.ProcessString(resetToInitialState);
|
||||
expectedStops = { 8, 16, 24, 32, 40, 48, 56, 64, 72 };
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
}
|
||||
|
||||
void TerminalBufferTests::TestAddTabStop()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
const auto clearTabStops = L"\033[3g";
|
||||
const auto addTabStop = L"\033H";
|
||||
|
||||
Log::Comment(L"Clear all tabs.");
|
||||
termSm.ProcessString(clearTabStops);
|
||||
std::list<short> expectedStops{};
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Add tab to empty list.");
|
||||
cursor.SetXPosition(12);
|
||||
termSm.ProcessString(addTabStop);
|
||||
expectedStops.push_back(12);
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Add tab to head of existing list.");
|
||||
cursor.SetXPosition(4);
|
||||
termSm.ProcessString(addTabStop);
|
||||
expectedStops.push_front(4);
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Add tab to tail of existing list.");
|
||||
cursor.SetXPosition(30);
|
||||
termSm.ProcessString(addTabStop);
|
||||
expectedStops.push_back(30);
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Add tab to middle of existing list.");
|
||||
cursor.SetXPosition(24);
|
||||
termSm.ProcessString(addTabStop);
|
||||
expectedStops.push_back(24);
|
||||
expectedStops.sort();
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
|
||||
Log::Comment(L"Add tab that duplicates an item in the existing list.");
|
||||
cursor.SetXPosition(24);
|
||||
termSm.ProcessString(addTabStop);
|
||||
VERIFY_ARE_EQUAL(expectedStops, _GetTabStops());
|
||||
}
|
||||
|
||||
void TerminalBufferTests::TestClearTabStop()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
const auto clearTabStops = L"\033[3g";
|
||||
const auto clearTabStop = L"\033[0g";
|
||||
const auto addTabStop = L"\033H";
|
||||
|
||||
Log::Comment(L"Start with all tabs cleared.");
|
||||
{
|
||||
termSm.ProcessString(clearTabStops);
|
||||
|
||||
VERIFY_IS_TRUE(_GetTabStops().empty());
|
||||
}
|
||||
|
||||
Log::Comment(L"Try to clear nonexistent list.");
|
||||
{
|
||||
cursor.SetXPosition(0);
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
VERIFY_IS_TRUE(_GetTabStops().empty(), L"List should remain empty");
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate 1 list item and clear it.");
|
||||
{
|
||||
cursor.SetXPosition(0);
|
||||
termSm.ProcessString(addTabStop);
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
VERIFY_IS_TRUE(_GetTabStops().empty());
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate 1 list item and clear nonexistent.");
|
||||
{
|
||||
cursor.SetXPosition(1);
|
||||
termSm.ProcessString(addTabStop);
|
||||
|
||||
Log::Comment(L"Free greater");
|
||||
cursor.SetXPosition(2);
|
||||
termSm.ProcessString(clearTabStop);
|
||||
VERIFY_IS_FALSE(_GetTabStops().empty());
|
||||
|
||||
Log::Comment(L"Free less than");
|
||||
cursor.SetXPosition(0);
|
||||
termSm.ProcessString(clearTabStop);
|
||||
VERIFY_IS_FALSE(_GetTabStops().empty());
|
||||
|
||||
// clear all tab stops
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate many (5) list items and clear head.");
|
||||
{
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, false);
|
||||
cursor.SetXPosition(inputData.front());
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
inputData.pop_front();
|
||||
VERIFY_ARE_EQUAL(inputData, _GetTabStops());
|
||||
|
||||
// clear all tab stops
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate many (5) list items and clear middle.");
|
||||
{
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, false);
|
||||
cursor.SetXPosition(*std::next(inputData.begin()));
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
inputData.erase(std::next(inputData.begin()));
|
||||
VERIFY_ARE_EQUAL(inputData, _GetTabStops());
|
||||
|
||||
// clear all tab stops
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate many (5) list items and clear tail.");
|
||||
{
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, false);
|
||||
cursor.SetXPosition(inputData.back());
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
inputData.pop_back();
|
||||
VERIFY_ARE_EQUAL(inputData, _GetTabStops());
|
||||
|
||||
// clear all tab stops
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
|
||||
Log::Comment(L"Allocate many (5) list items and clear nonexistent item.");
|
||||
{
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, false);
|
||||
cursor.SetXPosition(0);
|
||||
termSm.ProcessString(clearTabStop);
|
||||
|
||||
VERIFY_ARE_EQUAL(inputData, _GetTabStops());
|
||||
|
||||
// clear all tab stops
|
||||
termSm.ProcessString(clearTabStops);
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalBufferTests::TestGetForwardTab()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
const auto initialView = term->GetViewport();
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
const auto nextForwardTab = L"\033[I";
|
||||
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, true);
|
||||
|
||||
const COORD coordScreenBufferSize = initialView.Dimensions();
|
||||
|
||||
Log::Comment(L"Find next tab from before front.");
|
||||
{
|
||||
cursor.SetXPosition(0);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = inputData.front();
|
||||
|
||||
termSm.ProcessString(nextForwardTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor advanced to first tab stop from sample list.");
|
||||
}
|
||||
|
||||
Log::Comment(L"Find next tab from in the middle.");
|
||||
{
|
||||
cursor.SetXPosition(6);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = *std::next(inputData.begin(), 3);
|
||||
|
||||
termSm.ProcessString(nextForwardTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor advanced to middle tab stop from sample list.");
|
||||
}
|
||||
|
||||
Log::Comment(L"Find next tab from end.");
|
||||
{
|
||||
cursor.SetXPosition(30);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = coordScreenBufferSize.X - 1;
|
||||
|
||||
termSm.ProcessString(nextForwardTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor advanced to end of screen buffer.");
|
||||
}
|
||||
|
||||
Log::Comment(L"Find next tab from rightmost column.");
|
||||
{
|
||||
cursor.SetXPosition(coordScreenBufferSize.X - 1);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
|
||||
termSm.ProcessString(nextForwardTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor remains in rightmost column.");
|
||||
}
|
||||
}
|
||||
|
||||
void TerminalBufferTests::TestGetReverseTab()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
auto& cursor = termTb.GetCursor();
|
||||
|
||||
const auto nextReverseTab = L"\033[Z";
|
||||
|
||||
std::list<short> inputData = { 3, 5, 6, 10, 15, 17 };
|
||||
_SetTabStops(inputData, true);
|
||||
|
||||
Log::Comment(L"Find previous tab from before front.");
|
||||
{
|
||||
cursor.SetXPosition(1);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = 0;
|
||||
|
||||
termSm.ProcessString(nextReverseTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor adjusted to beginning of the buffer when it started before sample list.");
|
||||
}
|
||||
|
||||
Log::Comment(L"Find previous tab from in the middle.");
|
||||
{
|
||||
cursor.SetXPosition(6);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = *std::next(inputData.begin());
|
||||
|
||||
termSm.ProcessString(nextReverseTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor adjusted back one tab spot from middle of sample list.");
|
||||
}
|
||||
|
||||
Log::Comment(L"Find next tab from end.");
|
||||
{
|
||||
cursor.SetXPosition(30);
|
||||
|
||||
COORD coordCursorExpected = cursor.GetPosition();
|
||||
coordCursorExpected.X = inputData.back();
|
||||
|
||||
termSm.ProcessString(nextReverseTab);
|
||||
COORD const coordCursorResult = cursor.GetPosition();
|
||||
VERIFY_ARE_EQUAL(coordCursorExpected,
|
||||
coordCursorResult,
|
||||
L"Cursor adjusted to last item in the sample list from position beyond end.");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue