Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the location that selecting a mark uses #17138

Merged
merged 2 commits into from May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/cascadia/TerminalControl/ControlCore.cpp
Expand Up @@ -2620,12 +2620,27 @@ namespace winrt::Microsoft::Terminal::Control::implementation

CompletionsChanged.raise(*this, *args);
}

// Select the region of text between [s.start, s.end), in buffer space
void ControlCore::_selectSpan(til::point_span s)
{
// s.end is an _exclusive_ point. We need an inclusive one. But
// decrement in bounds wants an inclusive one. If you pass an exclusive
// one, then it might assert at you for being out of bounds. So we also
// take care of the case that the end point is outside the viewport
// manually.
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
const auto bufferSize{ _terminal->GetTextBuffer().GetSize() };
bufferSize.DecrementInBounds(s.end);
til::point inclusiveEnd = s.end;
if (s.end.x == bufferSize.Width())
{
inclusiveEnd = til::point{ std::max(0, s.end.x - 1), s.end.y };
}
else
{
bufferSize.DecrementInBounds(inclusiveEnd);
}

_terminal->SelectNewRegion(s.start, s.end);
_terminal->SelectNewRegion(s.start, inclusiveEnd);
_renderer->TriggerSelection();
}

Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/TerminalCore/terminalrenderdata.cpp
Expand Up @@ -199,7 +199,7 @@ til::CoordType Terminal::_ScrollToPoints(const til::point coordStart, const til:
_NotifyScrollEvent();
}

return _scrollOffset;
return _VisibleStartIndex();
Copy link
Contributor

@tusharsnx tusharsnx Apr 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also update the comment? It currently reads:

// Return Value:
// - The updated scroll offset

BTW, as someone new to this repo I have a doubt: what's the mutable viewport? And how does it differ from the viewport that _scrollOffset represents?

Not the best place to ask questions, so I'm sorry 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries! I probably didn't do the best job with that particular abstraction, and it bites even me to this day.

image

(I should commit that somehere)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PUT THIS IN THE REPO SOMEWHERE

}

void Terminal::SelectNewRegion(const til::point coordStart, const til::point coordEnd)
Expand Down
136 changes: 136 additions & 0 deletions src/cascadia/UnitTests_Control/ControlCoreTests.cpp
Expand Up @@ -40,6 +40,8 @@ namespace ControlUnitTests

TEST_METHOD(TestSelectCommandSimple);
TEST_METHOD(TestSelectOutputSimple);
TEST_METHOD(TestSelectOutputScrolling);
TEST_METHOD(TestSelectOutputExactWrap);

TEST_METHOD(TestSimpleClickSelection);

Expand Down Expand Up @@ -508,6 +510,140 @@ namespace ControlUnitTests
}
}

void ControlCoreTests::TestSelectOutputScrolling()
{
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
_standardInit(core);

Log::Comment(L"Print some text");

_writePrompt(conn, L"C:\\Windows"); // row 0
conn->WriteInput(L"Foo-bar"); // row 0
conn->WriteInput(L"\x1b]133;C\x7");

conn->WriteInput(L"\r\n");
conn->WriteInput(L"This is some text \r\n"); // row 1
conn->WriteInput(L"with varying amounts \r\n"); // row 2
conn->WriteInput(L"of whitespace \r\n"); // row 3

_writePrompt(conn, L"C:\\Windows"); // row 4
conn->WriteInput(L"gci");
conn->WriteInput(L"\x1b]133;C\x7");
conn->WriteInput(L"\r\n");

// enough to scroll
for (auto i = 0; i < 30; i++) // row 5-34
{
conn->WriteInput(L"-a--- 2/8/2024 9:47 README\r\n");
}

_writePrompt(conn, L"C:\\Windows");

Log::Comment(L"Check the buffer contents");
const auto& buffer = core->_terminal->GetTextBuffer();
const auto& cursor = buffer.GetCursor();

{
const til::point expectedCursor{ 17, 35 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
}

VERIFY_IS_FALSE(core->HasSelection());

// The second mark is the first one we'll see
core->SelectOutput(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 20, 4 }; // The character after the prompt
const til::point expectedEnd{ 26, 34 }; // x = the end of the text
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
core->SelectOutput(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 24, 0 }; // The character after the prompt
const til::point expectedEnd{ 21, 3 }; // x = the end of the text
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
}

void ControlCoreTests::TestSelectOutputExactWrap()
{
// Just like the TestSelectOutputScrolling test, but these lines will
// exactly wrap to the right edge of the buffer, to catch a edge case
// present in `ControlCore::_selectSpan`
auto [settings, conn] = _createSettingsAndConnection();
Log::Comment(L"Create ControlCore object");
auto core = createCore(*settings, *conn);
VERIFY_IS_NOT_NULL(core);
_standardInit(core);

Log::Comment(L"Print some text");

_writePrompt(conn, L"C:\\Windows"); // row 0
conn->WriteInput(L"Foo-bar"); // row 0
conn->WriteInput(L"\x1b]133;C\x7");

conn->WriteInput(L"\r\n");
conn->WriteInput(L"This is some text \r\n"); // row 1
conn->WriteInput(L"with varying amounts \r\n"); // row 2
conn->WriteInput(L"of whitespace \r\n"); // row 3

_writePrompt(conn, L"C:\\Windows"); // row 4
conn->WriteInput(L"gci");
conn->WriteInput(L"\x1b]133;C\x7");
conn->WriteInput(L"\r\n");

// enough to scroll
for (auto i = 0; i < 30; i++) // row 5-35
{
conn->WriteInput(L"-a--- 2/8/2024 9:47 README.md\r\n");
}

_writePrompt(conn, L"C:\\Windows");

Log::Comment(L"Check the buffer contents");
const auto& buffer = core->_terminal->GetTextBuffer();
const auto& cursor = buffer.GetCursor();

{
const til::point expectedCursor{ 17, 35 };
VERIFY_ARE_EQUAL(expectedCursor, cursor.GetPosition());
}

VERIFY_IS_FALSE(core->HasSelection());
// The second mark is the first one we'll see
core->SelectOutput(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 20, 4 }; // The character after the prompt
const til::point expectedEnd{ 29, 34 }; // x = the end of the text
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
core->SelectOutput(true);
VERIFY_IS_TRUE(core->HasSelection());
{
const auto& start = core->_terminal->GetSelectionAnchor();
const auto& end = core->_terminal->GetSelectionEnd();
const til::point expectedStart{ 24, 0 }; // The character after the prompt
const til::point expectedEnd{ 21, 3 }; // x = the end of the text
VERIFY_ARE_EQUAL(expectedStart, start);
VERIFY_ARE_EQUAL(expectedEnd, end);
}
}

void ControlCoreTests::TestSimpleClickSelection()
{
// Create a simple selection with the mouse, then click somewhere else,
Expand Down