Take wrapping into account when expanding wordwise selections (#17170)

Closes #17165
This commit is contained in:
Dustin L. Howett 2024-05-02 11:14:20 -05:00 committed by GitHub
parent a9446a12df
commit 6cda6797f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 86 additions and 35 deletions

View File

@ -80,6 +80,7 @@ mnt
mru mru
nje nje
noreply noreply
notwrapped
ogonek ogonek
ok'd ok'd
overlined overlined

View File

@ -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 // expand left until we hit the left boundary or a different delimiter class
while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter) while (result != bufferSize.Origin() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter)
{ {
//prevent selection wrapping on whitespace selection if (result.x == bufferSize.Left())
if (isControlChar && 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); bufferSize.DecrementInBounds(result);
} }
@ -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 // expand right until we hit the right boundary as a ControlChar or a different delimiter class
while (result != bufferSize.BottomRightInclusive() && _GetDelimiterClassAt(result, wordDelimiters) == initialDelimiter) 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); bufferSize.IncrementInBoundsCircular(result);
} }

View File

@ -2336,16 +2336,32 @@ void TextBufferTests::GetWordBoundaries()
} }
_buffer->Reset(); _buffer->Reset();
_buffer->ResizeTraditional({ 10, 5 }); _buffer->ResizeTraditional({ 10, 6 });
const std::vector<std::wstring> secondText = { L"this wordiswrapped", const std::vector<std::wstring> secondText = { L"this wordiswrapped",
L"notwrapped"
L"spaces wrapped reachEOB" }; L"spaces wrapped reachEOB" };
//Buffer looks like:
// this wordi
// swrapped
// spaces
// wrappe
// d reachEOB
WriteLinesToBuffer(secondText, *_buffer); 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 = { testData = {
{ { 0, 0 }, { { 0, 0 }, { 0, 0 } } }, { { 0, 0 }, { { 0, 0 }, { 0, 0 } } },
{ { 1, 0 }, { { 0, 0 }, { 0, 0 } } }, { { 1, 0 }, { { 0, 0 }, { 0, 0 } } },
@ -2358,15 +2374,18 @@ void TextBufferTests::GetWordBoundaries()
{ { 9, 1 }, { { 8, 1 }, { 5, 0 } } }, { { 9, 1 }, { { 8, 1 }, { 5, 0 } } },
{ { 0, 2 }, { { 0, 2 }, { 0, 2 } } }, { { 0, 2 }, { { 0, 2 }, { 0, 2 } } },
{ { 7, 2 }, { { 6, 2 }, { 0, 2 } } }, { { 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 } } },
{ { 1, 3 }, { { 0, 3 }, { 0, 2 } } }, { { 0, 5 }, { { 4, 4 }, { 4, 4 } } },
{ { 4, 3 }, { { 4, 3 }, { 4, 3 } } }, { { 1, 5 }, { { 1, 5 }, { 4, 4 } } },
{ { 8, 3 }, { { 4, 3 }, { 4, 3 } } }, { { 9, 5 }, { { 2, 5 }, { 2, 5 } } },
{ { 0, 4 }, { { 4, 3 }, { 4, 3 } } },
{ { 1, 4 }, { { 1, 4 }, { 4, 3 } } },
{ { 9, 4 }, { { 2, 4 }, { 2, 4 } } },
}; };
for (const auto& test : testData) for (const auto& test : testData)
{ {
@ -2377,12 +2396,15 @@ void TextBufferTests::GetWordBoundaries()
} }
//GetWordEnd for Wrapping Text //GetWordEnd for Wrapping Text
//Buffer looks like: // Buffer:
// this wordi // 0123456789
// swrapped // 0|this wordi| < wrapped
// spaces // 1|swrapped | < not wrapped
// wrappe // 2|notwrapped| < not wrapped
// d reachEOB // 3|spaces | < wrapped
// 4| wrappe| < wrapped
// 5|d reachEOB| < wrapped
// clang-format off
testData = { testData = {
// tests for first line of text // tests for first line of text
{ { 0, 0 }, { { 3, 0 }, { 5, 0 } } }, { { 0, 0 }, { { 3, 0 }, { 5, 0 } } },
@ -2395,17 +2417,20 @@ void TextBufferTests::GetWordBoundaries()
{ { 7, 1 }, { { 7, 1 }, { 0, 2 } } }, { { 7, 1 }, { { 7, 1 }, { 0, 2 } } },
{ { 9, 1 }, { { 9, 1 }, { 0, 2 } } }, { { 9, 1 }, { { 9, 1 }, { 0, 2 } } },
{ { 0, 2 }, { { 5, 2 }, { 4, 3 } } }, { { 0, 2 }, { { 9, 2 }, { 4, 4 } } },
{ { 7, 2 }, { { 9, 2 }, { 4, 3 } } }, { { 9, 2 }, { { 9, 2 }, { 4, 4 } } },
{ { 1, 3 }, { { 3, 3 }, { 4, 3 } } }, { { 0, 3 }, { { 5, 3 }, { 4, 4 } } },
{ { 4, 3 }, { { 0, 4 }, { 2, 4 } } }, { { 7, 3 }, { { 9, 3 }, { 4, 4 } } },
{ { 8, 3 }, { { 0, 4 }, { 2, 4 } } },
{ { 0, 4 }, { { 0, 4 }, { 2, 4 } } }, { { 1, 4 }, { { 3, 4 }, { 4, 4 } } },
{ { 1, 4 }, { { 1, 4 }, { 2, 4 } } }, { { 4, 4 }, { { 0, 5 }, { 2, 5 } } },
{ { 4, 4 }, { { 9, 4 }, { 0, 5 } } }, { { 8, 4 }, { { 0, 5 }, { 2, 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 // clang-format on