Skip to content

Commit

Permalink
Take wrapping into account when expanding wordwise selections (#17170)
Browse files Browse the repository at this point in the history
Closes #17165
  • Loading branch information
DHowett authored May 2, 2024
1 parent a9446a1 commit 6cda679
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 36 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/allow/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ mnt
mru
nje
noreply
notwrapped
ogonek
ok'd
overlined
Expand Down
35 changes: 30 additions & 5 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1440,10 +1440,23 @@ til::point TextBuffer::_GetWordStartForSelection(const til::point target, const
// expand left until we hit the left boundary or a different delimiter class
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
{
//prevent selection wrapping on whitespace selection
if (isControlChar && result.x == bufferSize.Left())
if (result.x == bufferSize.Left())
{
break;
// Prevent wrapping to the previous line if the selection begins on whitespace
if (isControlChar)
{
break;
}

if (result.y > 0)
{
// Prevent wrapping to the previous line if it was hard-wrapped (e.g. not forced by us to wrap)
const auto& priorRow = GetRowByOffset(result.y - 1);
if (!priorRow.WasWrapForced())
{
break;
}
}
}
bufferSize.DecrementInBounds(result);
}
Expand Down Expand Up @@ -1563,10 +1576,22 @@ til::point TextBuffer::_GetWordEndForSelection(const til::point target, const st
// expand right until we hit the right boundary as a ControlChar or a different delimiter class
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
{
if (isControlChar && result.x == bufferSize.RightInclusive())
if (result.x == bufferSize.RightInclusive())
{
break;
// Prevent wrapping to the next line if the selection begins on whitespace
if (isControlChar)
{
break;
}

// Prevent wrapping to the next line if this one was hard-wrapped (e.g. not forced by us to wrap)
const auto& row = GetRowByOffset(result.y);
if (!row.WasWrapForced())
{
break;
}
}

bufferSize.IncrementInBoundsCircular(result);
}

Expand Down
87 changes: 56 additions & 31 deletions src/host/ut_host/TextBufferTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2336,16 +2336,32 @@ void TextBufferTests::GetWordBoundaries()
}

_buffer->Reset();
_buffer->ResizeTraditional({ 10, 5 });
_buffer->ResizeTraditional({ 10, 6 });
const std::vector<std::wstring> secondText = { L"this wordiswrapped",
L"notwrapped"
L"spaces wrapped reachEOB" };
//Buffer looks like:
// this wordi
// swrapped
// spaces
// wrappe
// d reachEOB

WriteLinesToBuffer(secondText, *_buffer);

//Buffer looks like:
// 0123456789
// 0|this wordi| < wrapped
// 1|swrapped | < not wrapped
// 2|notwrapped| < not wrapped
// 3|spaces | < wrapped
// 4| wrappe| < wrapped
// 5|d reachEOB| < wrapped

VERIFY_IS_TRUE(_buffer->GetRowByOffset(0).WasWrapForced());
VERIFY_IS_FALSE(_buffer->GetRowByOffset(1).WasWrapForced());
// GH#780 See the comment in WriteLinesToBuffer
// VERIFY_IS_FALSE(_buffer->GetRowByOffset(2).WasWrapForced());
_buffer->GetMutableRowByOffset(2).SetWrapForced(false); // Ugh
VERIFY_IS_TRUE(_buffer->GetRowByOffset(3).WasWrapForced());
VERIFY_IS_TRUE(_buffer->GetRowByOffset(4).WasWrapForced());
VERIFY_IS_TRUE(_buffer->GetRowByOffset(5).WasWrapForced());

// clang-format off
testData = {
{ { 0, 0 }, { { 0, 0 }, { 0, 0 } } },
{ { 1, 0 }, { { 0, 0 }, { 0, 0 } } },
Expand All @@ -2358,15 +2374,18 @@ void TextBufferTests::GetWordBoundaries()
{ { 9, 1 }, { { 8, 1 }, { 5, 0 } } },

{ { 0, 2 }, { { 0, 2 }, { 0, 2 } } },
{ { 7, 2 }, { { 6, 2 }, { 0, 2 } } },

{ { 1, 3 }, { { 0, 3 }, { 0, 2 } } },
{ { 4, 3 }, { { 4, 3 }, { 4, 3 } } },
{ { 8, 3 }, { { 4, 3 }, { 4, 3 } } },

{ { 0, 4 }, { { 4, 3 }, { 4, 3 } } },
{ { 1, 4 }, { { 1, 4 }, { 4, 3 } } },
{ { 9, 4 }, { { 2, 4 }, { 2, 4 } } },
{ { 9, 2 }, { { 0, 2 }, { 0, 2 } } },
// v accessibility does not consider wrapping
{ { 0, 3 }, { { 0, 3 }, { 0, 2 } } },
{ { 7, 3 }, { { 6, 3 }, { 0, 2 } } },
// v accessibility does not consider wrapping
{ { 1, 4 }, { { 0, 4 }, { 0, 2 } } },
{ { 4, 4 }, { { 4, 4 }, { 4, 4 } } },
{ { 8, 4 }, { { 4, 4 }, { 4, 4 } } },

{ { 0, 5 }, { { 4, 4 }, { 4, 4 } } },
{ { 1, 5 }, { { 1, 5 }, { 4, 4 } } },
{ { 9, 5 }, { { 2, 5 }, { 2, 5 } } },
};
for (const auto& test : testData)
{
Expand All @@ -2377,12 +2396,15 @@ void TextBufferTests::GetWordBoundaries()
}

//GetWordEnd for Wrapping Text
//Buffer looks like:
// this wordi
// swrapped
// spaces
// wrappe
// d reachEOB
// Buffer:
// 0123456789
// 0|this wordi| < wrapped
// 1|swrapped | < not wrapped
// 2|notwrapped| < not wrapped
// 3|spaces | < wrapped
// 4| wrappe| < wrapped
// 5|d reachEOB| < wrapped
// clang-format off
testData = {
// tests for first line of text
{ { 0, 0 }, { { 3, 0 }, { 5, 0 } } },
Expand All @@ -2395,17 +2417,20 @@ void TextBufferTests::GetWordBoundaries()
{ { 7, 1 }, { { 7, 1 }, { 0, 2 } } },
{ { 9, 1 }, { { 9, 1 }, { 0, 2 } } },

{ { 0, 2 }, { { 5, 2 }, { 4, 3 } } },
{ { 7, 2 }, { { 9, 2 }, { 4, 3 } } },
{ { 0, 2 }, { { 9, 2 }, { 4, 4 } } },
{ { 9, 2 }, { { 9, 2 }, { 4, 4 } } },

{ { 0, 3 }, { { 5, 3 }, { 4, 4 } } },
{ { 7, 3 }, { { 9, 3 }, { 4, 4 } } },

{ { 1, 3 }, { { 3, 3 }, { 4, 3 } } },
{ { 4, 3 }, { { 0, 4 }, { 2, 4 } } },
{ { 8, 3 }, { { 0, 4 }, { 2, 4 } } },
{ { 1, 4 }, { { 3, 4 }, { 4, 4 } } },
{ { 4, 4 }, { { 0, 5 }, { 2, 5 } } },
{ { 8, 4 }, { { 0, 5 }, { 2, 5 } } },

{ { 0, 4 }, { { 0, 4 }, { 2, 4 } } },
{ { 1, 4 }, { { 1, 4 }, { 2, 4 } } },
{ { 4, 4 }, { { 9, 4 }, { 0, 5 } } },
{ { 9, 4 }, { { 9, 4 }, { 0, 5 } } },
{ { 0, 5 }, { { 0, 5 }, { 2, 5 } } },
{ { 1, 5 }, { { 1, 5 }, { 2, 5 } } },
{ { 4, 5 }, { { 9, 5 }, { 0, 6 } } },
{ { 9, 5 }, { { 9, 5 }, { 0, 6 } } },
};
// clang-format on

Expand Down

0 comments on commit 6cda679

Please sign in to comment.